📄 rtl8139.c
字号:
return NULL; /* We do a request_region() to register /proc/ioports info. */ request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); dev->base_addr = ioaddr; dev->irq = irq; dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN); memset(np, 0, sizeof(*np)); np->priv_addr = priv_mem; np->next_module = root_rtl8129_dev; root_rtl8129_dev = dev; np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_tbl[chip_idx].drv_flags; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes too much time. */ if (np->drv_flags & HAS_MII_XCVR) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < sizeof(np->phys); phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->advertising = mdio_read(dev, phy, 4); printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " "advertising %4.4x.\n", dev->name, phy, mii_status, np->advertising); } } if (phy_idx == 0) { printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " "transceiver.\n", dev->name); np->phys[0] = 32; } } else np->phys[0] = 32; /* Put the chip into low-power mode. */ outb(0xC0, ioaddr + Cfg9346); outb(0x03, ioaddr + Config1); outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ /* The lower four bits are the media type. */ if (option > 0) { np->full_duplex = (option & 0x210) ? 1 : 0; np->default_port = option & 0xff; if (np->default_port) np->medialock = 1; } if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) np->full_duplex = full_duplex[found_cnt]; if (np->full_duplex) { printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); /* Changing the MII-advertised media because might prevent re-connection. */ np->duplex_lock = 1; } if (np->default_port) { printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", (option & 0x20 ? 100 : 10), (option & 0x10 ? "full" : "half")); mdio_write(dev, np->phys[0], 0, ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } /* The Rtl8129-specific entries in the device structure. */ dev->open = &rtl8129_open; dev->hard_start_xmit = &rtl8129_start_xmit; dev->stop = &rtl8129_close; dev->get_stats = &rtl8129_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; return dev;}/* 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 eeprom_delay() inl(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 read_eeprom(long ioaddr, int location, int addr_len){ int i; unsigned retval = 0; long ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); outb(EE_ENB & ~EE_CS, ee_addr); outb(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outb(EE_ENB | dataval, ee_addr); eeprom_delay(); outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); } outb(EE_ENB, ee_addr); eeprom_delay(); for (i = 16; i > 0; i--) { outb(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); outb(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outb(~EE_CS, ee_addr); return retval;}/* MII serial management: mostly bogus for now. *//* Read and write the MII management registers using software-generated serial MDIO protocol. The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues. */#define MDIO_DIR 0x80#define MDIO_DATA_OUT 0x04#define MDIO_DATA_IN 0x02#define MDIO_CLK 0x01#define MDIO_WRITE0 (MDIO_DIR)#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)#define mdio_delay(mdio_addr) inb(mdio_addr)static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert, NWayLPAR, NWayExpansion, 0 };/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync(long mdio_addr){ int i; for (i = 32; i >= 0; i--) { outb(MDIO_WRITE1, mdio_addr); mdio_delay(mdio_addr); outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay(mdio_addr); } return;}static int mdio_read(struct net_device *dev, int phy_id, int location){ long mdio_addr = dev->base_addr + MII_SMI; 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] ? inw(dev->base_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; outb(MDIO_DIR | dataval, mdio_addr); mdio_delay(mdio_addr); outb(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--) { outb(0, mdio_addr); mdio_delay(mdio_addr); retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); outb(MDIO_CLK, mdio_addr); mdio_delay(mdio_addr); } return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){ long mdio_addr = dev->base_addr + MII_SMI; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; if (phy_id > 31) { /* Really a 8139. Use internal registers. */ long ioaddr = dev->base_addr; if (location == 0) { outb(0xC0, ioaddr + Cfg9346); outw(value, ioaddr + MII_BMCR); outb(0x00, ioaddr + Cfg9346); } else if (location < 8 && mii_2_8139_map[location]) outw(value, ioaddr + mii_2_8139_map[location]); 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; outb(dataval, mdio_addr); mdio_delay(mdio_addr); outb(dataval | MDIO_CLK, mdio_addr); mdio_delay(mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outb(0, mdio_addr); mdio_delay(mdio_addr); outb(MDIO_CLK, mdio_addr); mdio_delay(mdio_addr); } return;}static int rtl8129_open(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int rx_buf_len_idx; 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. */ rx_buf_len_idx = RX_BUF_LEN_IDX; do { tp->rx_buf_len = 8192 << rx_buf_len_idx; tp->rx_ring = kmalloc(tp->rx_buf_len + 16 + (TX_BUF_SIZE * NUM_TX_DESC), GFP_KERNEL); } while (tp->rx_ring == NULL && --rx_buf_len_idx >= 0); if (tp->rx_ring == NULL) { if (debug > 0) printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", dev->name, tp->rx_buf_len); MOD_DEC_USE_COUNT; return -ENOMEM; } tp->tx_bufs = tp->rx_ring + tp->rx_buf_len + 16; rtl8129_init_ring(dev); tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000; tp->rx_config = (RX_FIFO_THRESH << 13) | (rx_buf_len_idx << 11) | (RX_DMA_BURST<<8); rtl_hw_start(dev); netif_start_tx_queue(dev); 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. */ outb(0xC0, ioaddr + Cfg9346); 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? */ tp->cur_rx = 0; /* Must enable Tx/Rx before setting transfer thresholds! */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); 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<<8), ioaddr + TxConfig); /* 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; 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(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(0x00, 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); /* 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 *np = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; int mii_reg5 = mdio_read(dev, np->phys[0], 5); if (! np->duplex_lock && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; if (np->full_duplex != duplex) { np->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" " partner ability of %4.4x.\n", dev->name, np->full_duplex ? "full" : "half", np->phys[0], mii_reg5); outb(0xC0, ioaddr + Cfg9346); outb(np->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(0x00, ioaddr + Cfg9346); } }#if LINUX_VERSION_CODE < 0x20300 /* 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); rtl8129_interrupt(dev->irq, dev, 0); } } if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT) rtl8129_tx_timeout(dev);#else if (netif_queue_paused(dev) && np->cur_tx - np->dirty_tx > 1 && (jiffies - dev->trans_start) > TX_TIMEOUT) { rtl8129_tx_timeout(dev); }#endif#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 (np->twistie) switch(np->twistie) { case 1: { if (inw(ioaddr + CSCR) & CSCR_LinkOKBit) { /* We have link beat, let us tune the twister. */ outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -