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

📄 r8168_n.c

📁 RT8111/R8168 PCI Express 的linux驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		CSIAR_Write |		CSIAR_ByteEn << CSIAR_ByteEn_shift |		(addr & CSIAR_Addr_Mask));	for (i = 0; i < 10; i++) {		udelay(100);		/* Check if the RTL8168 has completed CSI write */		if (!(RTL_R32(CSIAR) & CSIAR_Flag)) 			break;	}	udelay(20);}static int rtl8168_csi_read(void __iomem *ioaddr, 		 int addr){	int i, value = -1;	RTL_W32(CSIAR, 		CSIAR_Read | 		CSIAR_ByteEn << CSIAR_ByteEn_shift |		(addr & CSIAR_Addr_Mask));	for (i = 0; i < 10; i++) {		udelay(100);		/* Check if the RTL8168 has completed CSI read */		if (RTL_R32(CSIAR) & CSIAR_Flag) {			value = (int)RTL_R32(CSIDR);			break;		}	}	udelay(20);	return value;}static void rtl8168_irq_mask_and_ack(void __iomem *ioaddr){	RTL_W16(IntrMask, 0x0000);}static void rtl8168_asic_down(struct net_device *dev){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	rtl8168_nic_reset(dev);	rtl8168_irq_mask_and_ack(ioaddr);}static void rtl8168_nic_reset(struct net_device *dev){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	int i;	if ((tp->mcfg != CFG_METHOD_1) && 	    (tp->mcfg != CFG_METHOD_2) &&	    (tp->mcfg != CFG_METHOD_3)) {		RTL_W8(ChipCmd, StopReq | CmdRxEnb | CmdTxEnb);		udelay(100);	}	/* Soft reset the chip. */	RTL_W8(ChipCmd, CmdReset);	/* Check that the chip has finished the reset. */	for (i = 1000; i > 0; i--) {		if ((RTL_R8(ChipCmd) & CmdReset) == 0)			break;		udelay(100);	}}static unsigned int rtl8168_xmii_reset_pending(struct net_device *dev){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	unsigned long flags;	unsigned int retval;	spin_lock_irqsave(&tp->phy_lock, flags);	mdio_write(ioaddr, 0x1f, 0x0000);	retval = mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;	spin_unlock_irqrestore(&tp->phy_lock, flags);	return retval;}static unsigned int rtl8168_xmii_link_ok(struct net_device *dev){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	mdio_write(ioaddr, 0x1f, 0x0000);	return RTL_R8(PHYstatus) & LinkStatus;}static void rtl8168_xmii_reset_enable(struct net_device *dev){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	unsigned long flags;	int i;	spin_lock_irqsave(&tp->phy_lock, flags);	mdio_write(ioaddr, 0x1f, 0x0000);	mdio_write(ioaddr, MII_BMCR, mdio_read(ioaddr, MII_BMCR) | BMCR_RESET);	for(i = 0; i < 2500; i++) {		if(!(mdio_read(ioaddr, MII_BMSR) & BMCR_RESET))			return;		mdelay(1);	}	spin_unlock_irqrestore(&tp->phy_lock, flags);}static void rtl8168_check_link_status(struct net_device *dev,			  struct rtl8168_private *tp, 			  void __iomem *ioaddr){	unsigned long flags;	spin_lock_irqsave(&tp->lock, flags);	if (tp->link_ok(dev)) {		netif_carrier_on(dev);		if (netif_msg_ifup(tp))			printk(KERN_INFO PFX "%s: link up\n", dev->name);	} else {		if (netif_msg_ifdown(tp))			printk(KERN_INFO PFX "%s: link down\n", dev->name);		netif_carrier_off(dev);	}	spin_unlock_irqrestore(&tp->lock, flags);}static void rtl8168_link_option(int idx, 		    u8 *aut, 		    u16 *spd, 		    u8 *dup){	unsigned char opt_speed;	unsigned char opt_duplex;	unsigned char opt_autoneg;	opt_speed = ((idx < MAX_UNITS) && (idx >= 0)) ? speed[idx] : 0xff;	opt_duplex = ((idx < MAX_UNITS) && (idx >= 0)) ? duplex[idx] : 0xff;	opt_autoneg = ((idx < MAX_UNITS) && (idx >= 0)) ? autoneg[idx] : 0xff;	if ((opt_speed == 0xff) |	    (opt_duplex == 0xff) |	    (opt_autoneg == 0xff)) {		*spd = SPEED_1000;		*dup = DUPLEX_FULL;		*aut = AUTONEG_ENABLE;	} else {		*spd = speed[idx];		*dup = duplex[idx];		*aut = autoneg[idx];		}}static void rtl8168_get_wol(struct net_device *dev, 		struct ethtool_wolinfo *wol){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	u8 options;	wol->wolopts = 0;#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)	wol->supported = WAKE_ANY;	spin_lock_irq(&tp->lock);	options = RTL_R8(Config1);	if (!(options & PMEnable))		goto out_unlock;	options = RTL_R8(Config3);	if (options & LinkUp)		wol->wolopts |= WAKE_PHY;	if (options & MagicPacket)		wol->wolopts |= WAKE_MAGIC;	options = RTL_R8(Config5);	if (options & UWF)		wol->wolopts |= WAKE_UCAST;	if (options & BWF)	        wol->wolopts |= WAKE_BCAST;	if (options & MWF)	        wol->wolopts |= WAKE_MCAST;out_unlock:	spin_unlock_irq(&tp->lock);}static int rtl8168_set_wol(struct net_device *dev, 		struct ethtool_wolinfo *wol){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	int i;	static struct {		u32 opt;		u16 reg;		u8  mask;	} cfg[] = {		{ WAKE_ANY,   Config1, PMEnable },		{ WAKE_PHY,   Config3, LinkUp },		{ WAKE_MAGIC, Config3, MagicPacket },		{ WAKE_UCAST, Config5, UWF },		{ WAKE_BCAST, Config5, BWF },		{ WAKE_MCAST, Config5, MWF },		{ WAKE_ANY,   Config5, LanWake }	};	spin_lock_irq(&tp->lock);	RTL_W8(Cfg9346, Cfg9346_Unlock);	for (i = 0; i < ARRAY_SIZE(cfg); i++) {		u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;		if (wol->wolopts & cfg[i].opt)			options |= cfg[i].mask;		RTL_W8(cfg[i].reg, options);	}	RTL_W8(Cfg9346, Cfg9346_Lock);	tp->wol_enabled = (wol->wolopts) ? 1 : 0;	spin_unlock_irq(&tp->lock);	return 0;}static void rtl8168_get_drvinfo(struct net_device *dev,		    struct ethtool_drvinfo *info){	struct rtl8168_private *tp = netdev_priv(dev);	strcpy(info->driver, MODULENAME);	strcpy(info->version, RTL8168_VERSION);	strcpy(info->bus_info, pci_name(tp->pci_dev));}static int rtl8168_get_regs_len(struct net_device *dev){	return R8168_REGS_SIZE;}static int rtl8168_set_speed_xmii(struct net_device *dev,		       u8 autoneg, 		       u16 speed, 		       u8 duplex){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	int auto_nego = 0;	int giga_ctrl = 0;	int bmcr_true_force = 0;	unsigned long flags;	if ((speed != SPEED_1000) && 	    (speed != SPEED_100) && 	    (speed != SPEED_10)) {		speed = SPEED_1000;		duplex = DUPLEX_FULL;	}	if ((autoneg == AUTONEG_ENABLE) || (speed == SPEED_1000)) {		/*n-way force*/		if ((speed == SPEED_10) && (duplex == DUPLEX_HALF)) {			auto_nego |= ADVERTISE_10HALF;		} else if ((speed == SPEED_10) && (duplex == DUPLEX_FULL)) {			auto_nego |= ADVERTISE_10HALF |				     ADVERTISE_10FULL;		} else if ((speed == SPEED_100) && (duplex == DUPLEX_HALF)) {			auto_nego |= ADVERTISE_100HALF | 				     ADVERTISE_10HALF | 				     ADVERTISE_10FULL;		} else if ((speed == SPEED_100) && (duplex == DUPLEX_FULL)) {			auto_nego |= ADVERTISE_100HALF | 				     ADVERTISE_100FULL |				     ADVERTISE_10HALF | 				     ADVERTISE_10FULL;		} else if (speed == SPEED_1000) {			giga_ctrl |= ADVERTISE_1000HALF | 				     ADVERTISE_1000FULL;			auto_nego |= ADVERTISE_100HALF | 				     ADVERTISE_100FULL |				     ADVERTISE_10HALF | 				     ADVERTISE_10FULL;		}		//disable flow contorol		auto_nego &= ~ADVERTISE_PAUSE_CAP;		auto_nego &= ~ADVERTISE_PAUSE_ASYM;		tp->phy_auto_nego_reg = auto_nego;		tp->phy_1000_ctrl_reg = giga_ctrl;		tp->autoneg = autoneg;		tp->speed = speed; 		tp->duplex = duplex; 		rtl8168_phy_power_up (dev);		spin_lock_irqsave(&tp->phy_lock, flags);		mdio_write(ioaddr, 0x1f, 0x0000);		mdio_write(ioaddr, MII_ADVERTISE, auto_nego);		mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);		mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);		spin_unlock_irqrestore(&tp->phy_lock, flags);	} else {		/*true force*/#ifndef BMCR_SPEED100#define BMCR_SPEED100	0x0040#endif#ifndef BMCR_SPEED10#define BMCR_SPEED10	0x0000#endif		if ((speed == SPEED_10) && (duplex == DUPLEX_HALF)) {			bmcr_true_force = BMCR_SPEED10;		} else if ((speed == SPEED_10) && (duplex == DUPLEX_FULL)) {			bmcr_true_force = BMCR_SPEED10 | BMCR_FULLDPLX;		} else if ((speed == SPEED_100) && (duplex == DUPLEX_HALF)) {			bmcr_true_force = BMCR_SPEED100;		} else if ((speed == SPEED_100) && (duplex == DUPLEX_FULL)) {			bmcr_true_force = BMCR_SPEED100 | BMCR_FULLDPLX;		}		spin_lock_irqsave(&tp->phy_lock, flags);		mdio_write(ioaddr, 0x1f, 0x0000);		mdio_write(ioaddr, MII_BMCR, bmcr_true_force);		spin_unlock_irqrestore(&tp->phy_lock, flags);	}	return 0;}static int rtl8168_set_speed(struct net_device *dev,		  u8 autoneg, 		  u16 speed, 		  u8 duplex){	struct rtl8168_private *tp = netdev_priv(dev);	int ret;	ret = tp->set_speed(dev, autoneg, speed, duplex);	return ret;}static int rtl8168_set_settings(struct net_device *dev, 		     struct ethtool_cmd *cmd){	struct rtl8168_private *tp = netdev_priv(dev);	unsigned long flags;	int ret;	spin_lock_irqsave(&tp->lock, flags);	ret = rtl8168_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);	spin_unlock_irqrestore(&tp->lock, flags);		return ret;}static u32 rtl8168_get_tx_csum(struct net_device *dev){	return (dev->features & NETIF_F_IP_CSUM) != 0;}static u32 rtl8168_get_rx_csum(struct net_device *dev){	struct rtl8168_private *tp = netdev_priv(dev);	return tp->cp_cmd & RxChkSum;}static int rtl8168_set_tx_csum(struct net_device *dev, 		    u32 data){	if (data)		dev->features |= NETIF_F_IP_CSUM;	else		dev->features &= ~NETIF_F_IP_CSUM;	return 0;}static int rtl8168_set_rx_csum(struct net_device *dev, 		    u32 data){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	unsigned long flags;	spin_lock_irqsave(&tp->lock, flags);	if (data)		tp->cp_cmd |= RxChkSum;	else		tp->cp_cmd &= ~RxChkSum;	RTL_W16(CPlusCmd, tp->cp_cmd);	spin_unlock_irqrestore(&tp->lock, flags);	return 0;}#ifdef CONFIG_R8168_VLANstatic inline u32 rtl8168_tx_vlan_tag(struct rtl8168_private *tp,		    struct sk_buff *skb){	return (tp->vlgrp && vlan_tx_tag_present(skb)) ?		TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;}static void rtl8168_vlan_rx_register(struct net_device *dev,			 struct vlan_group *grp){	struct rtl8168_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	unsigned long flags;	spin_lock_irqsave(&tp->lock, flags);	tp->vlgrp = grp;	tp->cp_cmd &= ~RxVlan;	RTL_W16(CPlusCmd, tp->cp_cmd);	spin_unlock_irqrestore(&tp->lock, flags);}static void rtl8168_vlan_rx_kill_vid(struct net_device *dev, 			 unsigned short vid){	struct rtl8168_private *tp = netdev_priv(dev);	unsigned long flags;	spin_lock_irqsave(&tp->lock, flags);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)	if (tp->vlgrp)		tp->vlgrp->vlan_devices[vid] = NULL;#else	vlan_group_set_device(tp->vlgrp, vid, NULL);#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)	spin_unlock_irqrestore(&tp->lock, flags);}static int rtl8168_rx_vlan_skb(struct rtl8168_private *tp, 		    struct RxDesc *desc,		    struct sk_buff *skb){	int ret;	u16 vlan_sig = (*(skb->data + ETH_ALEN * 2) << 8) | (*(skb->data + ETH_ALEN * 2 + 1));	u16 rx_vlan = (*(skb->data + ETH_HLEN + 1) << 8) | (*(skb->data + ETH_HLEN));	unsigned char *tmp = skb->data;	struct net_device *dev = tp->dev;	if (tp->vlgrp && (vlan_sig == ETH_P_8021Q)) {		skb_pull(skb, 4);		memmove(skb->data, tmp, ETH_ALEN * 2);		skb->protocol = eth_type_trans(skb, dev);		rtl8168_rx_hwaccel_skb(skb, tp->vlgrp, swab16(rx_vlan));		ret = 0;	} else {		ret = -1;	}	desc->opts2 = 0;	return ret;}#else /* !CONFIG_R8168_VLAN */static inline u32 rtl8168_tx_vlan_tag(struct rtl8168_private *tp,		    struct sk_buff *skb){	return 0;}

⌨️ 快捷键说明

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