📄 8139too.c
字号:
#define mdio_delay(mdio_addr) readb(mdio_addr)static char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, 0, 0, NWayAdvert, NWayLPAR, NWayExpansion, 0};/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync (void *mdio_addr){ int i; DPRINTK ("ENTER\n"); for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } DPRINTK ("EXIT\n");}static int mdio_read (struct net_device *dev, int phy_id, int location){ struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; int i; DPRINTK ("ENTER\n"); if (phy_id > 31) { /* Really a 8139. Use internal registers. */ DPRINTK ("EXIT after directly using 8139 internal regs\n"); return location < 8 && mii_2_8139_map[location] ? readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; } mdio_sync (mdio_addr); /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; writeb (MDIO_DIR | dataval, mdio_addr); mdio_delay (mdio_addr); writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb (0, mdio_addr); mdio_delay (mdio_addr); retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); writeb (MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); return (retval >> 1) & 0xffff;}static void mdio_write (struct net_device *dev, int phy_id, int location, int value){ struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; DPRINTK ("ENTER\n"); if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void *ioaddr = tp->mmio_addr; if (location == 0) { RTL_W8_F (Cfg9346, Cfg9346_Unlock); ////////////////////////////////////////////////////////////// switch(tp->AutoNegoAbility){ case 1: RTL_W16 (NWayAdvert, AutoNegoAbility10half); break; case 2: RTL_W16 (NWayAdvert, AutoNegoAbility10full); break; case 4: RTL_W16 (NWayAdvert, AutoNegoAbility100half); break; case 8: RTL_W16 (NWayAdvert, AutoNegoAbility100full); break; default: break; } RTL_W16_F (BasicModeCtrl, AutoNegotiationEnable|AutoNegotiationRestart); //////////////////////////////////////////////////////////////// RTL_W16_F (BasicModeCtrl, value); RTL_W8_F (Cfg9346, Cfg9346_Lock); } else if (location < 8 && mii_2_8139_map[location]) RTL_W16_F (mii_2_8139_map[location], value); return; } mdio_sync (mdio_addr); /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writeb (dataval, mdio_addr); mdio_delay (mdio_addr); writeb (dataval | MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb (0, mdio_addr); mdio_delay (mdio_addr); writeb (MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } return;}static int rtl8139_open (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; int retval;#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr;#endif DPRINTK ("ENTER\n"); retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { DPRINTK ("EXIT, returning %d\n", retval); return retval; } tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, &tp->tx_bufs_dma); tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, &tp->rx_ring_dma); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { free_irq(dev->irq, dev); if (tp->tx_bufs) pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, tp->tx_bufs, tp->tx_bufs_dma); if (tp->rx_ring) pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; tp->twistie = 1; rtl8139_init_ring (dev); rtl8139_hw_start (dev); DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), tp->full_duplex ? "full" : "half"); DPRINTK ("EXIT, returning 0\n"); return 0;}/* Start the hardware at open or resume. */static void rtl8139_hw_start (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; u8 tmp; DPRINTK ("ENTER\n"); /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); udelay (100); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; /* unlock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); /* Must enable Tx/Rx before setting transfer thresholds! */ RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdRxEnb | CmdTxEnb); i = rtl8139_rx_config | (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32_F (RxConfig, i); /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); tp->cur_rx = 0; /* This is check_duplex() */ 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; 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); } if (tp->chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; tmp |= Cfg1_Driver_Load; tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ RTL_W8_F (Config1, tmp); } else { u8 foo = RTL_R8 (Config1) & Config1Clear; RTL_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); } if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ tmp |= (1<<7); RTL_W8 (Config4, tmp); /* disable magic packet scanning, which is enabled * when PM is enabled above (Config1) */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); } /* Lock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Lock); udelay (10); /* init Rx ring buffer DMA address */ RTL_W32_F (RxBuf, tp->rx_ring_dma); /* init Tx buffer DMA addresses */ for (i = 0; i < NUM_TX_DESC; i++) RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs)); RTL_W32_F (RxMissed, 0); rtl8139_set_rx_mode (dev); /* no early-rx interrupts */ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); /* make sure RxTx has started */ RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdRxEnb | CmdTxEnb); /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16_F (IntrMask, rtl8139_intr_mask); netif_start_queue (dev); DPRINTK ("EXIT\n");}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void rtl8139_init_ring (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; int i; DPRINTK ("ENTER\n"); tp->cur_rx = 0; tp->cur_tx = 0; tp->dirty_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { tp->tx_info[i].skb = NULL; tp->tx_info[i].mapping = 0; tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; } DPRINTK ("EXIT\n");}static int rtl8139CP_open (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; int retval; u8 diff; //for 8139C+ u32 txPhyAddr, rxPhyAddr; //for 8139C+#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr;#endif DPRINTK ("ENTER\n"); retval = request_irq (dev->irq, rtl8139CP_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { DPRINTK ("EXIT, returning %d\n", retval); return retval; } ////////////////////////////////////////////////////////////////////////////// tp->TxDescArrays= kmalloc(NUM_CP_TX_DESC*sizeof(struct CPlusTxDesc)+256 , GFP_KERNEL); // Tx Desscriptor needs 256 bytes alignment; txPhyAddr=virt_to_bus(tp->TxDescArrays); diff=txPhyAddr-((txPhyAddr >> 8)<< 8); diff=256-diff; txPhyAddr +=diff; tp->TxDescArray = (struct CPlusTxDesc *)(tp->TxDescArrays + diff); tp->RxDescArrays= kmalloc(NUM_CP_RX_DESC*sizeof(struct CPlusRxDesc)+256 , GFP_KERNEL); // Rx Desscriptor needs 256 bytes alignment; rxPhyAddr=virt_to_bus(tp->RxDescArrays); diff=rxPhyAddr-((rxPhyAddr >> 8)<< 8); diff=256-diff; rxPhyAddr +=diff; tp->RxDescArray = (struct CPlusRxDesc *)(tp->RxDescArrays + diff); if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) { printk(KERN_INFO"Allocate RxDescArray or TxDescArray failed\n"); free_irq(dev->irq, dev); if (tp->TxDescArrays) kfree(tp->TxDescArrays); if (tp->RxDescArrays) kfree(tp->RxDescArrays); DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } tp->RxBufferRings=kmalloc( CP_RX_BUF_SIZE*NUM_CP_RX_DESC, GFP_KERNEL); if(tp->RxBufferRings==NULL){ printk(KERN_INFO"Allocate RxBufferRing failed\n"); } ////////////////////////////////////////////////////////////////////////////// tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; tp->twistie = 1; rtl8139CP_init_ring (dev); rtl8139CP_hw_start (dev); DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), tp->full_duplex ? "full" : "half"); DPRINTK ("EXIT, returning 0\n"); return 0;}/* Start the hardware at open or resume. */static void rtl8139CP_hw_start (struct net_device *dev){ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; u8 tmp; u16 BasicModeCtrlReg; u8 MediaStatusReg; DPRINTK ("ENTER\n"); /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); udelay (100); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; /* unlock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); RTL_W16 (CPlusCmd, CPlusTxEnb | CPlusRxEnb | CPlusCheckSumEnb); //C+ mode only /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); /* Must enable Tx/Rx before setting transfer thresholds! */ RTL_W8 (ChipCmd,CmdRxEnb | CmdTxEnb); //C+ mode only RTL_W8 (CPlusEarlyTxThldReg, CPlusEarlyTxThld); //C+ mode only i = rtl8139_rx_config | (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32_F (RxConfig, i); /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)|0x03000000); tp->CP_cur_rx = 0;/* ////////////////////////////////////////////////////////////// RTL_W8_F (Cfg9346, Cfg9346_Unlock); RTL_W16 (NWayAdvert, AutoNegoAbility10half | AutoNegoAbility10full | AutoNegoAbility100half | AutoNegoAbility100full); RTL_W16_F (BasicModeCtrl, AutoNegotiationEnable|AutoNegotiationRestart); RTL_W8_F (Cfg9346, Cfg9346_Lock); //////////////////////////////////////////////////////////////*/ MediaStatusReg = RTL_R8(MediaStatus); BasicModeCtrlReg = RTL_R16(BasicModeCtrl); /* This is check_duplex() */ 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;/* 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);*/ printk(KERN_INFO"%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, (MediaStatusReg & Speed_10) ? "10mbps " : "100mbps ", (BasicModeCtrlReg & DuplexMode) ? "full" : "half", mii_reg5); } if (tp->chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; tmp |= Cfg1_Driver_Load; tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ RTL_W8_F (Config1, tmp); } else { u8 foo = RTL_R8 (Config1) & Config1Clear; RTL_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); } if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ tmp |= (1<<7); RTL_W8 (Config4, tmp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -