Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/982293/?format=api
{ "id": 982293, "url": "http://patchwork.ozlabs.org/api/patches/982293/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20181011071731.1952-1-sasha.neftin@intel.com/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20181011071731.1952-1-sasha.neftin@intel.com>", "list_archive_url": null, "date": "2018-10-11T07:17:31", "name": "[v8,09/11] igc: Add code for PHY support", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "4efb8613fb1c1756f7492cef7853a7a16318ae1b", "submitter": { "id": 69860, "url": "http://patchwork.ozlabs.org/api/people/69860/?format=api", "name": "Sasha Neftin", "email": "sasha.neftin@intel.com" }, "delegate": { "id": 68, "url": "http://patchwork.ozlabs.org/api/users/68/?format=api", "username": "jtkirshe", "first_name": "Jeff", "last_name": "Kirsher", "email": "jeffrey.t.kirsher@intel.com" }, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20181011071731.1952-1-sasha.neftin@intel.com/mbox/", "series": [ { "id": 70170, "url": "http://patchwork.ozlabs.org/api/series/70170/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=70170", "date": "2018-10-11T07:17:13", "name": "[v8,01/11] igc: Add skeletal frame for Intel(R) 2.5G Ethernet Controller support.", "version": 8, "mbox": "http://patchwork.ozlabs.org/series/70170/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/982293/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/982293/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<intel-wired-lan-bounces@osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.133; helo=hemlock.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org;\n\tdmarc=fail (p=none dis=none) header.from=intel.com" ], "Received": [ "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 42W2Nm3xpTz9s8F\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 11 Oct 2018 18:17:44 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 1C8DE880C4;\n\tThu, 11 Oct 2018 07:17:43 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id Dj4ZmOFJbVRw; Thu, 11 Oct 2018 07:17:38 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id B9E7688127;\n\tThu, 11 Oct 2018 07:17:38 +0000 (UTC)", "from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\tby ash.osuosl.org (Postfix) with ESMTP id 2110E1C1507\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:36 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 1D7108705D\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:36 +0000 (UTC)", "from whitealder.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id CRPZ8Yy8hcaI for <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:33 +0000 (UTC)", "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby whitealder.osuosl.org (Postfix) with ESMTPS id C5AA38546D\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:33 +0000 (UTC)", "from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t11 Oct 2018 00:17:33 -0700", "from ccdlinuxdev08.iil.intel.com ([143.185.161.150])\n\tby fmsmga002.fm.intel.com with ESMTP; 11 Oct 2018 00:17:31 -0700" ], "X-Virus-Scanned": [ "amavisd-new at osuosl.org", "amavisd-new at osuosl.org" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-Amp-Result": "SKIPPED(no attachment in message)", "X-Amp-File-Uploaded": "False", "X-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos;i=\"5.54,367,1534834800\"; d=\"scan'208\";a=\"94223127\"", "From": "Sasha Neftin <sasha.neftin@intel.com>", "To": "sasha.neftin@intel.com,\n\tintel-wired-lan@lists.osuosl.org", "Date": "Thu, 11 Oct 2018 10:17:31 +0300", "Message-Id": "<20181011071731.1952-1-sasha.neftin@intel.com>", "X-Mailer": "git-send-email 2.11.0", "Subject": "[Intel-wired-lan] [PATCH v8 09/11] igc: Add code for PHY support", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>", "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>", "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>", "Cc": "Alexander Duyck <alexander.h.duyck@intel.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "intel-wired-lan-bounces@osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>" }, "content": "Add PHY's ID support\nAdd support for initialization, acquire and release of phy\nEnable register access\n\nSasha Neftin (v2):\nminor cosmetic changes\n\nAlexander Duyck (v3.5):\nMade non-gpy versions of phy functions static\nMove xmdio functions to avoid need for prototype function\nMove reset, read_reg, and write_reg ops into e1000_phy_ops_base\nDrop code implying more than one function\nFix merge conflict with v3.5 of NVM code.\n\nSasha Neftin (v3):\nIntroduce temporary workaround for PHY power down.\n\nSasha Neftin (v4):\naddress comments\nremove space\nfix minor grammar typo\nreplace e1000_ prefix with igc_ prefix\n\nSasha Neftin (v5):\nupdate IGC_GEN_POLL_TIMEOUT value to 1920\nfix code indentation\n\nSasha Neftin (v6):\nremove double defines from igc_defines.h\nremove unused defines from igc_defines.h\nremove unused code from igc_phy.c\nfix enum igc_bus_type definition\nminor cosmetic changes\n\nSasha Neftin (v7):\nno changes\n\nSasha Neftin (v8):\nfix whitespaces in comments\nremove unneeded blank lines\nremove unneeded forward declarations\n\nSigned-off-by: Sasha Neftin <sasha.neftin@intel.com>\nSigned-off-by: Alexander Duyck <alexander.h.duyck@intel.com>\n---\n drivers/net/ethernet/intel/igc/Makefile | 2 +-\n drivers/net/ethernet/intel/igc/igc.h | 16 +\n drivers/net/ethernet/intel/igc/igc_base.c | 122 +++++++\n drivers/net/ethernet/intel/igc/igc_base.h | 1 +\n drivers/net/ethernet/intel/igc/igc_defines.h | 79 +++++\n drivers/net/ethernet/intel/igc/igc_hw.h | 54 ++++\n drivers/net/ethernet/intel/igc/igc_mac.c | 45 +++\n drivers/net/ethernet/intel/igc/igc_mac.h | 11 +\n drivers/net/ethernet/intel/igc/igc_main.c | 11 +\n drivers/net/ethernet/intel/igc/igc_phy.c | 457 +++++++++++++++++++++++++++\n drivers/net/ethernet/intel/igc/igc_phy.h | 20 ++\n drivers/net/ethernet/intel/igc/igc_regs.h | 3 +\n 12 files changed, 820 insertions(+), 1 deletion(-)\n create mode 100644 drivers/net/ethernet/intel/igc/igc_phy.c\n create mode 100644 drivers/net/ethernet/intel/igc/igc_phy.h", "diff": "diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile\nindex 2b5378d96c7b..4387f6ba8e67 100644\n--- a/drivers/net/ethernet/intel/igc/Makefile\n+++ b/drivers/net/ethernet/intel/igc/Makefile\n@@ -7,4 +7,4 @@\n \n obj-$(CONFIG_IGC) += igc.o\n \n-igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o\n+igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o\ndiff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h\nindex 6dcf51c112f4..7cfbd83d25e4 100644\n--- a/drivers/net/ethernet/intel/igc/igc.h\n+++ b/drivers/net/ethernet/intel/igc/igc.h\n@@ -359,6 +359,22 @@ static inline u16 igc_desc_unused(const struct igc_ring *ring)\n \treturn ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;\n }\n \n+static inline s32 igc_get_phy_info(struct igc_hw *hw)\n+{\n+\tif (hw->phy.ops.get_phy_info)\n+\t\treturn hw->phy.ops.get_phy_info(hw);\n+\n+\treturn 0;\n+}\n+\n+static inline s32 igc_reset_phy(struct igc_hw *hw)\n+{\n+\tif (hw->phy.ops.reset)\n+\t\treturn hw->phy.ops.reset(hw);\n+\n+\treturn 0;\n+}\n+\n static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)\n {\n \treturn netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);\ndiff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c\nindex 2d49814966d3..55faef987479 100644\n--- a/drivers/net/ethernet/intel/igc/igc_base.c\n+++ b/drivers/net/ethernet/intel/igc/igc_base.c\n@@ -124,6 +124,22 @@ static s32 igc_reset_hw_base(struct igc_hw *hw)\n }\n \n /**\n+ * igc_get_phy_id_base - Retrieve PHY addr and id\n+ * @hw: pointer to the HW structure\n+ *\n+ * Retrieves the PHY address and ID for both PHY's which do and do not use\n+ * sgmi interface.\n+ */\n+static s32 igc_get_phy_id_base(struct igc_hw *hw)\n+{\n+\ts32 ret_val = 0;\n+\n+\tret_val = igc_get_phy_id(hw);\n+\n+\treturn ret_val;\n+}\n+\n+/**\n * igc_init_nvm_params_base - Init NVM func ptrs.\n * @hw: pointer to the HW structure\n */\n@@ -187,6 +203,59 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw)\n \treturn 0;\n }\n \n+/**\n+ * igc_init_phy_params_base - Init PHY func ptrs.\n+ * @hw: pointer to the HW structure\n+ */\n+static s32 igc_init_phy_params_base(struct igc_hw *hw)\n+{\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\ts32 ret_val = 0;\n+\tu32 ctrl_ext;\n+\n+\tif (hw->phy.media_type != igc_media_type_copper) {\n+\t\tphy->type = igc_phy_none;\n+\t\tgoto out;\n+\t}\n+\n+\tphy->autoneg_mask\t= AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;\n+\tphy->reset_delay_us\t= 100;\n+\n+\tctrl_ext = rd32(IGC_CTRL_EXT);\n+\n+\t/* set lan id */\n+\thw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>\n+\t\t\tIGC_STATUS_FUNC_SHIFT;\n+\n+\t/* Make sure the PHY is in a good state. Several people have reported\n+\t * firmware leaving the PHY's page select register set to something\n+\t * other than the default of zero, which causes the PHY ID read to\n+\t * access something other than the intended register.\n+\t */\n+\tret_val = hw->phy.ops.reset(hw);\n+\tif (ret_val) {\n+\t\thw_dbg(\"Error resetting the PHY.\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tret_val = igc_get_phy_id_base(hw);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\t/* Verify phy id and set remaining function pointers */\n+\tswitch (phy->id) {\n+\tcase I225_I_PHY_ID:\n+\t\tphy->type\t= igc_phy_i225;\n+\t\tbreak;\n+\tdefault:\n+\t\tret_val = -IGC_ERR_PHY;\n+\t\tgoto out;\n+\t}\n+\n+out:\n+\treturn ret_val;\n+}\n+\n static s32 igc_get_invariants_base(struct igc_hw *hw)\n {\n \tu32 link_mode = 0;\n@@ -211,6 +280,8 @@ static s32 igc_get_invariants_base(struct igc_hw *hw)\n \t\tbreak;\n \t}\n \n+\t/* setup PHY parameters */\n+\tret_val = igc_init_phy_params_base(hw);\n \tif (ret_val)\n \t\tgoto out;\n \n@@ -219,6 +290,34 @@ static s32 igc_get_invariants_base(struct igc_hw *hw)\n }\n \n /**\n+ * igc_acquire_phy_base - Acquire rights to access PHY\n+ * @hw: pointer to the HW structure\n+ *\n+ * Acquire access rights to the correct PHY. This is a\n+ * function pointer entry point called by the api module.\n+ */\n+static s32 igc_acquire_phy_base(struct igc_hw *hw)\n+{\n+\tu16 mask = IGC_SWFW_PHY0_SM;\n+\n+\treturn hw->mac.ops.acquire_swfw_sync(hw, mask);\n+}\n+\n+/**\n+ * igc_release_phy_base - Release rights to access PHY\n+ * @hw: pointer to the HW structure\n+ *\n+ * A wrapper to release access rights to the correct PHY. This is a\n+ * function pointer entry point called by the api module.\n+ */\n+static void igc_release_phy_base(struct igc_hw *hw)\n+{\n+\tu16 mask = IGC_SWFW_PHY0_SM;\n+\n+\thw->mac.ops.release_swfw_sync(hw, mask);\n+}\n+\n+/**\n * igc_get_link_up_info_base - Get link speed/duplex info\n * @hw: pointer to the HW structure\n * @speed: stores the current speed\n@@ -290,6 +389,20 @@ static s32 igc_read_mac_addr_base(struct igc_hw *hw)\n }\n \n /**\n+ * igc_power_down_phy_copper_base - Remove link during PHY power down\n+ * @hw: pointer to the HW structure\n+ *\n+ * In the case of a PHY power down to save power, or to turn off link during a\n+ * driver unload, or wake on lan is not enabled, remove the link.\n+ */\n+void igc_power_down_phy_copper_base(struct igc_hw *hw)\n+{\n+\t/* If the management interface is not enabled, then power down */\n+\tif (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))\n+\t\tigc_power_down_phy_copper(hw);\n+}\n+\n+/**\n * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable\n * @hw: pointer to the HW structure\n *\n@@ -373,7 +486,16 @@ static struct igc_mac_operations igc_mac_ops_base = {\n \t.get_speed_and_duplex\t= igc_get_link_up_info_base,\n };\n \n+static const struct igc_phy_operations igc_phy_ops_base = {\n+\t.acquire\t\t= igc_acquire_phy_base,\n+\t.release\t\t= igc_release_phy_base,\n+\t.reset\t\t\t= igc_phy_hw_reset,\n+\t.read_reg\t\t= igc_read_phy_reg_gpy,\n+\t.write_reg\t\t= igc_write_phy_reg_gpy,\n+};\n+\n const struct igc_info igc_base_info = {\n \t.get_invariants\t\t= igc_get_invariants_base,\n \t.mac_ops\t\t= &igc_mac_ops_base,\n+\t.phy_ops\t\t= &igc_phy_ops_base,\n };\ndiff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h\nindex 802a0cbd3123..35588fa7b8c5 100644\n--- a/drivers/net/ethernet/intel/igc/igc_base.h\n+++ b/drivers/net/ethernet/intel/igc/igc_base.h\n@@ -6,6 +6,7 @@\n \n /* forward declaration */\n void igc_rx_fifo_flush_base(struct igc_hw *hw);\n+void igc_power_down_phy_copper_base(struct igc_hw *hw);\n \n /* Transmit Descriptor - Advanced */\n union igc_adv_tx_desc {\ndiff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h\nindex e5736577009a..d271671e6825 100644\n--- a/drivers/net/ethernet/intel/igc/igc_defines.h\n+++ b/drivers/net/ethernet/intel/igc/igc_defines.h\n@@ -47,11 +47,14 @@\n #define IGC_ERR_MAC_INIT\t\t5\n #define IGC_ERR_RESET\t\t\t9\n #define IGC_ERR_MASTER_REQUESTS_PENDING\t10\n+#define IGC_ERR_BLK_PHY_RESET\t\t12\n #define IGC_ERR_SWFW_SYNC\t\t13\n \n /* Device Control */\n #define IGC_CTRL_RST\t\t0x04000000 /* Global reset */\n \n+#define IGC_CTRL_PHY_RST\t0x80000000 /* PHY Reset */\n+\n /* PBA constants */\n #define IGC_PBA_34K\t\t0x0022\n \n@@ -123,6 +126,22 @@\n #define HALF_DUPLEX\t\t1\n #define FULL_DUPLEX\t\t2\n \n+/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */\n+#define ADVERTISE_10_HALF\t\t0x0001\n+#define ADVERTISE_10_FULL\t\t0x0002\n+#define ADVERTISE_100_HALF\t\t0x0004\n+#define ADVERTISE_100_FULL\t\t0x0008\n+#define ADVERTISE_1000_HALF\t\t0x0010 /* Not used, just FYI */\n+#define ADVERTISE_1000_FULL\t\t0x0020\n+#define ADVERTISE_2500_HALF\t\t0x0040 /* Not used, just FYI */\n+#define ADVERTISE_2500_FULL\t\t0x0080\n+\n+#define IGC_ALL_SPEED_DUPLEX_2500 ( \\\n+\tADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \\\n+\tADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)\n+\n+#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500\tIGC_ALL_SPEED_DUPLEX_2500\n+\n /* Interrupt Cause Read */\n #define IGC_ICR_TXDW\t\tBIT(0)\t/* Transmit desc written back */\n #define IGC_ICR_TXQE\t\tBIT(1)\t/* Transmit Queue empty */\n@@ -208,6 +227,7 @@\n \n /* Management Control */\n #define IGC_MANC_RCV_TCO_EN\t0x00020000 /* Receive TCO Packets Enabled */\n+#define IGC_MANC_BLK_PHY_RST_ON_IDE\t0x00040000 /* Block phy resets */\n \n /* Receive Control */\n #define IGC_RCTL_RST\t\t0x00000001 /* Software reset */\n@@ -256,6 +276,65 @@\n #define I225_RXPBSIZE_DEFAULT\t0x000000A2 /* RXPBSIZE default */\n #define I225_TXPBSIZE_DEFAULT\t0x04000014 /* TXPBSIZE default */\n \n+/* GPY211 - I225 defines */\n+#define GPY_MMD_MASK\t\t0xFFFF0000\n+#define GPY_MMD_SHIFT\t\t16\n+#define GPY_REG_MASK\t\t0x0000FFFF\n+\n+#define IGC_MMDAC_FUNC_DATA\t0x4000 /* Data, no post increment */\n+\n+/* MAC definitions */\n+#define IGC_FACTPS_MNGCG\t0x20000000\n+#define IGC_FWSM_MODE_MASK\t0xE\n+#define IGC_FWSM_MODE_SHIFT\t1\n+\n+/* Management Control */\n+#define IGC_MANC_SMBUS_EN\t0x00000001 /* SMBus Enabled - RO */\n+#define IGC_MANC_ASF_EN\t\t0x00000002 /* ASF Enabled - RO */\n+\n+/* PHY */\n+#define PHY_REVISION_MASK\t0xFFFFFFF0\n+#define MAX_PHY_REG_ADDRESS\t0x1F /* 5 bit address bus (0-0x1F) */\n+#define IGC_GEN_POLL_TIMEOUT\t1920\n+\n+/* PHY Control Register */\n+#define MII_CR_FULL_DUPLEX\t0x0100 /* FDX =1, half duplex =0 */\n+#define MII_CR_RESTART_AUTO_NEG\t0x0200 /* Restart auto negotiation */\n+#define MII_CR_POWER_DOWN\t0x0800 /* Power down */\n+#define MII_CR_AUTO_NEG_EN\t0x1000 /* Auto Neg Enable */\n+#define MII_CR_LOOPBACK\t\t0x4000 /* 0 = normal, 1 = loopback */\n+#define MII_CR_RESET\t\t0x8000 /* 0 = normal, 1 = PHY reset */\n+#define MII_CR_SPEED_1000\t0x0040\n+#define MII_CR_SPEED_100\t0x2000\n+#define MII_CR_SPEED_10\t\t0x0000\n+\n+/* PHY Status Register */\n+#define MII_SR_LINK_STATUS\t0x0004 /* Link Status 1 = link */\n+#define MII_SR_AUTONEG_COMPLETE\t0x0020 /* Auto Neg Complete */\n+\n+/* PHY 1000 MII Register/Bit Definitions */\n+/* PHY Registers defined by IEEE */\n+#define PHY_CONTROL\t\t0x00 /* Control Register */\n+#define PHY_STATUS\t\t0x01 /* Status Register */\n+#define PHY_ID1\t\t\t0x02 /* Phy Id Reg (word 1) */\n+#define PHY_ID2\t\t\t0x03 /* Phy Id Reg (word 2) */\n+\n+/* Bit definitions for valid PHY IDs. I = Integrated E = External */\n+#define I225_I_PHY_ID\t\t0x67C9DC00\n+\n+/* MDI Control */\n+#define IGC_MDIC_DATA_MASK\t0x0000FFFF\n+#define IGC_MDIC_REG_MASK\t0x001F0000\n+#define IGC_MDIC_REG_SHIFT\t16\n+#define IGC_MDIC_PHY_MASK\t0x03E00000\n+#define IGC_MDIC_PHY_SHIFT\t21\n+#define IGC_MDIC_OP_WRITE\t0x04000000\n+#define IGC_MDIC_OP_READ\t0x08000000\n+#define IGC_MDIC_READY\t\t0x10000000\n+#define IGC_MDIC_INT_EN\t\t0x20000000\n+#define IGC_MDIC_ERROR\t\t0x40000000\n+#define IGC_MDIC_DEST\t\t0x80000000\n+\n #define IGC_N0_QUEUE -1\n \n #endif /* _IGC_DEFINES_H_ */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h\nindex 107d6461924b..65d1446ff0c3 100644\n--- a/drivers/net/ethernet/intel/igc/igc_hw.h\n+++ b/drivers/net/ethernet/intel/igc/igc_hw.h\n@@ -11,6 +11,7 @@\n #include \"igc_regs.h\"\n #include \"igc_defines.h\"\n #include \"igc_mac.h\"\n+#include \"igc_phy.h\"\n #include \"igc_nvm.h\"\n #include \"igc_i225.h\"\n #include \"igc_base.h\"\n@@ -18,6 +19,8 @@\n #define IGC_DEV_ID_I225_LM\t\t\t0x15F2\n #define IGC_DEV_ID_I225_V\t\t\t0x15F3\n \n+#define IGC_FUNC_0\t\t\t\t0\n+\n /* Function pointers for the MAC. */\n struct igc_mac_operations {\n \ts32 (*check_for_link)(struct igc_hw *hw);\n@@ -44,6 +47,12 @@ enum igc_phy_type {\n \tigc_phy_i225,\n };\n \n+enum igc_media_type {\n+\tigc_media_type_unknown = 0,\n+\tigc_media_type_copper = 1,\n+\tigc_num_media_types\n+};\n+\n enum igc_nvm_type {\n \tigc_nvm_unknown = 0,\n \tigc_nvm_flash_hw,\n@@ -84,6 +93,7 @@ struct igc_mac_info {\n \n \tbool adaptive_ifs;\n \tbool has_fwsm;\n+\tbool asf_firmware_present;\n \tbool arc_subsystem_valid;\n \n \tbool autoneg;\n@@ -101,6 +111,20 @@ struct igc_nvm_operations {\n \ts32 (*valid_led_default)(struct igc_hw *hw, u16 *data);\n };\n \n+struct igc_phy_operations {\n+\ts32 (*acquire)(struct igc_hw *hw);\n+\ts32 (*check_polarity)(struct igc_hw *hw);\n+\ts32 (*check_reset_block)(struct igc_hw *hw);\n+\ts32 (*force_speed_duplex)(struct igc_hw *hw);\n+\ts32 (*get_cfg_done)(struct igc_hw *hw);\n+\ts32 (*get_cable_length)(struct igc_hw *hw);\n+\ts32 (*get_phy_info)(struct igc_hw *hw);\n+\ts32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);\n+\tvoid (*release)(struct igc_hw *hw);\n+\ts32 (*reset)(struct igc_hw *hw);\n+\ts32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data);\n+};\n+\n struct igc_nvm_info {\n \tstruct igc_nvm_operations ops;\n \tenum igc_nvm_type type;\n@@ -115,6 +139,35 @@ struct igc_nvm_info {\n \tu16 page_size;\n };\n \n+struct igc_phy_info {\n+\tstruct igc_phy_operations ops;\n+\n+\tenum igc_phy_type type;\n+\n+\tu32 addr;\n+\tu32 id;\n+\tu32 reset_delay_us; /* in usec */\n+\tu32 revision;\n+\n+\tenum igc_media_type media_type;\n+\n+\tu16 autoneg_advertised;\n+\tu16 autoneg_mask;\n+\tu16 cable_length;\n+\tu16 max_cable_length;\n+\tu16 min_cable_length;\n+\tu16 pair_length[4];\n+\n+\tu8 mdix;\n+\n+\tbool disable_polarity_correction;\n+\tbool is_mdix;\n+\tbool polarity_correction;\n+\tbool reset_disable;\n+\tbool speed_downgraded;\n+\tbool autoneg_wait_to_complete;\n+};\n+\n struct igc_bus_info {\n \tu16 func;\n \tu16 pci_cmd_word;\n@@ -155,6 +208,7 @@ struct igc_hw {\n \tstruct igc_mac_info mac;\n \tstruct igc_fc_info fc;\n \tstruct igc_nvm_info nvm;\n+\tstruct igc_phy_info phy;\n \n \tstruct igc_bus_info bus;\n \ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c\nindex 249ac03b05d8..fce7f7f5aa46 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.c\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.c\n@@ -338,6 +338,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw)\n \t * link. If so, then we want to get the current speed/duplex\n \t * of the PHY.\n \t */\n+\tret_val = igc_phy_has_link(hw, 1, 0, &link);\n \tif (ret_val)\n \t\tgoto out;\n \n@@ -349,6 +350,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw)\n \t/* Check if there was DownShift, must be checked\n \t * immediately after link-up\n \t */\n+\tigc_check_downshift(hw);\n \n \t/* If we are forcing speed/duplex, then we simply return since\n \t * we have already determined whether we have link or not.\n@@ -488,3 +490,46 @@ void igc_put_hw_semaphore(struct igc_hw *hw)\n \n \twr32(IGC_SWSM, swsm);\n }\n+\n+/**\n+ * igc_enable_mng_pass_thru - Enable processing of ARP's\n+ * @hw: pointer to the HW structure\n+ *\n+ * Verifies the hardware needs to leave interface enabled so that frames can\n+ * be directed to and from the management interface.\n+ */\n+bool igc_enable_mng_pass_thru(struct igc_hw *hw)\n+{\n+\tbool ret_val = false;\n+\tu32 fwsm, factps;\n+\tu32 manc;\n+\n+\tif (!hw->mac.asf_firmware_present)\n+\t\tgoto out;\n+\n+\tmanc = rd32(IGC_MANC);\n+\n+\tif (!(manc & IGC_MANC_RCV_TCO_EN))\n+\t\tgoto out;\n+\n+\tif (hw->mac.arc_subsystem_valid) {\n+\t\tfwsm = rd32(IGC_FWSM);\n+\t\tfactps = rd32(IGC_FACTPS);\n+\n+\t\tif (!(factps & IGC_FACTPS_MNGCG) &&\n+\t\t ((fwsm & IGC_FWSM_MODE_MASK) ==\n+\t\t (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {\n+\t\t\tret_val = true;\n+\t\t\tgoto out;\n+\t\t}\n+\t} else {\n+\t\tif ((manc & IGC_MANC_SMBUS_EN) &&\n+\t\t !(manc & IGC_MANC_ASF_EN)) {\n+\t\t\tret_val = true;\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n+\n+out:\n+\treturn ret_val;\n+}\ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h\nindex 88599661d017..c842cc561123 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.h\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.h\n@@ -5,6 +5,7 @@\n #define _IGC_MAC_H_\n \n #include \"igc_hw.h\"\n+#include \"igc_phy.h\"\n #include \"igc_defines.h\"\n \n #ifndef IGC_REMOVED\n@@ -25,4 +26,14 @@ void igc_config_collision_dist(struct igc_hw *hw);\n s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,\n \t\t\t\t u16 *duplex);\n \n+bool igc_enable_mng_pass_thru(struct igc_hw *hw);\n+\n+enum igc_mng_mode {\n+\tigc_mng_mode_none = 0,\n+\tigc_mng_mode_asf,\n+\tigc_mng_mode_pt,\n+\tigc_mng_mode_ipmi,\n+\tigc_mng_mode_host_if_only\n+};\n+\n #endif\ndiff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c\nindex 115fc2a544d7..14f324826604 100644\n--- a/drivers/net/ethernet/intel/igc/igc_main.c\n+++ b/drivers/net/ethernet/intel/igc/igc_main.c\n@@ -78,6 +78,8 @@ static void igc_reset(struct igc_adapter *adapter)\n \n \tif (!netif_running(adapter->netdev))\n \t\tigc_power_down_link(adapter);\n+\n+\tigc_get_phy_info(hw);\n }\n \n /**\n@@ -86,6 +88,12 @@ static void igc_reset(struct igc_adapter *adapter)\n */\n static void igc_power_up_link(struct igc_adapter *adapter)\n {\n+\tigc_reset_phy(&adapter->hw);\n+\n+\tif (adapter->hw.phy.media_type == igc_media_type_copper)\n+\t\tigc_power_up_phy_copper(&adapter->hw);\n+\n+\tigc_setup_link(&adapter->hw);\n }\n \n /**\n@@ -94,6 +102,8 @@ static void igc_power_up_link(struct igc_adapter *adapter)\n */\n static void igc_power_down_link(struct igc_adapter *adapter)\n {\n+\tif (adapter->hw.phy.media_type == igc_media_type_copper)\n+\t\tigc_power_down_phy_copper_base(&adapter->hw);\n }\n \n /**\n@@ -3377,6 +3387,7 @@ static int igc_probe(struct pci_dev *pdev,\n \n \t/* Copy the default MAC and PHY function pointers */\n \tmemcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));\n+\tmemcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));\n \n \t/* Initialize skew-specific constants */\n \terr = ei->get_invariants(hw);\ndiff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c\nnew file mode 100644\nindex 000000000000..88583c1d4970\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igc/igc_phy.c\n@@ -0,0 +1,457 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (c) 2018 Intel Corporation */\n+\n+#include \"igc_phy.h\"\n+\n+/**\n+ * igc_check_reset_block - Check if PHY reset is blocked\n+ * @hw: pointer to the HW structure\n+ *\n+ * Read the PHY management control register and check whether a PHY reset\n+ * is blocked. If a reset is not blocked return 0, otherwise\n+ * return IGC_ERR_BLK_PHY_RESET (12).\n+ */\n+s32 igc_check_reset_block(struct igc_hw *hw)\n+{\n+\tu32 manc;\n+\n+\tmanc = rd32(IGC_MANC);\n+\n+\treturn (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?\n+\t\tIGC_ERR_BLK_PHY_RESET : 0;\n+}\n+\n+/**\n+ * igc_get_phy_id - Retrieve the PHY ID and revision\n+ * @hw: pointer to the HW structure\n+ *\n+ * Reads the PHY registers and stores the PHY ID and possibly the PHY\n+ * revision in the hardware structure.\n+ */\n+s32 igc_get_phy_id(struct igc_hw *hw)\n+{\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\ts32 ret_val = 0;\n+\tu16 phy_id;\n+\n+\tret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);\n+\tif (ret_val)\n+\t\tgoto out;\n+\n+\tphy->id = (u32)(phy_id << 16);\n+\tusleep_range(200, 500);\n+\tret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);\n+\tif (ret_val)\n+\t\tgoto out;\n+\n+\tphy->id |= (u32)(phy_id & PHY_REVISION_MASK);\n+\tphy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_phy_has_link - Polls PHY for link\n+ * @hw: pointer to the HW structure\n+ * @iterations: number of times to poll for link\n+ * @usec_interval: delay between polling attempts\n+ * @success: pointer to whether polling was successful or not\n+ *\n+ * Polls the PHY status register for link, 'iterations' number of times.\n+ */\n+s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,\n+\t\t u32 usec_interval, bool *success)\n+{\n+\tu16 i, phy_status;\n+\ts32 ret_val = 0;\n+\n+\tfor (i = 0; i < iterations; i++) {\n+\t\t/* Some PHYs require the PHY_STATUS register to be read\n+\t\t * twice due to the link bit being sticky. No harm doing\n+\t\t * it across the board.\n+\t\t */\n+\t\tret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);\n+\t\tif (ret_val && usec_interval > 0) {\n+\t\t\t/* If the first read fails, another entity may have\n+\t\t\t * ownership of the resources, wait and try again to\n+\t\t\t * see if they have relinquished the resources yet.\n+\t\t\t */\n+\t\t\tif (usec_interval >= 1000)\n+\t\t\t\tmdelay(usec_interval / 1000);\n+\t\t\telse\n+\t\t\t\tudelay(usec_interval);\n+\t\t}\n+\t\tret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);\n+\t\tif (ret_val)\n+\t\t\tbreak;\n+\t\tif (phy_status & MII_SR_LINK_STATUS)\n+\t\t\tbreak;\n+\t\tif (usec_interval >= 1000)\n+\t\t\tmdelay(usec_interval / 1000);\n+\t\telse\n+\t\t\tudelay(usec_interval);\n+\t}\n+\n+\t*success = (i < iterations) ? true : false;\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_power_up_phy_copper - Restore copper link in case of PHY power down\n+ * @hw: pointer to the HW structure\n+ *\n+ * In the case of a PHY power down to save power, or to turn off link during a\n+ * driver unload, restore the link to previous settings.\n+ */\n+void igc_power_up_phy_copper(struct igc_hw *hw)\n+{\n+\tu16 mii_reg = 0;\n+\n+\t/* The PHY will retain its settings across a power down/up cycle */\n+\thw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);\n+\tmii_reg &= ~MII_CR_POWER_DOWN;\n+\thw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);\n+}\n+\n+/**\n+ * igc_power_down_phy_copper - Power down copper PHY\n+ * @hw: pointer to the HW structure\n+ *\n+ * Power down PHY to save power when interface is down and wake on lan\n+ * is not enabled.\n+ */\n+void igc_power_down_phy_copper(struct igc_hw *hw)\n+{\n+\tu16 mii_reg = 0;\n+\n+\t/* The PHY will retain its settings across a power down/up cycle */\n+\thw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);\n+\tmii_reg |= MII_CR_POWER_DOWN;\n+\n+\t/* Temporary workaround - should be removed when PHY will implement\n+\t * IEEE registers as properly\n+\t */\n+\t/* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/\n+\tusleep_range(1000, 2000);\n+}\n+\n+/**\n+ * igc_check_downshift - Checks whether a downshift in speed occurred\n+ * @hw: pointer to the HW structure\n+ *\n+ * Success returns 0, Failure returns 1\n+ *\n+ * A downshift is detected by querying the PHY link health.\n+ */\n+s32 igc_check_downshift(struct igc_hw *hw)\n+{\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\tu16 phy_data, offset, mask;\n+\ts32 ret_val;\n+\n+\tswitch (phy->type) {\n+\tcase igc_phy_i225:\n+\tdefault:\n+\t\t/* speed downshift not supported */\n+\t\tphy->speed_downgraded = false;\n+\t\tret_val = 0;\n+\t\tgoto out;\n+\t}\n+\n+\tret_val = phy->ops.read_reg(hw, offset, &phy_data);\n+\n+\tif (!ret_val)\n+\t\tphy->speed_downgraded = (phy_data & mask) ? true : false;\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_phy_hw_reset - PHY hardware reset\n+ * @hw: pointer to the HW structure\n+ *\n+ * Verify the reset block is not blocking us from resetting. Acquire\n+ * semaphore (if necessary) and read/set/write the device control reset\n+ * bit in the PHY. Wait the appropriate delay time for the device to\n+ * reset and release the semaphore (if necessary).\n+ */\n+s32 igc_phy_hw_reset(struct igc_hw *hw)\n+{\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\ts32 ret_val;\n+\tu32 ctrl;\n+\n+\tret_val = igc_check_reset_block(hw);\n+\tif (ret_val) {\n+\t\tret_val = 0;\n+\t\tgoto out;\n+\t}\n+\n+\tret_val = phy->ops.acquire(hw);\n+\tif (ret_val)\n+\t\tgoto out;\n+\n+\tctrl = rd32(IGC_CTRL);\n+\twr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);\n+\twrfl();\n+\n+\tudelay(phy->reset_delay_us);\n+\n+\twr32(IGC_CTRL, ctrl);\n+\twrfl();\n+\n+\tusleep_range(1500, 2000);\n+\n+\tphy->ops.release(hw);\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_read_phy_reg_mdic - Read MDI control register\n+ * @hw: pointer to the HW structure\n+ * @offset: register offset to be read\n+ * @data: pointer to the read data\n+ *\n+ * Reads the MDI control register in the PHY at offset and stores the\n+ * information read to data.\n+ */\n+static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)\n+{\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\tu32 i, mdic = 0;\n+\ts32 ret_val = 0;\n+\n+\tif (offset > MAX_PHY_REG_ADDRESS) {\n+\t\thw_dbg(\"PHY Address %d is out of range\\n\", offset);\n+\t\tret_val = -IGC_ERR_PARAM;\n+\t\tgoto out;\n+\t}\n+\n+\t/* Set up Op-code, Phy Address, and register offset in the MDI\n+\t * Control register. The MAC will take care of interfacing with the\n+\t * PHY to retrieve the desired data.\n+\t */\n+\tmdic = ((offset << IGC_MDIC_REG_SHIFT) |\n+\t\t(phy->addr << IGC_MDIC_PHY_SHIFT) |\n+\t\t(IGC_MDIC_OP_READ));\n+\n+\twr32(IGC_MDIC, mdic);\n+\n+\t/* Poll the ready bit to see if the MDI read completed\n+\t * Increasing the time out as testing showed failures with\n+\t * the lower time out\n+\t */\n+\tfor (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {\n+\t\tusleep_range(500, 1000);\n+\t\tmdic = rd32(IGC_MDIC);\n+\t\tif (mdic & IGC_MDIC_READY)\n+\t\t\tbreak;\n+\t}\n+\tif (!(mdic & IGC_MDIC_READY)) {\n+\t\thw_dbg(\"MDI Read did not complete\\n\");\n+\t\tret_val = -IGC_ERR_PHY;\n+\t\tgoto out;\n+\t}\n+\tif (mdic & IGC_MDIC_ERROR) {\n+\t\thw_dbg(\"MDI Error\\n\");\n+\t\tret_val = -IGC_ERR_PHY;\n+\t\tgoto out;\n+\t}\n+\t*data = (u16)mdic;\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_write_phy_reg_mdic - Write MDI control register\n+ * @hw: pointer to the HW structure\n+ * @offset: register offset to write to\n+ * @data: data to write to register at offset\n+ *\n+ * Writes data to MDI control register in the PHY at offset.\n+ */\n+static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)\n+{\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\tu32 i, mdic = 0;\n+\ts32 ret_val = 0;\n+\n+\tif (offset > MAX_PHY_REG_ADDRESS) {\n+\t\thw_dbg(\"PHY Address %d is out of range\\n\", offset);\n+\t\tret_val = -IGC_ERR_PARAM;\n+\t\tgoto out;\n+\t}\n+\n+\t/* Set up Op-code, Phy Address, and register offset in the MDI\n+\t * Control register. The MAC will take care of interfacing with the\n+\t * PHY to write the desired data.\n+\t */\n+\tmdic = (((u32)data) |\n+\t\t(offset << IGC_MDIC_REG_SHIFT) |\n+\t\t(phy->addr << IGC_MDIC_PHY_SHIFT) |\n+\t\t(IGC_MDIC_OP_WRITE));\n+\n+\twr32(IGC_MDIC, mdic);\n+\n+\t/* Poll the ready bit to see if the MDI read completed\n+\t * Increasing the time out as testing showed failures with\n+\t * the lower time out\n+\t */\n+\tfor (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {\n+\t\tusleep_range(500, 1000);\n+\t\tmdic = rd32(IGC_MDIC);\n+\t\tif (mdic & IGC_MDIC_READY)\n+\t\t\tbreak;\n+\t}\n+\tif (!(mdic & IGC_MDIC_READY)) {\n+\t\thw_dbg(\"MDI Write did not complete\\n\");\n+\t\tret_val = -IGC_ERR_PHY;\n+\t\tgoto out;\n+\t}\n+\tif (mdic & IGC_MDIC_ERROR) {\n+\t\thw_dbg(\"MDI Error\\n\");\n+\t\tret_val = -IGC_ERR_PHY;\n+\t\tgoto out;\n+\t}\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * __igc_access_xmdio_reg - Read/write XMDIO register\n+ * @hw: pointer to the HW structure\n+ * @address: XMDIO address to program\n+ * @dev_addr: device address to program\n+ * @data: pointer to value to read/write from/to the XMDIO address\n+ * @read: boolean flag to indicate read or write\n+ */\n+static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,\n+\t\t\t\t u8 dev_addr, u16 *data, bool read)\n+{\n+\ts32 ret_val;\n+\n+\tret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\tret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\tret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |\n+\t\t\t\t\tdev_addr);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\tif (read)\n+\t\tret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);\n+\telse\n+\t\tret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\t/* Recalibrate the device back to 0 */\n+\tret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_read_xmdio_reg - Read XMDIO register\n+ * @hw: pointer to the HW structure\n+ * @addr: XMDIO address to program\n+ * @dev_addr: device address to program\n+ * @data: value to be read from the EMI address\n+ */\n+static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,\n+\t\t\t u8 dev_addr, u16 *data)\n+{\n+\treturn __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);\n+}\n+\n+/**\n+ * igc_write_xmdio_reg - Write XMDIO register\n+ * @hw: pointer to the HW structure\n+ * @addr: XMDIO address to program\n+ * @dev_addr: device address to program\n+ * @data: value to be written to the XMDIO address\n+ */\n+static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,\n+\t\t\t u8 dev_addr, u16 data)\n+{\n+\treturn __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);\n+}\n+\n+/**\n+ * igc_write_phy_reg_gpy - Write GPY PHY register\n+ * @hw: pointer to the HW structure\n+ * @offset: register offset to write to\n+ * @data: data to write at register offset\n+ *\n+ * Acquires semaphore, if necessary, then writes the data to PHY register\n+ * at the offset. Release any acquired semaphores before exiting.\n+ */\n+s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)\n+{\n+\tu8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;\n+\ts32 ret_val;\n+\n+\toffset = offset & GPY_REG_MASK;\n+\n+\tif (!dev_addr) {\n+\t\tret_val = hw->phy.ops.acquire(hw);\n+\t\tif (ret_val)\n+\t\t\treturn ret_val;\n+\t\tret_val = igc_write_phy_reg_mdic(hw, offset, data);\n+\t\tif (ret_val)\n+\t\t\treturn ret_val;\n+\t\thw->phy.ops.release(hw);\n+\t} else {\n+\t\tret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,\n+\t\t\t\t\t data);\n+\t}\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_read_phy_reg_gpy - Read GPY PHY register\n+ * @hw: pointer to the HW structure\n+ * @offset: lower half is register offset to read to\n+ * upper half is MMD to use.\n+ * @data: data to read at register offset\n+ *\n+ * Acquires semaphore, if necessary, then reads the data in the PHY register\n+ * at the offset. Release any acquired semaphores before exiting.\n+ */\n+s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)\n+{\n+\tu8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;\n+\ts32 ret_val;\n+\n+\toffset = offset & GPY_REG_MASK;\n+\n+\tif (!dev_addr) {\n+\t\tret_val = hw->phy.ops.acquire(hw);\n+\t\tif (ret_val)\n+\t\t\treturn ret_val;\n+\t\tret_val = igc_read_phy_reg_mdic(hw, offset, data);\n+\t\tif (ret_val)\n+\t\t\treturn ret_val;\n+\t\thw->phy.ops.release(hw);\n+\t} else {\n+\t\tret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,\n+\t\t\t\t\t data);\n+\t}\n+\n+\treturn ret_val;\n+}\ndiff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h\nnew file mode 100644\nindex 000000000000..6a62f381559d\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igc/igc_phy.h\n@@ -0,0 +1,20 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (c) 2018 Intel Corporation */\n+\n+#ifndef _IGC_PHY_H_\n+#define _IGC_PHY_H_\n+\n+#include \"igc_mac.h\"\n+\n+s32 igc_check_reset_block(struct igc_hw *hw);\n+s32 igc_phy_hw_reset(struct igc_hw *hw);\n+s32 igc_get_phy_id(struct igc_hw *hw);\n+s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,\n+\t\t u32 usec_interval, bool *success);\n+s32 igc_check_downshift(struct igc_hw *hw);\n+void igc_power_up_phy_copper(struct igc_hw *hw);\n+void igc_power_down_phy_copper(struct igc_hw *hw);\n+s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);\n+s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);\n+\n+#endif\ndiff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h\nindex b5996e474c3c..a1bd3216c906 100644\n--- a/drivers/net/ethernet/intel/igc/igc_regs.h\n+++ b/drivers/net/ethernet/intel/igc/igc_regs.h\n@@ -39,6 +39,9 @@\n #define IGC_SWSM\t\t0x05B50 /* SW Semaphore */\n #define IGC_FWSM\t\t0x05B54 /* FW Semaphore */\n \n+/* Function Active and Power State to MNG */\n+#define IGC_FACTPS\t\t0x05B30\n+\n /* Interrupt Register Description */\n #define IGC_EICS\t\t0x01520 /* Ext. Interrupt Cause Set - W0 */\n #define IGC_EIMS\t\t0x01524 /* Ext. Interrupt Mask Set/Read - RW */\n", "prefixes": [ "v8", "09/11" ] }