📄 rtl8139.c.1
字号:
} } if (phy_idx == 0) { printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " "transceiver.\n", dev->name); tp->phys[0] = -1; } } else { tp->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) { tp->full_duplex = (option & 0x200) ? 1 : 0; tp->default_port = option & 15; if (tp->default_port) tp->medialock = 1; } if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) tp->full_duplex = full_duplex[found_cnt]; if (tp->full_duplex) { printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); mdio_write(dev, tp->phys[0], 4, 0x141); tp->duplex_lock = 1; } /* 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 << 6)#define EE_READ_CMD (6 << 6)#define EE_ERASE_CMD (7 << 6)static int read_eeprom(long ioaddr, int location){ int i; unsigned retval = 0; long ee_addr = ioaddr + Cfg9346; int read_cmd = location | EE_READ_CMD; outb(EE_ENB & ~EE_CS, ee_addr); outb(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 10; 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() 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(); outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay(); } return;}static int mdio_read(struct 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 & 0x1f) == 0) { /* 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(); outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr); mdio_delay(); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outb(0, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); outb(MDIO_CLK, mdio_addr); mdio_delay(); } return (retval>>1) & 0xffff;}static void mdio_write(struct 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 == 32) { /* Really a 8139. Use internal registers. */ if (location < 8 && mii_2_8139_map[location]) outw(value, dev->base_addr + 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(); outb(dataval | MDIO_CLK, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outb(0, mdio_addr); mdio_delay(); outb(MDIO_CLK, mdio_addr); mdio_delay(); } return;}static intrtl8129_open(struct 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); if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) { return -EAGAIN; } request_irq(14, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev); request_irq(9, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev); request_irq(11, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev); MOD_INC_USE_COUNT; tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL); tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { if (tp->tx_bufs) kfree(tp->tx_bufs); if (rtl8129_debug > 0) printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", dev->name, RX_BUF_LEN); return -ENOMEM; } rtl8129_init_ring(dev); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break; for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + MAC0 + i); /* Must enable Tx/Rx before setting transfer thresholds! */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), ioaddr + RxConfig); outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000; tp->full_duplex = tp->duplex_lock; if (tp->phys[0] >= 0 || (rtl_cap_tbl[tp->chip_id] & 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 (rtl8129_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(0xC0, ioaddr + Cfg9346); 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); 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 (rtl8129_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 = RUN_AT((24*HZ)/10); /* 2.4 sec. */ tp->timer.data = (unsigned long)dev; tp->timer.function = &rtl8129_timer; /* timer handler */ add_timer(&tp->timer); return 0;}static void rtl8129_timer(unsigned long data){ struct device *dev = (struct device *)data; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 0; int mii_reg5 = mdio_read(dev, tp->phys[0], 5); printk("inside rtl8129_timer\n"); 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(0xC0, ioaddr + Cfg9346); outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(0x00, ioaddr + Cfg9346); } next_tick = 60*HZ; } if (rtl8129_debug > 2) { if (rtl_cap_tbl[tp->chip_id] & 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)); } if (next_tick) { tp->timer.expires = RUN_AT(next_tick); add_timer(&tp->timer); }}static void rtl8129_tx_timeout(struct device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int mii_reg, i; if (rtl8129_debug > 0) printk(KERN_WARNING "%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("%s: Tx queue start entry %d dirty entry %d.\n", dev->name, tp->cur_tx, tp->dirty_tx); 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"); /* 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; for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + MAC0 + i); outb(0x00, ioaddr + Cfg9346); tp->cur_rx = 0; /* Must enable Tx/Rx before setting transfer thresholds! */ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), ioaddr + RxConfig); outl((TX_DMA_BURST<<8), ioaddr + TxConfig); set_rx_mode(dev); { /* Save the unsent Tx packets. */ struct sk_buff *saved_skb[NUM_TX_DESC], *skb; int j; for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) saved_skb[j] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC]; tp->dirty_tx = tp->cur_tx = 0; for (i = 0; i < j; i++) { skb = tp->tx_skbuff[i] = saved_skb[i]; if ((long)skb->data & 3) { /* Must use alignment buffer. */ memcpy(tp->tx_buf[i], skb->data, skb->len); outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4); } else outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4); /* Note: the chip doesn't have auto-pad! */ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), ioaddr + TxStatus0 + i*4); } tp->cur_tx = i; while (i < NUM_TX_DESC) tp->tx_skbuff[i] = 0; if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ dev->tbusy = 0; tp->tx_full = 0; } else { tp->tx_full = 1; } } dev->trans_start = jiffies; tp->stats.tx_errors++; /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidrtl8129_init_ring(struct device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; int i; tp->tx_full = 0; tp->cur_rx = 0; tp->dirty_tx = tp->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { tp->tx_skbuff[i] = 0; tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE]; }}static intrtl8129_start_xmit(struct sk_buff *skb, struct device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; int entry; printk("start rtl8129_start_xmit\n"); /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { if (jiffies - dev->trans_start < TX_TIMEOUT) return 1; rtl8129_tx_timeout(dev); return 1; } /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; tp->tx_skbuff[entry] = skb; if ((long)skb->data & 3) { /* Must use alignment buffer. */ memcpy(tp->tx_buf[entry], skb->data, skb->len); outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4); } else outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4); /* Note: the chip doesn't have auto-pad! */ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), ioaddr + TxStatus0 + entry*4); if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ clear_bit(0, (void*)&dev->tbusy); } else { tp->tx_full = 1; } dev->trans_start = jiffies; if (rtl8129_debug > 4)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -