[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8d117cab-2221-2cc4-ff0a-891f4a60dc92@gmail.com>
Date: Thu, 21 Dec 2017 21:50:25 +0100
From: Heiner Kallweit <hkallweit1@...il.com>
To: Andrew Lunn <andrew@...n.ch>,
Realtek linux nic maintainers <nic_swsd@...ltek.com>,
Chun-Hao Lin <hau@...ltek.com>
Cc: David Miller <davem@...emloft.net>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>
Subject: [PATCH RFC 08/18] r8168: add basic phylib support
All PHY's of the supported chips are MII-compatible, therefore let
phylib do the work.
Signed-off-by: Heiner Kallweit <hkallweit1@...il.com>
---
drivers/net/ethernet/realtek/Kconfig | 1 +
drivers/net/ethernet/realtek/r8168.c | 152 +++++++++++++++++++++++++++--------
2 files changed, 120 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index 011b524c5..97b24103e 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -99,6 +99,7 @@ config R8168
depends on PCI
select FW_LOADER
select CRC32
+ select PHYLIB
select MII
---help---
Say Y here if you have a Realtek 8168 PCI Gigabit Ethernet adapter.
diff --git a/drivers/net/ethernet/realtek/r8168.c b/drivers/net/ethernet/realtek/r8168.c
index b0c4b5ea8..be6c45b11 100644
--- a/drivers/net/ethernet/realtek/r8168.c
+++ b/drivers/net/ethernet/realtek/r8168.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <linux/if_vlan.h>
#include <linux/crc32.h>
#include <linux/in.h>
@@ -818,6 +819,7 @@ struct rtl8168_private {
unsigned features;
struct mii_if_info mii;
+ struct mii_bus *mii_bus;
dma_addr_t counters_phys_addr;
struct rtl8168_counters *counters;
struct rtl8168_tc_offsets tc_offset;
@@ -1632,33 +1634,6 @@ static void rtl_link_chg_patch(struct rtl8168_private *tp)
}
}
-static void __rtl8168_check_link_status(struct net_device *dev,
- struct rtl8168_private *tp,
- void __iomem *ioaddr, bool pm)
-{
- if (rtl8168_xmii_link_ok(ioaddr)) {
- rtl_link_chg_patch(tp);
- /* This is to cancel a scheduled suspend if there's one. */
- if (pm)
- pm_request_resume(&tp->pci_dev->dev);
- netif_carrier_on(dev);
- if (net_ratelimit())
- netif_info(tp, ifup, dev, "link up\n");
- } else {
- netif_carrier_off(dev);
- netif_info(tp, ifdown, dev, "link down\n");
- if (pm)
- pm_schedule_suspend(&tp->pci_dev->dev, 5000);
- }
-}
-
-static void rtl8168_check_link_status(struct net_device *dev,
- struct rtl8168_private *tp,
- void __iomem *ioaddr)
-{
- __rtl8168_check_link_status(dev, tp, ioaddr, false);
-}
-
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
static u32 __rtl8168_get_wol(struct rtl8168_private *tp)
@@ -6694,8 +6669,8 @@ static void rtl_reset_work(struct rtl8168_private *tp)
napi_enable(&tp->napi);
rtl_hw_start(dev);
+ phy_start(dev->phydev);
netif_wake_queue(dev);
- rtl8168_check_link_status(dev, tp, tp->mmio_addr);
}
static void rtl8168_tx_timeout(struct net_device *dev)
@@ -7329,7 +7304,7 @@ static void rtl_slow_event_work(struct rtl8168_private *tp)
rtl8168_pcierr_interrupt(dev);
if (status & LinkChg)
- __rtl8168_check_link_status(dev, tp, tp->mmio_addr, true);
+ phy_mac_interrupt(dev->phydev, netif_carrier_ok(dev));
rtl_irq_enable_all(tp);
}
@@ -7405,6 +7380,8 @@ static void rtl8168_down(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
+ phy_stop(dev->phydev);
+
del_timer_sync(&tp->timer);
napi_disable(&tp->napi);
@@ -7466,7 +7443,6 @@ static void rtl8168_netpoll(struct net_device *dev)
static int rtl_open(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
int retval = -ENOMEM;
@@ -7519,14 +7495,14 @@ static int rtl_open(struct net_device *dev)
if (!rtl8168_init_counter_offsets(dev))
netif_warn(tp, hw, dev, "counter reset/update failed\n");
+ phy_start(dev->phydev);
+
netif_start_queue(dev);
rtl_unlock_work(tp);
tp->saved_wolopts = 0;
pm_runtime_put_noidle(&pdev->dev);
-
- rtl8168_check_link_status(dev, tp, ioaddr);
out:
return retval;
@@ -7605,6 +7581,8 @@ static void rtl8168_net_suspend(struct net_device *dev)
if (!netif_running(dev))
return;
+ phy_stop(dev->phydev);
+
netif_device_detach(dev);
netif_stop_queue(dev);
@@ -7796,7 +7774,10 @@ static void rtl_remove_one(struct pci_dev *pdev)
netif_napi_del(&tp->napi);
+ phy_disconnect(dev->phydev);
+
unregister_netdev(dev);
+ mdiobus_unregister(tp->mii_bus);
rtl_release_firmware(tp);
@@ -7899,6 +7880,97 @@ DECLARE_RTL_COND(rtl_rxtx_empty_cond)
return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
}
+static int r8168_mdio_read_reg(struct mii_bus *mii_bus, int phyaddr, int phyreg)
+{
+ struct rtl8168_private *tp = mii_bus->priv;
+
+ return tp->mdio_ops.read(tp, phyreg);
+}
+
+static int r8168_mdio_write_reg(struct mii_bus *mii_bus, int phyaddr,
+ int phyreg, u16 val)
+{
+ struct rtl8168_private *tp = mii_bus->priv;
+
+ tp->mdio_ops.write(tp, phyreg, val);
+
+ return 0;
+}
+
+static int r8168_mdio_register(struct rtl8168_private *tp)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ struct mii_bus *new_bus;
+ int ret;
+
+ new_bus = devm_mdiobus_alloc(&pdev->dev);
+ if (!new_bus)
+ return -ENOMEM;
+
+ new_bus->name = "r8168";
+ new_bus->priv = tp;
+ new_bus->phy_mask = ~1;
+ new_bus->parent = &pdev->dev;
+ new_bus->irq[0] = PHY_IGNORE_INTERRUPT;
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%02x:%02x.%x",
+ new_bus->name, pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+ new_bus->read = r8168_mdio_read_reg;
+ new_bus->write = r8168_mdio_write_reg;
+
+ ret = mdiobus_register(new_bus);
+ if (!ret)
+ tp->mii_bus = new_bus;
+
+ return ret;
+}
+
+static void r8168_phylink_handler(struct net_device *ndev)
+{
+ struct rtl8168_private *tp = netdev_priv(ndev);
+
+ if (netif_carrier_ok(ndev)) {
+ rtl_link_chg_patch(tp);
+ pm_request_resume(&tp->pci_dev->dev);
+ } else {
+ pm_schedule_suspend(&tp->pci_dev->dev, 5000);
+ }
+
+ if (net_ratelimit())
+ phy_print_status(ndev->phydev);
+}
+
+static int r8168_phy_connect(struct rtl8168_private *tp)
+{
+ struct phy_device *phydev;
+ phy_interface_t phy_mode;
+ int ret;
+
+ phy_mode = tp->mii.supports_gmii ? PHY_INTERFACE_MODE_GMII :
+ PHY_INTERFACE_MODE_MII;
+
+ phydev = phy_find_first(tp->mii_bus);
+ if (!phydev)
+ return -ENODEV;
+
+ ret = phy_connect_direct(tp->dev, phydev, r8168_phylink_handler,
+ phy_mode);
+ if (ret)
+ return ret;
+
+ phy_attached_info(phydev);
+
+ if (!tp->mii.supports_gmii && (phydev->supported &
+ (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full))) {
+ netif_info(tp, probe, tp->dev, "Restrict PHY to 100Mbit because MAC doesn't support 1GBit");
+ phy_set_max_speed(phydev, SPEED_100);
+ ret = genphy_restart_aneg(phydev);
+ }
+
+ return ret;
+}
+
static void rtl_hw_init_8168g(struct rtl8168_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -8212,10 +8284,18 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!tp->counters)
return -ENOMEM;
- rc = register_netdev(dev);
+ rc = r8168_mdio_register(tp);
if (rc < 0)
return rc;
+ rc = register_netdev(dev);
+ if (rc < 0)
+ goto err_mdio_unregister;
+
+ rc = r8168_phy_connect(tp);
+ if (rc < 0)
+ goto err_netdev_unregister;
+
pci_set_drvdata(pdev, dev);
netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
@@ -8244,6 +8324,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netif_carrier_off(dev);
return 0;
+
+err_netdev_unregister:
+ unregister_netdev(dev);
+err_mdio_unregister:
+ mdiobus_unregister(tp->mii_bus);
+ return rc;
}
static struct pci_driver rtl8168_pci_driver = {
--
2.15.1
Powered by blists - more mailing lists