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

📄 r8169.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	ASSERT_RTNL();	counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);	if (!counters)		return;	RTL_W32(CounterAddrHigh, (u64)paddr >> 32);	cmd = (u64)paddr & DMA_32BIT_MASK;	RTL_W32(CounterAddrLow, cmd);	RTL_W32(CounterAddrLow, cmd | CounterDump);	while (RTL_R32(CounterAddrLow) & CounterDump) {		if (msleep_interruptible(1))			break;	}	RTL_W32(CounterAddrLow, 0);	RTL_W32(CounterAddrHigh, 0);	data[0] = le64_to_cpu(counters->tx_packets);	data[1] = le64_to_cpu(counters->rx_packets);	data[2] = le64_to_cpu(counters->tx_errors);	data[3] = le32_to_cpu(counters->rx_errors);	data[4] = le16_to_cpu(counters->rx_missed);	data[5] = le16_to_cpu(counters->align_errors);	data[6] = le32_to_cpu(counters->tx_one_collision);	data[7] = le32_to_cpu(counters->tx_multi_collision);	data[8] = le64_to_cpu(counters->rx_unicast);	data[9] = le64_to_cpu(counters->rx_broadcast);	data[10] = le32_to_cpu(counters->rx_multicast);	data[11] = le16_to_cpu(counters->tx_aborted);	data[12] = le16_to_cpu(counters->tx_underun);	pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);}static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data){	switch(stringset) {	case ETH_SS_STATS:		memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));		break;	}}static const struct ethtool_ops rtl8169_ethtool_ops = {	.get_drvinfo		= rtl8169_get_drvinfo,	.get_regs_len		= rtl8169_get_regs_len,	.get_link		= ethtool_op_get_link,	.get_settings		= rtl8169_get_settings,	.set_settings		= rtl8169_set_settings,	.get_msglevel		= rtl8169_get_msglevel,	.set_msglevel		= rtl8169_set_msglevel,	.get_rx_csum		= rtl8169_get_rx_csum,	.set_rx_csum		= rtl8169_set_rx_csum,	.set_tx_csum		= ethtool_op_set_tx_csum,	.set_sg			= ethtool_op_set_sg,	.set_tso		= ethtool_op_set_tso,	.get_regs		= rtl8169_get_regs,	.get_wol		= rtl8169_get_wol,	.set_wol		= rtl8169_set_wol,	.get_strings		= rtl8169_get_strings,	.get_sset_count		= rtl8169_get_sset_count,	.get_ethtool_stats	= rtl8169_get_ethtool_stats,};static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg,				       int bitnum, int bitval){	int val;	val = mdio_read(ioaddr, reg);	val = (bitval == 1) ?		val | (bitval << bitnum) :  val & ~(0x0001 << bitnum);	mdio_write(ioaddr, reg, val & 0xffff);}static void rtl8169_get_mac_version(struct rtl8169_private *tp,				    void __iomem *ioaddr){	/*	 * The driver currently handles the 8168Bf and the 8168Be identically	 * but they can be identified more specifically through the test below	 * if needed:	 *	 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be	 *	 * Same thing for the 8101Eb and the 8101Ec:	 *	 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec	 */	const struct {		u32 mask;		u32 val;		int mac_version;	} mac_info[] = {		/* 8168B family. */		{ 0x7c800000, 0x3c800000,	RTL_GIGA_MAC_VER_18 },		{ 0x7cf00000, 0x3c000000,	RTL_GIGA_MAC_VER_19 },		{ 0x7cf00000, 0x3c200000,	RTL_GIGA_MAC_VER_20 },		{ 0x7c800000, 0x3c000000,	RTL_GIGA_MAC_VER_20 },		/* 8168B family. */		{ 0x7cf00000, 0x38000000,	RTL_GIGA_MAC_VER_12 },		{ 0x7cf00000, 0x38500000,	RTL_GIGA_MAC_VER_17 },		{ 0x7c800000, 0x38000000,	RTL_GIGA_MAC_VER_17 },		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },		/* 8101 family. */		{ 0x7cf00000, 0x34000000,	RTL_GIGA_MAC_VER_13 },		{ 0x7cf00000, 0x34200000,	RTL_GIGA_MAC_VER_16 },		{ 0x7c800000, 0x34000000,	RTL_GIGA_MAC_VER_16 },		/* FIXME: where did these entries come from ? -- FR */		{ 0xfc800000, 0x38800000,	RTL_GIGA_MAC_VER_15 },		{ 0xfc800000, 0x30800000,	RTL_GIGA_MAC_VER_14 },		/* 8110 family. */		{ 0xfc800000, 0x98000000,	RTL_GIGA_MAC_VER_06 },		{ 0xfc800000, 0x18000000,	RTL_GIGA_MAC_VER_05 },		{ 0xfc800000, 0x10000000,	RTL_GIGA_MAC_VER_04 },		{ 0xfc800000, 0x04000000,	RTL_GIGA_MAC_VER_03 },		{ 0xfc800000, 0x00800000,	RTL_GIGA_MAC_VER_02 },		{ 0xfc800000, 0x00000000,	RTL_GIGA_MAC_VER_01 },		{ 0x00000000, 0x00000000,	RTL_GIGA_MAC_VER_01 }	/* Catch-all */	}, *p = mac_info;	u32 reg;	reg = RTL_R32(TxConfig);	while ((reg & p->mask) != p->val)		p++;	tp->mac_version = p->mac_version;	if (p->mask == 0x00000000) {		struct pci_dev *pdev = tp->pci_dev;		dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);	}}static void rtl8169_print_mac_version(struct rtl8169_private *tp){	dprintk("mac_version = 0x%02x\n", tp->mac_version);}struct phy_reg {	u16 reg;	u16 val;};static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len){	while (len-- > 0) {		mdio_write(ioaddr, regs->reg, regs->val);		regs++;	}}static void rtl8169s_hw_phy_config(void __iomem *ioaddr){	struct {		u16 regs[5]; /* Beware of bit-sign propagation */	} phy_magic[5] = { {		{ 0x0000,	//w 4 15 12 0		  0x00a1,	//w 3 15 0 00a1		  0x0008,	//w 2 15 0 0008		  0x1020,	//w 1 15 0 1020		  0x1000 } },{	//w 0 15 0 1000		{ 0x7000,	//w 4 15 12 7		  0xff41,	//w 3 15 0 ff41		  0xde60,	//w 2 15 0 de60		  0x0140,	//w 1 15 0 0140		  0x0077 } },{	//w 0 15 0 0077		{ 0xa000,	//w 4 15 12 a		  0xdf01,	//w 3 15 0 df01		  0xdf20,	//w 2 15 0 df20		  0xff95,	//w 1 15 0 ff95		  0xfa00 } },{	//w 0 15 0 fa00		{ 0xb000,	//w 4 15 12 b		  0xff41,	//w 3 15 0 ff41		  0xde20,	//w 2 15 0 de20		  0x0140,	//w 1 15 0 0140		  0x00bb } },{	//w 0 15 0 00bb		{ 0xf000,	//w 4 15 12 f		  0xdf01,	//w 3 15 0 df01		  0xdf20,	//w 2 15 0 df20		  0xff95,	//w 1 15 0 ff95		  0xbf00 }	//w 0 15 0 bf00		}	}, *p = phy_magic;	unsigned int i;	mdio_write(ioaddr, 0x1f, 0x0001);		//w 31 2 0 1	mdio_write(ioaddr, 0x15, 0x1000);		//w 21 15 0 1000	mdio_write(ioaddr, 0x18, 0x65c7);		//w 24 15 0 65c7	rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);	//w 4 11 11 0	for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {		int val, pos = 4;		val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);		mdio_write(ioaddr, pos, val);		while (--pos >= 0)			mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0	}	mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0}static void rtl8169sb_hw_phy_config(void __iomem *ioaddr){	struct phy_reg phy_reg_init[] = {		{ 0x1f, 0x0002 },		{ 0x01, 0x90d0 },		{ 0x1f, 0x0000 }	};	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl8168cp_hw_phy_config(void __iomem *ioaddr){	struct phy_reg phy_reg_init[] = {		{ 0x1f, 0x0000 },		{ 0x1d, 0x0f00 },		{ 0x1f, 0x0002 },		{ 0x0c, 0x1ec8 },		{ 0x1f, 0x0000 }	};	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl8168c_hw_phy_config(void __iomem *ioaddr){	struct phy_reg phy_reg_init[] = {		{ 0x1f, 0x0001 },		{ 0x12, 0x2300 },		{ 0x1f, 0x0002 },		{ 0x00, 0x88d4 },		{ 0x01, 0x82b1 },		{ 0x03, 0x7002 },		{ 0x08, 0x9e30 },		{ 0x09, 0x01f0 },		{ 0x0a, 0x5500 },		{ 0x0c, 0x00c8 },		{ 0x1f, 0x0003 },		{ 0x12, 0xc096 },		{ 0x16, 0x000a },		{ 0x1f, 0x0000 }	};	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl8168cx_hw_phy_config(void __iomem *ioaddr){	struct phy_reg phy_reg_init[] = {		{ 0x1f, 0x0000 },		{ 0x12, 0x2300 },		{ 0x1f, 0x0003 },		{ 0x16, 0x0f0a },		{ 0x1f, 0x0000 },		{ 0x1f, 0x0002 },		{ 0x0c, 0x7eb8 },		{ 0x1f, 0x0000 }	};	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl_hw_phy_config(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	rtl8169_print_mac_version(tp);	switch (tp->mac_version) {	case RTL_GIGA_MAC_VER_01:		break;	case RTL_GIGA_MAC_VER_02:	case RTL_GIGA_MAC_VER_03:		rtl8169s_hw_phy_config(ioaddr);		break;	case RTL_GIGA_MAC_VER_04:		rtl8169sb_hw_phy_config(ioaddr);		break;	case RTL_GIGA_MAC_VER_18:		rtl8168cp_hw_phy_config(ioaddr);		break;	case RTL_GIGA_MAC_VER_19:		rtl8168c_hw_phy_config(ioaddr);		break;	case RTL_GIGA_MAC_VER_20:		rtl8168cx_hw_phy_config(ioaddr);		break;	default:		break;	}}static void rtl8169_phy_timer(unsigned long __opaque){	struct net_device *dev = (struct net_device *)__opaque;	struct rtl8169_private *tp = netdev_priv(dev);	struct timer_list *timer = &tp->timer;	void __iomem *ioaddr = tp->mmio_addr;	unsigned long timeout = RTL8169_PHY_TIMEOUT;	assert(tp->mac_version > RTL_GIGA_MAC_VER_01);	if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))		return;	spin_lock_irq(&tp->lock);	if (tp->phy_reset_pending(ioaddr)) {		/*		 * A busy loop could burn quite a few cycles on nowadays CPU.		 * Let's delay the execution of the timer for a few ticks.		 */		timeout = HZ/10;		goto out_mod_timer;	}	if (tp->link_ok(ioaddr))		goto out_unlock;	if (netif_msg_link(tp))		printk(KERN_WARNING "%s: PHY reset until link up\n", dev->name);	tp->phy_reset_enable(ioaddr);out_mod_timer:	mod_timer(timer, jiffies + timeout);out_unlock:	spin_unlock_irq(&tp->lock);}static inline void rtl8169_delete_timer(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	struct timer_list *timer = &tp->timer;	if (tp->mac_version <= RTL_GIGA_MAC_VER_01)		return;	del_timer_sync(timer);}static inline void rtl8169_request_timer(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	struct timer_list *timer = &tp->timer;	if (tp->mac_version <= RTL_GIGA_MAC_VER_01)		return;	mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);}#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */static void rtl8169_netpoll(struct net_device *dev){	struct rtl8169_private *tp = netdev_priv(dev);	struct pci_dev *pdev = tp->pci_dev;	disable_irq(pdev->irq);	rtl8169_interrupt(pdev->irq, dev);	enable_irq(pdev->irq);}#endifstatic void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,				  void __iomem *ioaddr){	iounmap(ioaddr);	pci_release_regions(pdev);	pci_disable_device(pdev);	free_netdev(dev);}static void rtl8169_phy_reset(struct net_device *dev,			      struct rtl8169_private *tp){	void __iomem *ioaddr = tp->mmio_addr;	unsigned int i;	tp->phy_reset_enable(ioaddr);	for (i = 0; i < 100; i++) {		if (!tp->phy_reset_pending(ioaddr))			return;		msleep(1);	}	if (netif_msg_link(tp))		printk(KERN_ERR "%s: PHY reset failed.\n", dev->name);}static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp){	void __iomem *ioaddr = tp->mmio_addr;	rtl_hw_phy_config(dev);	dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");	RTL_W8(0x82, 0x01);	pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)		pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);	if (tp->mac_version == RTL_GIGA_MAC_VER_02) {		dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");		RTL_W8(0x82, 0x01);		dprintk("Set PHY Reg 0x0bh = 0x00h\n");		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0	}	rtl8169_phy_reset(dev, tp);	/*	 * rtl8169_set_speed_xmii takes good care of the Fast Ethernet	 * only 8101. Don't panic.	 */	rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);	if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))		printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);}static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr){	void __iomem *ioaddr = tp->mmio_addr;	u32 high;	u32 low;	low  = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);	high = addr[4] | (addr[5] << 8);	spin_lock_irq(&tp->lock);	RTL_W8(Cfg9346, Cfg9346_Unlock);	RTL_W32(MAC0, low);	RTL_W32(MAC4, high);	RTL_W8(Cfg9346, Cfg9346_Lock);	spin_unlock_irq(&tp->lock);}static int rtl_set_mac_address(struct net_device *dev, void *p){	struct rtl8169_private *tp = netdev_priv(dev);	struct sockaddr *addr = p;	if (!is_valid_ether_addr(addr->sa_data))		return -EADDRNOTAVAIL;	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);	rtl_rar_set(tp, dev->dev_addr);	return 0;}static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	struct rtl8169_private *tp = netdev_priv(dev);	struct mii_ioctl_data *data = if_mii(ifr);	if (!netif_running(dev))		return -ENODEV;	switch (cmd) {	case SIOCGMIIPHY:		data->phy_id = 32; /* Internal PHY */		return 0;	case SIOCGMIIREG:		data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f);		return 0;	case SIOCSMIIREG:		if (!capable(CAP_NET_ADMIN))			return -EPERM;		mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in);		return 0;	}	return -EOPNOTSUPP;}static const struct rtl_cfg_info {	void (*hw_start)(struct net_device *);	unsigned int region;	unsigned int align;	u16 intr_event;	u16 napi_event;	unsigned msi;} rtl_cfg_infos [] = {	[RTL_CFG_0] = {		.hw_start	= rtl_hw_start_8169,		.region		= 1,		.align		= 0,		.intr_event	= SYSErr | LinkChg | RxOverflow |				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,

⌨️ 快捷键说明

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