|
@@ -370,8 +370,9 @@ struct ring_info {
|
|
|
};
|
|
|
|
|
|
enum features {
|
|
|
- RTL_FEATURE_WOL = (1 << 0),
|
|
|
- RTL_FEATURE_MSI = (1 << 1),
|
|
|
+ RTL_FEATURE_WOL = (1 << 0),
|
|
|
+ RTL_FEATURE_MSI = (1 << 1),
|
|
|
+ RTL_FEATURE_GMII = (1 << 2),
|
|
|
};
|
|
|
|
|
|
struct rtl8169_private {
|
|
@@ -406,13 +407,15 @@ struct rtl8169_private {
|
|
|
struct vlan_group *vlgrp;
|
|
|
#endif
|
|
|
int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
|
|
|
- void (*get_settings)(struct net_device *, struct ethtool_cmd *);
|
|
|
+ int (*get_settings)(struct net_device *, struct ethtool_cmd *);
|
|
|
void (*phy_reset_enable)(void __iomem *);
|
|
|
void (*hw_start)(struct net_device *);
|
|
|
unsigned int (*phy_reset_pending)(void __iomem *);
|
|
|
unsigned int (*link_ok)(void __iomem *);
|
|
|
struct delayed_work task;
|
|
|
unsigned features;
|
|
|
+
|
|
|
+ struct mii_if_info mii;
|
|
|
};
|
|
|
|
|
|
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
|
|
@@ -482,6 +485,23 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
+static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
|
|
|
+ int val)
|
|
|
+{
|
|
|
+ struct rtl8169_private *tp = netdev_priv(dev);
|
|
|
+ void __iomem *ioaddr = tp->mmio_addr;
|
|
|
+
|
|
|
+ mdio_write(ioaddr, location, val);
|
|
|
+}
|
|
|
+
|
|
|
+static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
|
|
|
+{
|
|
|
+ struct rtl8169_private *tp = netdev_priv(dev);
|
|
|
+ void __iomem *ioaddr = tp->mmio_addr;
|
|
|
+
|
|
|
+ return mdio_read(ioaddr, location);
|
|
|
+}
|
|
|
+
|
|
|
static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr)
|
|
|
{
|
|
|
RTL_W16(IntrMask, 0x0000);
|
|
@@ -850,7 +870,7 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
|
|
|
|
|
|
#endif
|
|
|
|
|
|
-static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
|
+static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
|
{
|
|
|
struct rtl8169_private *tp = netdev_priv(dev);
|
|
|
void __iomem *ioaddr = tp->mmio_addr;
|
|
@@ -867,65 +887,29 @@ static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
|
|
|
|
cmd->speed = SPEED_1000;
|
|
|
cmd->duplex = DUPLEX_FULL; /* Always set */
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
|
+static int 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;
|
|
|
+
|
|
|
+ return mii_ethtool_gset(&tp->mii, cmd);
|
|
|
}
|
|
|
|
|
|
static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
|
{
|
|
|
struct rtl8169_private *tp = netdev_priv(dev);
|
|
|
unsigned long flags;
|
|
|
+ int rc;
|
|
|
|
|
|
spin_lock_irqsave(&tp->lock, flags);
|
|
|
|
|
|
- tp->get_settings(dev, cmd);
|
|
|
+ rc = tp->get_settings(dev, cmd);
|
|
|
|
|
|
spin_unlock_irqrestore(&tp->lock, flags);
|
|
|
- return 0;
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
|
|
@@ -1513,7 +1497,7 @@ static const struct rtl_cfg_info {
|
|
|
unsigned int align;
|
|
|
u16 intr_event;
|
|
|
u16 napi_event;
|
|
|
- unsigned msi;
|
|
|
+ unsigned features;
|
|
|
} rtl_cfg_infos [] = {
|
|
|
[RTL_CFG_0] = {
|
|
|
.hw_start = rtl_hw_start_8169,
|
|
@@ -1522,7 +1506,7 @@ static const struct rtl_cfg_info {
|
|
|
.intr_event = SYSErr | LinkChg | RxOverflow |
|
|
|
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
|
|
|
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
|
|
|
- .msi = 0
|
|
|
+ .features = RTL_FEATURE_GMII
|
|
|
},
|
|
|
[RTL_CFG_1] = {
|
|
|
.hw_start = rtl_hw_start_8168,
|
|
@@ -1531,7 +1515,7 @@ static const struct rtl_cfg_info {
|
|
|
.intr_event = SYSErr | LinkChg | RxOverflow |
|
|
|
TxErr | TxOK | RxOK | RxErr,
|
|
|
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
|
|
|
- .msi = RTL_FEATURE_MSI
|
|
|
+ .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI
|
|
|
},
|
|
|
[RTL_CFG_2] = {
|
|
|
.hw_start = rtl_hw_start_8101,
|
|
@@ -1540,7 +1524,7 @@ static const struct rtl_cfg_info {
|
|
|
.intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
|
|
|
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
|
|
|
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
|
|
|
- .msi = RTL_FEATURE_MSI
|
|
|
+ .features = RTL_FEATURE_MSI
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -1552,7 +1536,7 @@ static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr,
|
|
|
u8 cfg2;
|
|
|
|
|
|
cfg2 = RTL_R8(Config2) & ~MSIEnable;
|
|
|
- if (cfg->msi) {
|
|
|
+ if (cfg->features & RTL_FEATURE_MSI) {
|
|
|
if (pci_enable_msi(pdev)) {
|
|
|
dev_info(&pdev->dev, "no MSI. Back to INTx.\n");
|
|
|
} else {
|
|
@@ -1578,6 +1562,7 @@ rtl8169_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 mii_if_info *mii;
|
|
|
struct net_device *dev;
|
|
|
void __iomem *ioaddr;
|
|
|
unsigned int i;
|
|
@@ -1602,6 +1587,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
tp->pci_dev = pdev;
|
|
|
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
|
|
|
|
|
|
+ mii = &tp->mii;
|
|
|
+ mii->dev = dev;
|
|
|
+ mii->mdio_read = rtl_mdio_read;
|
|
|
+ mii->mdio_write = rtl_mdio_write;
|
|
|
+ mii->phy_id_mask = 0x1f;
|
|
|
+ mii->reg_num_mask = 0x1f;
|
|
|
+ mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
|
|
|
+
|
|
|
/* enable device (incl. PCI PM wakeup and hotplug setup) */
|
|
|
rc = pci_enable_device(pdev);
|
|
|
if (rc < 0) {
|