⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8139too.c

📁 rtl8139网卡
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 */static const 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),	  HasHltClk /* XXX undocumented? */	| 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 __iomem *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 watchdog_fired : 1;	unsigned int default_port : 4;	/* Last dev->if_port value. */	unsigned int have_thread : 1;	spinlock_t lock;	spinlock_t rx_lock;	chip_t chipset;	u32 rx_config;	struct rtl_extra_stats xstats;	struct delayed_work thread;	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 __iomem *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 rtl8139_private *tp);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);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 void rtl8139_thread (struct work_struct *work);static void rtl8139_tx_timeout_task(struct work_struct *work);static const struct ethtool_ops rtl8139_ethtool_ops;/* write MMIO register, with flush *//* Flush avoids rtl8139 bug w/ posted MMIO writes */#define RTL_W8_F(reg, val8)	do { iowrite8 ((val8), ioaddr + (reg)); ioread8 (ioaddr + (reg)); } while (0)#define RTL_W16_F(reg, val16)	do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)#define RTL_W32_F(reg, val32)	do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)#define MMIO_FLUSH_AUDIT_COMPLETE 1#if MMIO_FLUSH_AUDIT_COMPLETE/* write MMIO register */#define RTL_W8(reg, val8)	iowrite8 ((val8), ioaddr + (reg))#define RTL_W16(reg, val16)	iowrite16 ((val16), ioaddr + (reg))#define RTL_W32(reg, val32)	iowrite32 ((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)		ioread8 (ioaddr + (reg))#define RTL_R16(reg)		ioread16 (ioaddr + (reg))#define RTL_R32(reg)		((unsigned long) ioread32 (ioaddr + (reg)))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;#ifdef USE_IO_OPS	if (tp->mmio_addr)		ioport_unmap (tp->mmio_addr);#else	if (tp->mmio_addr)		pci_iounmap (pdev, 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 __iomem *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 __iomem *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) {		dev_err(&pdev->dev, "Unable to alloc new net device\n");		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)) {		dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");		rc = -ENODEV;		goto err_out;	}	/* check for weird/broken PCI region reporting */	if (pio_len < RTL_MIN_IO_SIZE) {		dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n");		rc = -ENODEV;		goto err_out;	}#else	/* make sure PCI base addr 1 is MMIO */	if (!(mmio_flags & IORESOURCE_MEM)) {		dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");		rc = -ENODEV;		goto err_out;	}	if (mmio_len < RTL_MIN_IO_SIZE) {		dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n");		rc = -ENODEV;		goto err_out;	}#endif	rc = pci_request_regions (pdev, DRV_NAME);	if (rc)		goto err_out;	disable_dev_on_err = 1;	/* enable PCI bus-mastering */	pci_set_master (pdev);#ifdef USE_IO_OPS	ioaddr = ioport_map(pio_start, pio_len);	if (!ioaddr) {		dev_err(&pdev->dev, "cannot map PIO, aborting\n");		rc = -EIO;		goto err_out;	}	dev->base_addr = pio_start;	tp->mmio_addr = ioaddr;	tp->regs_len = pio_len;#else	/* ioremap MMIO region */	ioaddr = pci_iomap(pdev, 1, 0);	if (ioaddr == NULL) {		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");		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) {		dev_err(&pdev->dev, "Chip not responding, ignoring board\n");		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 */	dev_printk (KERN_DEBUG, &pdev->dev,		    "unknown chip version, assuming RTL-8139\n");	dev_printk (KERN_DEBUG, &pdev->dev,		    "TxConfig = 0x%lx\n", 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 __iomem *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");	}#endif	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {		dev_info(&pdev->dev,			   "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",		       	   pdev->vendor, pdev->device, pci_rev);		dev_info(&pdev->dev,			   "Use the \"8139cp\" driver for improved performance and stability.\n");	}	i = rtl8139_init_board (pdev, &dev);	if (i < 0)		return i;	assert (dev != NULL);	tp = netdev_priv(dev);	ioaddr = tp->mmio_addr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -