📄 r8168_n.c
字号:
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 + -