diff options
Diffstat (limited to 'target/linux/imx6/patches-4.3/204-net-igb-register-mii_bus-for-SerDes-w-external-phy.patch')
-rw-r--r-- | target/linux/imx6/patches-4.3/204-net-igb-register-mii_bus-for-SerDes-w-external-phy.patch | 308 |
1 files changed, 0 insertions, 308 deletions
diff --git a/target/linux/imx6/patches-4.3/204-net-igb-register-mii_bus-for-SerDes-w-external-phy.patch b/target/linux/imx6/patches-4.3/204-net-igb-register-mii_bus-for-SerDes-w-external-phy.patch deleted file mode 100644 index b73895b..0000000 --- a/target/linux/imx6/patches-4.3/204-net-igb-register-mii_bus-for-SerDes-w-external-phy.patch +++ /dev/null @@ -1,308 +0,0 @@ -From 03855caf93f7332a3f320228ba1a0e7baae8a749 Mon Sep 17 00:00:00 2001 -From: Tim Harvey <tharvey@gateworks.com> -Date: Thu, 15 May 2014 12:36:23 -0700 -Subject: [PATCH] net: igb: register mii_bus for SerDes w/ external phy - -If an i210 is configured for 1000BASE-BX link_mode and has an external phy -specified, then register an mii bus using the external phy address as -a mask. - -An i210 hooked to an external standard phy will be configured with a link_mo -of SGMII in which case phy ops will be configured and used internall in the -igb driver for link status. However, in certain cases one might be using a -backplane SerDes connection to something that talks on the mdio bus but is -not a standard phy, such as a switch. In this case by registering an mdio -bus a phy driver can manage the device. - -Signed-off-by: Tim Harvey <tharvey@gateworks.com> ---- - drivers/net/ethernet/intel/igb/e1000_82575.c | 15 +++ - drivers/net/ethernet/intel/igb/e1000_hw.h | 7 ++ - drivers/net/ethernet/intel/igb/igb_main.c | 168 ++++++++++++++++++++++++++- - 3 files changed, 185 insertions(+), 5 deletions(-) - ---- a/drivers/net/ethernet/intel/igb/e1000_82575.c -+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c -@@ -612,13 +612,25 @@ static s32 igb_get_invariants_82575(stru - switch (link_mode) { - case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: - hw->phy.media_type = e1000_media_type_internal_serdes; -+ if (igb_sgmii_uses_mdio_82575(hw)) { -+ u32 mdicnfg = rd32(E1000_MDICNFG); -+ mdicnfg &= E1000_MDICNFG_PHY_MASK; -+ hw->phy.addr = mdicnfg >> E1000_MDICNFG_PHY_SHIFT; -+ hw_dbg("1000BASE_KX w/ external MDIO device at 0x%x\n", -+ hw->phy.addr); -+ } else { -+ hw_dbg("1000BASE_KX"); -+ } - break; - case E1000_CTRL_EXT_LINK_MODE_SGMII: - /* Get phy control interface type set (MDIO vs. I2C)*/ - if (igb_sgmii_uses_mdio_82575(hw)) { - hw->phy.media_type = e1000_media_type_copper; - dev_spec->sgmii_active = true; -+ hw_dbg("SGMII with external MDIO PHY"); - break; -+ } else { -+ hw_dbg("SGMII with external I2C PHY"); - } - /* fall through for I2C based SGMII */ - case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: -@@ -635,8 +647,11 @@ static s32 igb_get_invariants_82575(stru - hw->phy.media_type = e1000_media_type_copper; - dev_spec->sgmii_active = true; - } -+ hw_dbg("SERDES with external SFP"); - - break; -+ } else { -+ hw_dbg("SERDES"); - } - - /* do not change link mode for 100BaseFX */ ---- a/drivers/net/ethernet/intel/igb/e1000_hw.h -+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h -@@ -27,6 +27,7 @@ - #include <linux/delay.h> - #include <linux/io.h> - #include <linux/netdevice.h> -+#include <linux/phy.h> - - #include "e1000_regs.h" - #include "e1000_defines.h" -@@ -543,6 +544,12 @@ struct e1000_hw { - struct e1000_mbx_info mbx; - struct e1000_host_mng_dhcp_cookie mng_cookie; - -+#ifdef CONFIG_PHYLIB -+ /* Phylib and MDIO interface */ -+ struct mii_bus *mii_bus; -+ struct phy_device *phy_dev; -+ phy_interface_t phy_interface; -+#endif - union { - struct e1000_dev_spec_82575 _82575; - } dev_spec; ---- a/drivers/net/ethernet/intel/igb/igb_main.c -+++ b/drivers/net/ethernet/intel/igb/igb_main.c -@@ -41,6 +41,7 @@ - #include <linux/if_vlan.h> - #include <linux/pci.h> - #include <linux/pci-aspm.h> -+#include <linux/phy.h> - #include <linux/delay.h> - #include <linux/interrupt.h> - #include <linux/ip.h> -@@ -2223,6 +2224,126 @@ static s32 igb_init_i2c(struct igb_adapt - return status; - } - -+ -+#ifdef CONFIG_PHYLIB -+/* -+ * MMIO/PHYdev support -+ */ -+ -+static int igb_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -+{ -+ struct e1000_hw *hw = bus->priv; -+ u16 out; -+ int err; -+ -+ err = igb_read_reg_gs40g(hw, mii_id, regnum, &out); -+ if (err) -+ return err; -+ return out; -+} -+ -+static int igb_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, -+ u16 val) -+{ -+ struct e1000_hw *hw = bus->priv; -+ -+ return igb_write_reg_gs40g(hw, mii_id, regnum, val); -+} -+ -+static int igb_enet_mdio_reset(struct mii_bus *bus) -+{ -+ udelay(300); -+ return 0; -+} -+ -+static void igb_enet_mii_link(struct net_device *netdev) -+{ -+} -+ -+/* Probe the mdio bus for phys and connect them */ -+static int igb_enet_mii_probe(struct net_device *netdev) -+{ -+ struct igb_adapter *adapter = netdev_priv(netdev); -+ struct e1000_hw *hw = &adapter->hw; -+ struct phy_device *phy_dev = NULL; -+ int phy_id; -+ -+ /* check for attached phy */ -+ for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) { -+ if (hw->mii_bus->phy_map[phy_id]) { -+ phy_dev = hw->mii_bus->phy_map[phy_id]; -+ break; -+ } -+ } -+ if (!phy_dev) { -+ netdev_err(netdev, "no PHY found\n"); -+ return -ENODEV; -+ } -+ -+ hw->phy_interface = PHY_INTERFACE_MODE_RGMII; -+ phy_dev = phy_connect(netdev, dev_name(&phy_dev->dev), -+ igb_enet_mii_link, hw->phy_interface); -+ if (IS_ERR(phy_dev)) { -+ netdev_err(netdev, "could not attach to PHY\n"); -+ return PTR_ERR(phy_dev); -+ } -+ -+ hw->phy_dev = phy_dev; -+ netdev_info(netdev, "igb PHY driver [%s] (mii_bus:phy_addr=%s)\n", -+ hw->phy_dev->drv->name, dev_name(&hw->phy_dev->dev)); -+ -+ return 0; -+} -+ -+/* Create and register mdio bus */ -+static int igb_enet_mii_init(struct pci_dev *pdev) -+{ -+ struct mii_bus *mii_bus; -+ struct net_device *netdev = pci_get_drvdata(pdev); -+ struct igb_adapter *adapter = netdev_priv(netdev); -+ struct e1000_hw *hw = &adapter->hw; -+ int err; -+ -+ mii_bus = mdiobus_alloc(); -+ if (mii_bus == NULL) { -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ mii_bus->name = "igb_enet_mii_bus"; -+ mii_bus->read = igb_enet_mdio_read; -+ mii_bus->write = igb_enet_mdio_write; -+ mii_bus->reset = igb_enet_mdio_reset; -+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", -+ pci_name(pdev), hw->device_id + 1); -+ mii_bus->priv = hw; -+ mii_bus->parent = &pdev->dev; -+ mii_bus->phy_mask = ~(1 << hw->phy.addr); -+ -+ err = mdiobus_register(mii_bus); -+ if (err) { -+ printk(KERN_ERR "failed to register mii_bus: %d\n", err); -+ goto err_out_free_mdiobus; -+ } -+ hw->mii_bus = mii_bus; -+ -+ return 0; -+ -+err_out_free_mdiobus: -+ mdiobus_free(mii_bus); -+err_out: -+ return err; -+} -+ -+static void igb_enet_mii_remove(struct e1000_hw *hw) -+{ -+ if (hw->mii_bus) { -+ mdiobus_unregister(hw->mii_bus); -+ mdiobus_free(hw->mii_bus); -+ } -+} -+#endif /* CONFIG_PHYLIB */ -+ - /** - * igb_probe - Device Initialization Routine - * @pdev: PCI device information struct -@@ -2645,6 +2766,13 @@ static int igb_probe(struct pci_dev *pde - } - } - pm_runtime_put_noidle(&pdev->dev); -+ -+#ifdef CONFIG_PHYLIB -+ /* create and register the mdio bus if using ext phy */ -+ if (rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO) -+ igb_enet_mii_init(pdev); -+#endif -+ - return 0; - - err_register: -@@ -2792,6 +2920,10 @@ static void igb_remove(struct pci_dev *p - struct e1000_hw *hw = &adapter->hw; - - pm_runtime_get_noresume(&pdev->dev); -+#ifdef CONFIG_PHYLIB -+ if (rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO) -+ igb_enet_mii_remove(hw); -+#endif - #ifdef CONFIG_IGB_HWMON - igb_sysfs_exit(adapter); - #endif -@@ -3105,6 +3237,12 @@ static int __igb_open(struct net_device - if (!resuming) - pm_runtime_put(&pdev->dev); - -+#ifdef CONFIG_PHYLIB -+ /* Probe and connect to PHY if using ext phy */ -+ if (rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO) -+ igb_enet_mii_probe(netdev); -+#endif -+ - /* start the watchdog. */ - hw->mac.get_link_status = 1; - schedule_work(&adapter->watchdog_task); -@@ -7090,21 +7228,41 @@ void igb_alloc_rx_buffers(struct igb_rin - static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) - { - struct igb_adapter *adapter = netdev_priv(netdev); -+ struct e1000_hw *hw = &adapter->hw; - struct mii_ioctl_data *data = if_mii(ifr); - -- if (adapter->hw.phy.media_type != e1000_media_type_copper) -+ if (adapter->hw.phy.media_type != e1000_media_type_copper && -+ !(rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO)) - return -EOPNOTSUPP; - - switch (cmd) { - case SIOCGMIIPHY: -- data->phy_id = adapter->hw.phy.addr; -+ data->phy_id = hw->phy.addr; - break; - case SIOCGMIIREG: -- if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, -- &data->val_out)) -- return -EIO; -+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) { -+ if (igb_read_reg_gs40g(&adapter->hw, data->phy_id, -+ data->reg_num & 0x1F, -+ &data->val_out)) -+ return -EIO; -+ } else { -+ if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, -+ &data->val_out)) -+ return -EIO; -+ } - break; - case SIOCSMIIREG: -+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) { -+ if (igb_write_reg_gs40g(hw, data->phy_id, -+ data->reg_num & 0x1F, -+ data->val_in)) -+ return -EIO; -+ } else { -+ if (igb_write_phy_reg(hw, data->reg_num & 0x1F, -+ data->val_in)) -+ return -EIO; -+ } -+ break; - default: - return -EOPNOTSUPP; - } |