?? rtl8139.c
字號:
diff=rxPhyAddr-((rxPhyAddr >> 8)<< 8); diff=256-diff; rxPhyAddr +=diff; tp->rxDescArray = (struct CPlusRxDesc *)(tp->rxDescArrays + diff); rtl8139cp_init_ring(dev); tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH<<TX_FIFO_THRESH_SHIFT) & 0x003f0000; tp->rx_config = (RX_FIFO_THRESH << RX_FIFO_THRESH_SHIFT) | (RX_BUF_LEN_IDX << RX_BUF_LEN_IDX_SHIFT) | (RX_DMA_BURST << RX_DMA_BURST_SHIFT); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; outl(cpu_to_le32(*(u32*)(dev->dev_addr + 0)), ioaddr + MAC0 + 0); outl(cpu_to_le32(*(u32*)(dev->dev_addr + 4)), ioaddr + MAC0 + 4); /* Must enable Tx/Rx before setting transfer thresholds! */ outb( CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); outw( CpCmdRxEnb | CpCmdTxEnb, ioaddr + CPlusCmd); outb( CPEarlyTxThld, ioaddr + CPlusEarlyTxThld); outl(tp->rx_config, ioaddr + RxConfig); /* The manual contradicts itself describing the proper IFG setting. */ outl((TX_DMA_BURST << TX_DMA_BURST_SHIFT) | 0x03000000, ioaddr + TxConfig); if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (mii_reg5 == 0xffff) ; /* Not there */ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) tp->full_duplex = 1; if (debug > 1) printk(KERN_INFO"%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", tp->full_duplex ? "full" : "half", mii_reg5); } outb(Cfg9346_Unlock, ioaddr + Cfg9346); outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outl(rxPhyAddr, ioaddr + CPlusRxStartAddr); outl(txPhyAddr, ioaddr + CPlusTxStartAddr); outb(Cfg9346_Lock, ioaddr + Cfg9346); /* Start the chip's Tx and Rx process. */ outl(0, ioaddr + RxMissed); set_rx_mode(dev); outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); if (debug > 1) printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData), tp->full_duplex ? "full" : "half"); /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ init_timer(&tp->timer); tp->timer.expires = jiffies + 3*HZ; tp->timer.data = (unsigned long)dev; tp->timer.function = &rtl8129_timer; add_timer(&tp->timer); return 0;}static int rtl8129_open(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int i; /* Soft reset the chip. */ outb(CmdReset, ioaddr + ChipCmd); MOD_INC_USE_COUNT; if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) { MOD_DEC_USE_COUNT; return -EAGAIN; } /* The Rx ring allocation size is 2^N + delta, which is worst-case for the kernel binary-buddy allocation. We allocate the Tx bounce buffers at the same time to use some of the otherwise wasted space. The delta of +16 is required for dribble-over because the receiver does not wrap when the packet terminates just beyond the end of the ring. */ tp->rx_ring = kmalloc(RX_BUF_LEN + 16 + (TX_BUF_SIZE * NUM_TX_DESC), GFP_KERNEL); if (tp->rx_ring == NULL) { if (debug > 0) printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", dev->name, RX_BUF_LEN); MOD_DEC_USE_COUNT; return -ENOMEM; } tp->tx_bufs = tp->rx_ring + RX_BUF_LEN + 16; rtl8129_init_ring(dev); tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH<<TX_FIFO_THRESH_SHIFT) & 0x003f0000; tp->rx_config = (RX_FIFO_THRESH << RX_FIFO_THRESH_SHIFT) | (RX_BUF_LEN_IDX << RX_BUF_LEN_IDX_SHIFT) | (RX_DMA_BURST<<RX_DMA_BURST_SHIFT); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; outl(cpu_to_le32(*(u32*)(dev->dev_addr + 0)), ioaddr + MAC0 + 0); outl(cpu_to_le32(*(u32*)(dev->dev_addr + 4)), ioaddr + MAC0 + 4); /* Must enable Tx/Rx before setting transfer thresholds! */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); outl(tp->rx_config, ioaddr + RxConfig); /* The manual contradicts itself describing the proper IFG setting. */ outl((TX_DMA_BURST<<TX_DMA_BURST_SHIFT)|0x00000000, ioaddr + TxConfig); if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (mii_reg5 == 0xffff) ; /* Not there */ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) tp->full_duplex = 1; if (debug > 1) printk(KERN_INFO"%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", tp->full_duplex ? "full" : "half", mii_reg5); } outb(Cfg9346_Unlock, ioaddr + Cfg9346); outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(Cfg9346_Lock, ioaddr + Cfg9346); outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf); /* Start the chip's Tx and Rx process. */ outl(0, ioaddr + RxMissed); set_rx_mode(dev); outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); if (debug > 1) printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData), tp->full_duplex ? "full" : "half"); /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ init_timer(&tp->timer); tp->timer.expires = jiffies + 3*HZ; tp->timer.data = (unsigned long)dev; tp->timer.function = &rtl8129_timer; add_timer(&tp->timer); return 0;}/* Start the hardware at open or resume. */static void rtl_hw_start(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int i; /* Soft reset the chip. */ outb(CmdReset, ioaddr + ChipCmd); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; /* Restore our idea of the MAC address. */ outl(cpu_to_le32(*(u32*)(dev->dev_addr + 0)), ioaddr + MAC0 + 0); outl(cpu_to_le32(*(u32*)(dev->dev_addr + 4)), ioaddr + MAC0 + 4); /* Hmmm, do these belong here? */ outb(Cfg9346_Lock, ioaddr + Cfg9346); tp->cur_rx = 0; /* Must enable Tx/Rx before setting transfer thresholds! */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);//add for 8139C+ if(CPFlag == 1){ outw( CpCmdRxEnb | CpCmdTxEnb, ioaddr + CPlusCmd); outb( CPEarlyTxThld, ioaddr + CPlusEarlyTxThld); } outl(tp->rx_config, ioaddr + RxConfig); /* Check this value: the documentation contradicts ifself. Is the IFG correct with bit 28:27 zero, or with |0x03000000 ? */ outl((TX_DMA_BURST<<TX_DMA_BURST_SHIFT), ioaddr + TxConfig); /* check_duplex() here. */ outb(Cfg9346_Unlock, ioaddr + Cfg9346); outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(Cfg9346_Lock, ioaddr + Cfg9346);//add for 8139C+ if( CPFlag != 1 ) outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf); /* Start the chip's Tx and Rx process. */ outl(0, ioaddr + RxMissed); set_rx_mode(dev); outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);}static void rtl8129_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; int mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (! tp->duplex_lock && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); outb(Cfg9346_Unlock, ioaddr + Cfg9346); outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(Cfg9346_Lock, ioaddr + Cfg9346); } } /* Check for bogusness. */ if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { int status = inw(ioaddr + IntrStatus); /* Double check */ if (status & (TxOK | RxOK) && ! dev->interrupt) { printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n", dev->name, status);//add for 8139C+ if( CPFlag ==1 ) rtl8139CP_interrupt(dev->irq, dev, 0); else rtl8129_interrupt(dev->irq, dev, 0); } } if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT) rtl8129_tx_timeout(dev);#if defined(RTL_TUNE_TWISTER) /* This is a complicated state machine to configure the "twister" for impedance/echos based on the cable length. All of this is magic and undocumented. */ if (tp->twistie) switch(tp->twistie) { case 1: { if (inw(ioaddr + CSCR) & CSCR_LinkOKBit) { /* We have link beat, let us tune the twister. */ outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); tp->twistie = 2; /* Change to state 2. */ next_tick = HZ/10; } else { /* Just put in some reasonable defaults for when beat returns. */ outw(CSCR_LinkDownCmd, ioaddr + CSCR); outl(0x20,ioaddr + FIFOTMS); /* Turn on cable test mode. */ outl(PARA78_default ,ioaddr + PARA78); outl(PARA7c_default ,ioaddr + PARA7c); tp->twistie = 0; /* Bail from future actions. */ } } break; case 2: { /* Read how long it took to hear the echo. */ int linkcase = inw(ioaddr + CSCR) & CSCR_LinkStatusBits; if (linkcase == 0x7000) tp->twist_row = 3; else if (linkcase == 0x3000) tp->twist_row = 2; else if (linkcase == 0x1000) tp->twist_row = 1; else tp->twist_row = 0; tp->twist_col = 0; tp->twistie = 3; /* Change to state 2. */ next_tick = HZ/10; } break; case 3: { /* Put out four tuning parameters, one per 100msec. */ if (tp->twist_col == 0) outw(0, ioaddr + FIFOTMS); outl(param[(int)tp->twist_row][(int)tp->twist_col], ioaddr + PARA7c); next_tick = HZ/10; if (++tp->twist_col >= 4) { /* For short cables we are done. For long cables (row == 3) check for mistune. */ tp->twistie = (tp->twist_row == 3) ? 4 : 0; } } break; case 4: { /* Special case for long cables: check for mistune. */ if ((inw(ioaddr + CSCR) & CSCR_LinkStatusBits) == 0x7000) { tp->twistie = 0; break; } else { outl(0xfb38de03, ioaddr + PARA7c); tp->twistie = 5; next_tick = HZ/10; } } break; case 5: { /* Retune for shorter cable (column 2). */ outl(0x20,ioaddr + FIFOTMS); outl(PARA78_default, ioaddr + PARA78); outl(PARA7c_default, ioaddr + PARA7c); outl(0x00,ioaddr + FIFOTMS); tp->twist_row = 2; tp->twist_col = 0; tp->twistie = 3; next_tick = HZ/10; } break; }#endif if (debug > 2) { if (tp->drv_flags & HAS_MII_XCVR) printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n", dev->name, inb(ioaddr + GPPinData)); else printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n", dev->name, inw(ioaddr + NWayLPAR)); printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x" " RxStatus %4.4x.\n", dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus), inl(ioaddr + RxEarlyStatus)); printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n", dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); } tp->timer.expires = jiffies + next_tick; add_timer(&tp->timer);}static void rtl8129_tx_timeout(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int mii_reg, i; if (debug > 0) printk(KERN_ERR "%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus), inb(ioaddr + GPPinData)); /* Disable interrupts by clearing the interrupt mask. */ outw(0x0000, ioaddr + IntrMask); /* Emit info to figure out what went wrong. */ printk(KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d%s.\n", dev->name, tp->cur_tx, tp->dirty_tx, tp->tx_full ? ", full" : ""); for (i = 0; i < NUM_TX_DESC; i++) printk(KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n", dev->name, i, inl(ioaddr + TxStatus0 + i*4), i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); printk(KERN_DEBUG "%s: MII #%d registers are:", dev->name, tp->phys[0]); for (mii_reg = 0; mii_reg < 8; mii_reg++) printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg)); printk(".\n"); /* Stop a shared interrupt from scavenging while we are. */ tp->dirty_tx = tp->cur_tx = 0; /* Dump the unsent Tx packets. *///add for 8139C+. if( CPFlag == 1 ){ for (i = 0; i < NUM_CP_TX_DESC; i++) { if (tp->tx_skbuff[i]) { dev_free_skb(tp->tx_skbuff[i]); tp->tx_skbuff[i] = 0; tp->stats.tx_dropped++; } } } else{ for (i = 0; i < NUM_TX_DESC; i++) { if (tp->tx_skbuffa[i]) { dev_free_skb(tp->tx_skbuffa[i]); tp->tx_skbuffa[i] = 0; tp->stats.tx_dropped++; } } } rtl_hw_start(dev); tp->tx_full = dev->tbusy = 0; return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void rtl8139cp_init_ring(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; int i;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -