📄 8139too.c
字号:
typedef enum { CH_8139 = 0, CH_8139_K, CH_8139A, CH_8139A_G, CH_8139B, CH_8130, CH_8139C, CH_8100, CH_8100B_8139D, CH_8101,} chip_t;enum chip_flags { HasHltClk = (1 << 0), HasLWake = (1 << 1),};#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)/* directly indexed by chip_t, above */const static struct { const char *name; u32 version; /* from RTL8139C/RTL8139D docs */ u32 flags;} rtl_chip_info[] = { { "RTL-8139", HW_REVID(1, 0, 0, 0, 0, 0, 0), HasHltClk, }, { "RTL-8139 rev K", HW_REVID(1, 1, 0, 0, 0, 0, 0), HasHltClk, }, { "RTL-8139A", HW_REVID(1, 1, 1, 0, 0, 0, 0), HasHltClk, /* XXX undocumented? */ }, { "RTL-8139A rev G", HW_REVID(1, 1, 1, 0, 0, 1, 0), HasHltClk, /* XXX undocumented? */ }, { "RTL-8139B", HW_REVID(1, 1, 1, 1, 0, 0, 0), HasLWake, }, { "RTL-8130", HW_REVID(1, 1, 1, 1, 1, 0, 0), HasLWake, }, { "RTL-8139C", HW_REVID(1, 1, 1, 0, 1, 0, 0), HasLWake, }, { "RTL-8100", HW_REVID(1, 1, 1, 1, 0, 1, 0), HasLWake, }, { "RTL-8100B/8139D", HW_REVID(1, 1, 1, 0, 1, 0, 1), HasLWake, }, { "RTL-8101", HW_REVID(1, 1, 1, 0, 1, 1, 1), HasLWake, },};struct rtl_extra_stats { unsigned long early_rx; unsigned long tx_buf_mapped; unsigned long tx_timeouts; unsigned long rx_lost_in_ring;};struct rtl8139_private { void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; u32 msg_enable; struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int tx_flag; unsigned long cur_tx; unsigned long dirty_tx; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ dma_addr_t rx_ring_dma; dma_addr_t tx_bufs_dma; signed char phys[4]; /* MII device addresses. */ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int default_port:4; /* Last dev->if_port value. */ spinlock_t lock; spinlock_t rx_lock; chip_t chipset; pid_t thr_pid; wait_queue_head_t thr_wait; struct completion thr_exited; u32 rx_config; struct rtl_extra_stats xstats; int time_to_die; struct mii_if_info mii; unsigned int regs_len; unsigned long fifo_copy_timeout;};MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);module_param(multicast_filter_limit, int, 0);module_param_array(media, int, NULL, 0);module_param_array(full_duplex, int, NULL, 0);module_param(debug, int, 0);MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");static int read_eeprom (void *ioaddr, int location, int addr_len);static int rtl8139_open (struct net_device *dev);static int mdio_read (struct net_device *dev, int phy_id, int location);static void mdio_write (struct net_device *dev, int phy_id, int location, int val);static void rtl8139_start_thread(struct net_device *dev);static void rtl8139_tx_timeout (struct net_device *dev);static void rtl8139_init_ring (struct net_device *dev);static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev);static int rtl8139_poll(struct net_device *dev, int *budget);#ifdef CONFIG_NET_POLL_CONTROLLERstatic void rtl8139_poll_controller(struct net_device *dev);#endifstatic irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs);static int rtl8139_close (struct net_device *dev);static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);static void rtl8139_set_rx_mode (struct net_device *dev);static void __set_rx_mode (struct net_device *dev);static void rtl8139_hw_start (struct net_device *dev);static struct ethtool_ops rtl8139_ethtool_ops;#ifdef USE_IO_OPS#define RTL_R8(reg) inb (((unsigned long)ioaddr) + (reg))#define RTL_R16(reg) inw (((unsigned long)ioaddr) + (reg))#define RTL_R32(reg) ((unsigned long) inl (((unsigned long)ioaddr) + (reg)))#define RTL_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg))#define RTL_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg))#define RTL_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg))#define RTL_W8_F RTL_W8#define RTL_W16_F RTL_W16#define RTL_W32_F RTL_W32#undef readb#undef readw#undef readl#undef writeb#undef writew#undef writel#define readb(addr) inb((unsigned long)(addr))#define readw(addr) inw((unsigned long)(addr))#define readl(addr) inl((unsigned long)(addr))#define writeb(val,addr) outb((val),(unsigned long)(addr))#define writew(val,addr) outw((val),(unsigned long)(addr))#define writel(val,addr) outl((val),(unsigned long)(addr))#else/* write MMIO register, with flush *//* Flush avoids rtl8139 bug w/ posted MMIO writes */#define RTL_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)#define RTL_W16_F(reg, val16) do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)#define RTL_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)#define MMIO_FLUSH_AUDIT_COMPLETE 1#if MMIO_FLUSH_AUDIT_COMPLETE/* write MMIO register */#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))#else/* write MMIO register, then flush */#define RTL_W8 RTL_W8_F#define RTL_W16 RTL_W16_F#define RTL_W32 RTL_W32_F#endif /* MMIO_FLUSH_AUDIT_COMPLETE *//* read MMIO register */#define RTL_R8(reg) readb (ioaddr + (reg))#define RTL_R16(reg) readw (ioaddr + (reg))#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))#endif /* USE_IO_OPS */static const u16 rtl8139_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;static const u16 rtl8139_norx_intr_mask = PCIErr | PCSTimeout | RxUnderrun | TxErr | TxOK | RxErr ;#if RX_BUF_IDX == 0static const unsigned int rtl8139_rx_config = RxCfgRcv8K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);#elif RX_BUF_IDX == 1static const unsigned int rtl8139_rx_config = RxCfgRcv16K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);#elif RX_BUF_IDX == 2static const unsigned int rtl8139_rx_config = RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);#elif RX_BUF_IDX == 3static const unsigned int rtl8139_rx_config = RxCfgRcv64K | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);#else#error "Invalid configuration for 8139_RXBUF_IDX"#endifstatic const unsigned int rtl8139_tx_config = TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);static void __rtl8139_cleanup_dev (struct net_device *dev){ struct rtl8139_private *tp = netdev_priv(dev); struct pci_dev *pdev; assert (dev != NULL); assert (tp->pci_dev != NULL); pdev = tp->pci_dev;#ifndef USE_IO_OPS if (tp->mmio_addr) iounmap (tp->mmio_addr);#endif /* !USE_IO_OPS */ /* it's ok to call this even if we have no regions to free */ pci_release_regions (pdev); free_netdev(dev); pci_set_drvdata (pdev, NULL);}static void rtl8139_chip_reset (void *ioaddr){ int i; /* Soft reset the chip. */ RTL_W8 (ChipCmd, CmdReset); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) { barrier(); if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; udelay (10); }}static int __devinit rtl8139_init_board (struct pci_dev *pdev, struct net_device **dev_out){ void *ioaddr; struct net_device *dev; struct rtl8139_private *tp; u8 tmp8; int rc, disable_dev_on_err = 0; unsigned int i; unsigned long pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 version; assert (pdev != NULL); *dev_out = NULL; /* dev and priv zeroed in alloc_etherdev */ dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev)); return -ENOMEM; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); tp->pci_dev = pdev; /* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pci_enable_device (pdev); if (rc) goto err_out; pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); pio_len = pci_resource_len (pdev, 0); mmio_start = pci_resource_start (pdev, 1); mmio_end = pci_resource_end (pdev, 1); mmio_flags = pci_resource_flags (pdev, 1); mmio_len = pci_resource_len (pdev, 1); /* set this immediately, we need to know before * we talk to the chip directly */ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);#ifdef USE_IO_OPS /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev)); rc = -ENODEV; goto err_out; } /* check for weird/broken PCI region reporting */ if (pio_len < RTL_MIN_IO_SIZE) { printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev)); rc = -ENODEV; goto err_out; }#else /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev)); rc = -ENODEV; goto err_out; } if (mmio_len < RTL_MIN_IO_SIZE) { printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev)); rc = -ENODEV; goto err_out; }#endif rc = pci_request_regions (pdev, "8139too"); if (rc) goto err_out; disable_dev_on_err = 1; /* enable PCI bus-mastering */ pci_set_master (pdev);#ifdef USE_IO_OPS ioaddr = (void *) pio_start; dev->base_addr = pio_start; tp->mmio_addr = ioaddr; tp->regs_len = pio_len;#else /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev)); rc = -EIO; goto err_out; } dev->base_addr = (long) ioaddr; tp->mmio_addr = ioaddr; tp->regs_len = mmio_len;#endif /* USE_IO_OPS */ /* Bring old chips out of low-power mode. */ RTL_W8 (HltClk, 'R'); /* check for missing/broken hardware */ if (RTL_R32 (TxConfig) == 0xFFFFFFFF) { printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n", pci_name(pdev)); rc = -EIO; goto err_out; } /* identify chip attached to board */ version = RTL_R32 (TxConfig) & HW_REVID_MASK; for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++) if (version == rtl_chip_info[i].version) { tp->chipset = i; goto match; } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n", pci_name(pdev)); printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig)); tp->chipset = 0;match: DPRINTK ("chipset id (%d) == index %d, '%s'\n", version, i, rtl_chip_info[i].name); if (tp->chipset >= CH_8139B) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); DPRINTK("PCI PM wakeup\n"); if ((rtl_chip_info[tp->chipset].flags & HasLWake) && (tmp8 & LWAKE)) new_tmp8 &= ~LWAKE; new_tmp8 |= Cfg1_PM_Enable; if (new_tmp8 != tmp8) { RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tmp8); RTL_W8 (Cfg9346, Cfg9346_Lock); } if (rtl_chip_info[tp->chipset].flags & HasLWake) { tmp8 = RTL_R8 (Config4); if (tmp8 & LWPTN) { RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config4, tmp8 & ~LWPTN); RTL_W8 (Cfg9346, Cfg9346_Lock); } } } else { DPRINTK("Old chip wakeup\n"); tmp8 = RTL_R8 (Config1); tmp8 &= ~(SLEEP | PWRDN); RTL_W8 (Config1, tmp8); } rtl8139_chip_reset (ioaddr); *dev_out = dev; return 0;err_out: __rtl8139_cleanup_dev (dev); if (disable_dev_on_err) pci_disable_device (pdev); return rc;}static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev = NULL; struct rtl8139_private *tp; int i, addr_len, option; void *ioaddr; static int board_idx = -1; u8 pci_rev; assert (pdev != NULL); assert (ent != NULL); board_idx++; /* when we're built into the kernel, the driver version message * is only printed if at least one 8139 board has been found */#ifndef MODULE { static int printed_version; if (!printed_version++) printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -