📄 rtl_8139too.c
字号:
/* h/w no longer present (hotplug?) or major error, bail */ if (status == 0xFFFF) break; /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); if ((status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) { break; } if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) { /* Rx interrupt */ rt_rtl8139_rx_interrupt (dev); } if (status & (TxOK | TxErr)) { rt_rtl8139_tx_interrupt (dev); } boguscnt--; } while (boguscnt > 0); if (boguscnt <= 0) { rtl_printf ( "%s: Too much work at interrupt, " "IntrStatus=0x%4.4x.\n", dev->name, status); /* Clear all interrupt sources. */ RTL_W16 (IntrStatus, 0xffff); } if(!trying_to_close){ rtl_hard_enable_irq(private_data.pdev->irq); } rt_rtl8139_interrupted--; return (inside_the_interrupt_handler = 0);}/* Syncronize the MII management interface by shifting 32 one bits out. */ static void rt_rtl8139_mdio_sync (void *mdio_addr){ int i; for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); } }static int rt_rtl8139_mdio_read (struct pci_dev *dev, int phy_id, int location){ void *mdio_addr = private_data.mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; int i; if (phy_id > 31) { /* Really a 8139. Use internal registers. */ return location < 8 && mii_2_8139_map[location] ? readw (private_data.mmio_addr + mii_2_8139_map[location]) : 0; } rt_rtl8139_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); rt_rtl8139_mdio_delay (mdio_addr); writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb (0, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); writeb (MDIO_CLK, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); } return (retval >> 1) & 0xffff;}static void rt_rtl8139_mdio_write (struct pci_dev *dev, int phy_id, int location, int value){ void *mdio_addr = private_data.mmio_addr + Config4; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void *ioaddr = private_data.mmio_addr; if (location == 0) { RTL_W8_F (Cfg9346, Cfg9346_Unlock); ////////////////////////////////////////////////////////////// switch(private_data.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_W8_F (Cfg9346, Cfg9346_Lock); } else if (location < 8 && mii_2_8139_map[location]) RTL_W16_F (mii_2_8139_map[location], value); return; } rt_rtl8139_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); rt_rtl8139_mdio_delay (mdio_addr); writeb (dataval | MDIO_CLK, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb (0, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); writeb (MDIO_CLK, mdio_addr); rt_rtl8139_mdio_delay (mdio_addr); } return;}/* Serial EEPROM section. */ /* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */#define EE_CS 0x08 /* EEPROM chip select. */#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */#define EE_WRITE_0 0x00#define EE_WRITE_1 0x02#define EE_DATA_READ 0x01 /* EEPROM chip data out. */#define EE_ENB (0x80 | EE_CS) /* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */ #define rt_rtl8139_eeprom_delay() readl(ee_addr) /* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5)#define EE_READ_CMD (6)#define EE_ERASE_CMD (7)static int __devinit rt_rtl8139_read_eeprom (void *ioaddr, int location, int addr_len){ int i; unsigned retval = 0; void *ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); writeb (EE_ENB & ~EE_CS, ee_addr); writeb (EE_ENB, ee_addr); rt_rtl8139_eeprom_delay (); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; writeb (EE_ENB | dataval, ee_addr); rt_rtl8139_eeprom_delay (); writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); rt_rtl8139_eeprom_delay (); } writeb (EE_ENB, ee_addr); rt_rtl8139_eeprom_delay (); for (i = 16; i > 0; i--) { writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); rt_rtl8139_eeprom_delay (); retval = (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 : 0); writeb (EE_ENB, ee_addr); rt_rtl8139_eeprom_delay (); } /* Terminate the EEPROM access. */ writeb (~EE_CS, ee_addr); rt_rtl8139_eeprom_delay (); return retval;}/* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ static unsigned const ethernet_polynomial = 0x04c11db7U;static inline u32 rt_rtl8139_ether_crc (int length, unsigned char *data){ int crc = -1; while (--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } return crc;} static void rt_rtl8139_set_rx_mode (struct pci_dev *dev){ void *ioaddr = private_data.mmio_addr; int rx_mode; u32 tmp; /* Note: do not reorder, GCC is clever about common statements. */ rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptAllPhys; /* We can safely update without stopping the chip. */ tmp = rtl8139_rx_config | rx_mode | (RTL_R32 (RxConfig) & rtl_chip_info[private_data.chipset].RxConfigMask); RTL_W32_F (RxConfig, tmp); rtl_printf ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, private_data.drv_flags, RTL_R32 (RxConfig)); }/* Start the hardware at open or resume. */static void rt_rtl8139_hw_start (struct pci_dev *dev){ void *ioaddr = private_data.mmio_addr; u32 i; u8 tmp; /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); rtl_delay (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 *) (private_data.dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (private_data.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[private_data.chipset].RxConfigMask); RTL_W32_F (RxConfig, i); /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); private_data.cur_rx = 0; /* This is check_duplex() */ if (private_data.phys[0] >= 0 || (private_data.drv_flags & HAS_MII_XCVR)) { u16 mii_reg5 = rt_rtl8139_mdio_read(dev, private_data.phys[0], 5); if (mii_reg5 == 0xffff) ; /* Not there */ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) private_data.full_duplex = 1; rtl_printf("%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", private_data.full_duplex ? "full" : "half", mii_reg5); } if (private_data.chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; tmp |= Cfg1_Driver_Load; tmp |= (private_data.chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ RTL_W8_F (Config1, tmp); } else { u8 foo = RTL_R8 (Config1) & Config1Clear; RTL_W8 (Config1, private_data.full_duplex ? (foo|0x60) : (foo|0x20)); } if (private_data.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); rtl_delay (10); /* init Rx ring buffer DMA address */ RTL_W32_F (RxBuf, private_data.rx_ring_dma); /* init Tx buffer DMA addresses */ for (i = 0; i < NUM_TX_DESC; i++) RTL_W32_F (TxAddr0 + (i * 4), private_data.tx_bufs_dma + (private_data.tx_buf[i] - private_data.tx_bufs)); RTL_W32_F (RxMissed, 0); rt_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); }/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void rt_rtl8139_init_ring (struct pci_dev *dev){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -