📄 r8169.c
字号:
RTL_W8(ChipCmd, 0x00); rtl8169_irq_mask_and_ack(ioaddr); RTL_R16(CPlusCmd);}static unsigned int rtl8169_tbi_reset_pending(void __iomem *ioaddr){ return RTL_R32(TBICSR) & TBIReset;}static unsigned int rtl8169_xmii_reset_pending(void __iomem *ioaddr){ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;}static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr){ return RTL_R32(TBICSR) & TBILinkOk;}static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr){ return RTL_R8(PHYstatus) & LinkStatus;}static void rtl8169_tbi_reset_enable(void __iomem *ioaddr){ RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);}static void rtl8169_xmii_reset_enable(void __iomem *ioaddr){ unsigned int val; val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET; mdio_write(ioaddr, MII_BMCR, val & 0xffff);}static void rtl8169_check_link_status(struct net_device *dev, struct rtl8169_private *tp, void __iomem *ioaddr){ unsigned long flags; spin_lock_irqsave(&tp->lock, flags); if (tp->link_ok(ioaddr)) { 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 rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ struct rtl8169_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 rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; unsigned 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); if (wol->wolopts) tp->features |= RTL_FEATURE_WOL; else tp->features &= ~RTL_FEATURE_WOL; spin_unlock_irq(&tp->lock); return 0;}static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct rtl8169_private *tp = netdev_priv(dev); strcpy(info->driver, MODULENAME); strcpy(info->version, RTL8169_VERSION); strcpy(info->bus_info, pci_name(tp->pci_dev));}static int rtl8169_get_regs_len(struct net_device *dev){ return R8169_REGS_SIZE;}static int rtl8169_set_speed_tbi(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; int ret = 0; u32 reg; reg = RTL_R32(TBICSR); if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && (duplex == DUPLEX_FULL)) { RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); } else if (autoneg == AUTONEG_ENABLE) RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); else { if (netif_msg_link(tp)) { printk(KERN_WARNING "%s: " "incorrect speed setting refused in TBI mode\n", dev->name); } ret = -EOPNOTSUPP; } return ret;}static int rtl8169_set_speed_xmii(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; int auto_nego, giga_ctrl; auto_nego = mdio_read(ioaddr, MII_ADVERTISE); auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL); giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); if (autoneg == AUTONEG_ENABLE) { auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL); giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; } else { if (speed == SPEED_10) auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; else if (speed == SPEED_100) auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; else if (speed == SPEED_1000) giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; if (duplex == DUPLEX_HALF) auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); if (duplex == DUPLEX_FULL) auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); /* This tweak comes straight from Realtek's driver. */ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && ((tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_16))) { auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; } } /* The 8100e/8101e do Fast Ethernet only. */ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_14) || (tp->mac_version == RTL_GIGA_MAC_VER_15) || (tp->mac_version == RTL_GIGA_MAC_VER_16)) { if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) && netif_msg_link(tp)) { printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n", dev->name); } giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); } auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if ((tp->mac_version == RTL_GIGA_MAC_VER_12) || (tp->mac_version == RTL_GIGA_MAC_VER_17)) { /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */ mdio_write(ioaddr, 0x1f, 0x0000); mdio_write(ioaddr, 0x0e, 0x0000); } tp->phy_auto_nego_reg = auto_nego; tp->phy_1000_ctrl_reg = giga_ctrl; mdio_write(ioaddr, MII_ADVERTISE, auto_nego); mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); return 0;}static int rtl8169_set_speed(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex){ struct rtl8169_private *tp = netdev_priv(dev); int ret; ret = tp->set_speed(dev, autoneg, speed, duplex); if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); return ret;}static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); unsigned long flags; int ret; spin_lock_irqsave(&tp->lock, flags); ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex); spin_unlock_irqrestore(&tp->lock, flags); return ret;}static u32 rtl8169_get_rx_csum(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); return tp->cp_cmd & RxChkSum;}static int rtl8169_set_rx_csum(struct net_device *dev, u32 data){ struct rtl8169_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); RTL_R16(CPlusCmd); spin_unlock_irqrestore(&tp->lock, flags); return 0;}#ifdef CONFIG_R8169_VLANstatic inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, struct sk_buff *skb){ return (tp->vlgrp && vlan_tx_tag_present(skb)) ? TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;}static void rtl8169_vlan_rx_register(struct net_device *dev, struct vlan_group *grp){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; unsigned long flags; spin_lock_irqsave(&tp->lock, flags); tp->vlgrp = grp; if (tp->vlgrp) tp->cp_cmd |= RxVlan; else tp->cp_cmd &= ~RxVlan; RTL_W16(CPlusCmd, tp->cp_cmd); RTL_R16(CPlusCmd); spin_unlock_irqrestore(&tp->lock, flags);}static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, struct sk_buff *skb){ u32 opts2 = le32_to_cpu(desc->opts2); int ret; if (tp->vlgrp && (opts2 & RxVlanTag)) { rtl8169_rx_hwaccel_skb(skb, tp->vlgrp, swab16(opts2 & 0xffff)); ret = 0; } else ret = -1; desc->opts2 = 0; return ret;}#else /* !CONFIG_R8169_VLAN */static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, struct sk_buff *skb){ return 0;}static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc, struct sk_buff *skb){ return -1;}#endifstatic void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; u32 status; cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE; cmd->port = PORT_FIBRE; cmd->transceiver = XCVR_INTERNAL; status = RTL_R32(TBICSR); cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; cmd->autoneg = !!(status & TBINwEnable); cmd->speed = SPEED_1000; cmd->duplex = DUPLEX_FULL; /* Always set */}static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; u8 status; cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP; cmd->autoneg = 1; cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; if (tp->phy_auto_nego_reg & ADVERTISE_10HALF) cmd->advertising |= ADVERTISED_10baseT_Half; if (tp->phy_auto_nego_reg & ADVERTISE_10FULL) cmd->advertising |= ADVERTISED_10baseT_Full; if (tp->phy_auto_nego_reg & ADVERTISE_100HALF) cmd->advertising |= ADVERTISED_100baseT_Half; if (tp->phy_auto_nego_reg & ADVERTISE_100FULL) cmd->advertising |= ADVERTISED_100baseT_Full; if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL) cmd->advertising |= ADVERTISED_1000baseT_Full; status = RTL_R8(PHYstatus); if (status & _1000bpsF) cmd->speed = SPEED_1000; else if (status & _100bps) cmd->speed = SPEED_100; else if (status & _10bps) cmd->speed = SPEED_10; if (status & TxFlowCtrl) cmd->advertising |= ADVERTISED_Asym_Pause; if (status & RxFlowCtrl) cmd->advertising |= ADVERTISED_Pause; cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? DUPLEX_FULL : DUPLEX_HALF;}static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&tp->lock, flags); tp->get_settings(dev, cmd); spin_unlock_irqrestore(&tp->lock, flags); return 0;}static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p){ struct rtl8169_private *tp = netdev_priv(dev); unsigned long flags; if (regs->len > R8169_REGS_SIZE) regs->len = R8169_REGS_SIZE; spin_lock_irqsave(&tp->lock, flags); memcpy_fromio(p, tp->mmio_addr, regs->len); spin_unlock_irqrestore(&tp->lock, flags);}static u32 rtl8169_get_msglevel(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); return tp->msg_enable;}static void rtl8169_set_msglevel(struct net_device *dev, u32 value){ struct rtl8169_private *tp = netdev_priv(dev); tp->msg_enable = value;}static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { "tx_packets", "rx_packets", "tx_errors", "rx_errors", "rx_missed", "align_errors", "tx_single_collisions", "tx_multi_collisions", "unicast", "broadcast", "multicast", "tx_aborted", "tx_underrun",};struct rtl8169_counters { __le64 tx_packets; __le64 rx_packets; __le64 tx_errors; __le32 rx_errors; __le16 rx_missed; __le16 align_errors; __le32 tx_one_collision; __le32 tx_multi_collision; __le64 rx_unicast; __le64 rx_broadcast; __le32 rx_multicast; __le16 tx_aborted; __le16 tx_underun;};static int rtl8169_get_sset_count(struct net_device *dev, int sset){ switch (sset) { case ETH_SS_STATS: return ARRAY_SIZE(rtl8169_gstrings); default: return -EOPNOTSUPP; }}static void rtl8169_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; struct rtl8169_counters *counters; dma_addr_t paddr; u32 cmd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -