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

📄 r8169.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		.msi		= 0	},	[RTL_CFG_1] = {		.hw_start	= rtl_hw_start_8168,		.region		= 2,		.align		= 8,		.intr_event	= SYSErr | LinkChg | RxOverflow |				  TxErr | TxOK | RxOK | RxErr,		.napi_event	= TxErr | TxOK | RxOK | RxOverflow,		.msi		= RTL_FEATURE_MSI	},	[RTL_CFG_2] = {		.hw_start	= rtl_hw_start_8101,		.region		= 2,		.align		= 8,		.intr_event	= SYSErr | LinkChg | RxOverflow | PCSTimeout |				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,		.msi		= RTL_FEATURE_MSI	}};/* Cfg9346_Unlock assumed. */static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr,			    const struct rtl_cfg_info *cfg){	unsigned msi = 0;	u8 cfg2;	cfg2 = RTL_R8(Config2) & ~MSIEnable;	if (cfg->msi) {		if (pci_enable_msi(pdev)) {			dev_info(&pdev->dev, "no MSI. Back to INTx.\n");		} else {			cfg2 |= MSIEnable;			msi = RTL_FEATURE_MSI;		}	}	RTL_W8(Config2, cfg2);	return msi;}static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp){	if (tp->features & RTL_FEATURE_MSI) {		pci_disable_msi(pdev);		tp->features &= ~RTL_FEATURE_MSI;	}}static int __devinitrtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;	const unsigned int region = cfg->region;	struct rtl8169_private *tp;	struct net_device *dev;	void __iomem *ioaddr;	unsigned int i;	int rc;	if (netif_msg_drv(&debug)) {		printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",		       MODULENAME, RTL8169_VERSION);	}	dev = alloc_etherdev(sizeof (*tp));	if (!dev) {		if (netif_msg_drv(&debug))			dev_err(&pdev->dev, "unable to alloc new ethernet\n");		rc = -ENOMEM;		goto out;	}	SET_NETDEV_DEV(dev, &pdev->dev);	tp = netdev_priv(dev);	tp->dev = dev;	tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);	/* enable device (incl. PCI PM wakeup and hotplug setup) */	rc = pci_enable_device(pdev);	if (rc < 0) {		if (netif_msg_probe(tp))			dev_err(&pdev->dev, "enable failure\n");		goto err_out_free_dev_1;	}	rc = pci_set_mwi(pdev);	if (rc < 0)		goto err_out_disable_2;	/* make sure PCI base addr 1 is MMIO */	if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {		if (netif_msg_probe(tp)) {			dev_err(&pdev->dev,				"region #%d not an MMIO resource, aborting\n",				region);		}		rc = -ENODEV;		goto err_out_mwi_3;	}	/* check for weird/broken PCI region reporting */	if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {		if (netif_msg_probe(tp)) {			dev_err(&pdev->dev,				"Invalid PCI region size(s), aborting\n");		}		rc = -ENODEV;		goto err_out_mwi_3;	}	rc = pci_request_regions(pdev, MODULENAME);	if (rc < 0) {		if (netif_msg_probe(tp))			dev_err(&pdev->dev, "could not request regions.\n");		goto err_out_mwi_3;	}	tp->cp_cmd = PCIMulRW | RxChkSum;	if ((sizeof(dma_addr_t) > 4) &&	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) {		tp->cp_cmd |= PCIDAC;		dev->features |= NETIF_F_HIGHDMA;	} else {		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);		if (rc < 0) {			if (netif_msg_probe(tp)) {				dev_err(&pdev->dev,					"DMA configuration failed.\n");			}			goto err_out_free_res_4;		}	}	pci_set_master(pdev);	/* ioremap MMIO region */	ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);	if (!ioaddr) {		if (netif_msg_probe(tp))			dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");		rc = -EIO;		goto err_out_free_res_4;	}	/* Unneeded ? Don't mess with Mrs. Murphy. */	rtl8169_irq_mask_and_ack(ioaddr);	/* Soft reset the chip. */	RTL_W8(ChipCmd, CmdReset);	/* Check that the chip has finished the reset. */	for (i = 0; i < 100; i++) {		if ((RTL_R8(ChipCmd) & CmdReset) == 0)			break;		msleep_interruptible(1);	}	/* Identify chip attached to board */	rtl8169_get_mac_version(tp, ioaddr);	rtl8169_print_mac_version(tp);	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {		if (tp->mac_version == rtl_chip_info[i].mac_version)			break;	}	if (i < 0) {		/* Unknown chip: assume array element #0, original RTL-8169 */		if (netif_msg_probe(tp)) {			dev_printk(KERN_DEBUG, &pdev->dev,				"unknown chip version, assuming %s\n",				rtl_chip_info[0].name);		}		i++;	}	tp->chipset = i;	RTL_W8(Cfg9346, Cfg9346_Unlock);	RTL_W8(Config1, RTL_R8(Config1) | PMEnable);	RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);	tp->features |= rtl_try_msi(pdev, ioaddr, cfg);	RTL_W8(Cfg9346, Cfg9346_Lock);	if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&	    (RTL_R8(PHYstatus) & TBI_Enable)) {		tp->set_speed = rtl8169_set_speed_tbi;		tp->get_settings = rtl8169_gset_tbi;		tp->phy_reset_enable = rtl8169_tbi_reset_enable;		tp->phy_reset_pending = rtl8169_tbi_reset_pending;		tp->link_ok = rtl8169_tbi_link_ok;		tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */	} else {		tp->set_speed = rtl8169_set_speed_xmii;		tp->get_settings = rtl8169_gset_xmii;		tp->phy_reset_enable = rtl8169_xmii_reset_enable;		tp->phy_reset_pending = rtl8169_xmii_reset_pending;		tp->link_ok = rtl8169_xmii_link_ok;		dev->do_ioctl = rtl8169_ioctl;	}	/* Get MAC address.  FIXME: read EEPROM */	for (i = 0; i < MAC_ADDR_LEN; i++)		dev->dev_addr[i] = RTL_R8(MAC0 + i);	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);	dev->open = rtl8169_open;	dev->hard_start_xmit = rtl8169_start_xmit;	dev->get_stats = rtl8169_get_stats;	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);	dev->stop = rtl8169_close;	dev->tx_timeout = rtl8169_tx_timeout;	dev->set_multicast_list = rtl_set_rx_mode;	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;	dev->irq = pdev->irq;	dev->base_addr = (unsigned long) ioaddr;	dev->change_mtu = rtl8169_change_mtu;	dev->set_mac_address = rtl_set_mac_address;#ifdef CONFIG_R8169_NAPI	netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);#endif#ifdef CONFIG_R8169_VLAN	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;	dev->vlan_rx_register = rtl8169_vlan_rx_register;#endif#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = rtl8169_netpoll;#endif	tp->intr_mask = 0xffff;	tp->pci_dev = pdev;	tp->mmio_addr = ioaddr;	tp->align = cfg->align;	tp->hw_start = cfg->hw_start;	tp->intr_event = cfg->intr_event;	tp->napi_event = cfg->napi_event;	init_timer(&tp->timer);	tp->timer.data = (unsigned long) dev;	tp->timer.function = rtl8169_phy_timer;	spin_lock_init(&tp->lock);	rc = register_netdev(dev);	if (rc < 0)		goto err_out_msi_5;	pci_set_drvdata(pdev, dev);	if (netif_msg_probe(tp)) {		u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff;		printk(KERN_INFO "%s: %s at 0x%lx, "		       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "		       "XID %08x IRQ %d\n",		       dev->name,		       rtl_chip_info[tp->chipset].name,		       dev->base_addr,		       dev->dev_addr[0], dev->dev_addr[1],		       dev->dev_addr[2], dev->dev_addr[3],		       dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq);	}	rtl8169_init_phy(dev, tp);out:	return rc;err_out_msi_5:	rtl_disable_msi(pdev, tp);	iounmap(ioaddr);err_out_free_res_4:	pci_release_regions(pdev);err_out_mwi_3:	pci_clear_mwi(pdev);err_out_disable_2:	pci_disable_device(pdev);err_out_free_dev_1:	free_netdev(dev);	goto out;}static void __devexit rtl8169_remove_one(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	struct rtl8169_private *tp = netdev_priv(dev);	flush_scheduled_work();	unregister_netdev(dev);	rtl_disable_msi(pdev, tp);	rtl8169_release_board(pdev, dev, tp->mmio_addr);	pci_set_drvdata(pdev, NULL);}static void rtl8169_set_rxbufsize(struct rtl8169_private *tp,				  struct net_device *dev){	unsigned int mtu = dev->mtu;	tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE;}static int rtl8169_open(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	struct pci_dev *pdev = tp->pci_dev;	int retval = -ENOMEM;	rtl8169_set_rxbufsize(tp, dev);	/*	 * Rx and Tx desscriptors needs 256 bytes alignment.	 * pci_alloc_consistent provides more.	 */	tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,					       &tp->TxPhyAddr);	if (!tp->TxDescArray)		goto out;	tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,					       &tp->RxPhyAddr);	if (!tp->RxDescArray)		goto err_free_tx_0;	retval = rtl8169_init_ring(dev);	if (retval < 0)		goto err_free_rx_1;	INIT_DELAYED_WORK(&tp->task, NULL);	smp_mb();	retval = request_irq(dev->irq, rtl8169_interrupt,			     (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,			     dev->name, dev);	if (retval < 0)		goto err_release_ring_2;#ifdef CONFIG_R8169_NAPI	napi_enable(&tp->napi);#endif	rtl_hw_start(dev);	rtl8169_request_timer(dev);	rtl8169_check_link_status(dev, tp, tp->mmio_addr);out:	return retval;err_release_ring_2:	rtl8169_rx_clear(tp);err_free_rx_1:	pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,			    tp->RxPhyAddr);err_free_tx_0:	pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,			    tp->TxPhyAddr);	goto out;}static void rtl8169_hw_reset(void __iomem *ioaddr){	/* Disable interrupts */	rtl8169_irq_mask_and_ack(ioaddr);	/* Reset the chipset */	RTL_W8(ChipCmd, CmdReset);	/* PCI commit */	RTL_R8(ChipCmd);}static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp){	void __iomem *ioaddr = tp->mmio_addr;	u32 cfg = rtl8169_rx_config;	cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);	RTL_W32(RxConfig, cfg);	/* Set DMA burst size and Interframe Gap Time */	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |		(InterFrameGap << TxInterFrameGapShift));}static void rtl_hw_start(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	unsigned int i;	/* Soft reset the chip. */	RTL_W8(ChipCmd, CmdReset);	/* Check that the chip has finished the reset. */	for (i = 0; i < 100; i++) {		if ((RTL_R8(ChipCmd) & CmdReset) == 0)			break;		msleep_interruptible(1);	}	tp->hw_start(dev);	netif_start_queue(dev);}static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,					 void __iomem *ioaddr){	/*	 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh	 * register to be written before TxDescAddrLow to work.	 * Switching from MMIO to I/O access fixes the issue as well.	 */	RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);	RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);	RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);	RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);}static u16 rtl_rw_cpluscmd(void __iomem *ioaddr){	u16 cmd;	cmd = RTL_R16(CPlusCmd);	RTL_W16(CPlusCmd, cmd);	return cmd;}static void rtl_set_rx_max_size(void __iomem *ioaddr){	/* Low hurts. Let's disable the filtering. */	RTL_W16(RxMaxSize, 16383);}static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version){	struct {		u32 mac_version;		u32 clk;		u32 val;	} cfg2_info [] = {		{ RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd		{ RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },		{ RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe		{ RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }	}, *p = cfg2_info;	unsigned int i;	u32 clk;	clk = RTL_R8(Config2) & PCI_Clock_66MHz;	for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {		if ((p->mac_version == mac_version) && (p->clk == clk)) {			RTL_W32(0x7c, p->val);			break;		}	}}static void rtl_hw_start_8169(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	struct pci_dev *pdev = tp->pci_dev;	if (tp->mac_version == RTL_GIGA_MAC_VER_05) {		RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);	}	RTL_W8(Cfg9346, Cfg9346_Unlock);	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_04))		RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);	RTL_W8(EarlyTxThres, EarlyTxThld);	rtl_set_rx_max_size(ioaddr);	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_04))		rtl_set_rx_tx_config_registers(tp);	tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;	if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||	    (tp->mac_version == RTL_GIGA_MAC_VER_03)) {		dprintk("Set MAC Reg C+CR Offset 0xE0. "			"Bit-3 and bit-14 MUST be 1\n");		tp->cp_cmd |= (1 << 14);	}	RTL_W16(CPlusCmd, tp->cp_cmd);	rtl8169_set_magic_reg(ioaddr, tp->mac_version);	/*	 * Undocumented corner. Supposedly:	 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets

⌨️ 快捷键说明

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