get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/945573/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 945573,
    "url": "http://patchwork.ozlabs.org/api/patches/945573/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180718081809.15868-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": "<20180718081809.15868-1-sasha.neftin@intel.com>",
    "list_archive_url": null,
    "date": "2018-07-18T08:18:09",
    "name": "[v4,09/11] igc: Add code for PHY support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "8e6f9556314a37487bf940155f7694c7f9b5f55d",
    "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/20180718081809.15868-1-sasha.neftin@intel.com/mbox/",
    "series": [
        {
            "id": 56158,
            "url": "http://patchwork.ozlabs.org/api/series/56158/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=56158",
            "date": "2018-07-18T08:17:45",
            "name": "[v4,01/11] igc: Add skeletal frame for Intel(R) 2.5G Ethernet Controller support.",
            "version": 4,
            "mbox": "http://patchwork.ozlabs.org/series/56158/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/945573/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/945573/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.136; helo=silver.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 silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 41Vqm42P9rz9rxx\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 18 Jul 2018 18:18:28 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id D15D0244BF;\n\tWed, 18 Jul 2018 08:18:26 +0000 (UTC)",
            "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id Ugzvvj5Rc4kJ; Wed, 18 Jul 2018 08:18:18 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id 335683079A;\n\tWed, 18 Jul 2018 08:18:18 +0000 (UTC)",
            "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id D5A0F1C094F\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 18 Jul 2018 08:18:16 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id D2D5788C5B\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 18 Jul 2018 08:18:16 +0000 (UTC)",
            "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id ws2M59LlBCwV for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 18 Jul 2018 08:18:14 +0000 (UTC)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id 8F9A188C59\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 18 Jul 2018 08:18:14 +0000 (UTC)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t18 Jul 2018 01:18:13 -0700",
            "from ccdlinuxdev06.iil.intel.com ([143.185.162.2])\n\tby orsmga001.jf.intel.com with ESMTP; 18 Jul 2018 01:18:10 -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.51,369,1526367600\"; d=\"scan'208\";a=\"73736657\"",
        "From": "Sasha Neftin <sasha.neftin@intel.com>",
        "To": "sasha.neftin@intel.com,\n\tintel-wired-lan@lists.osuosl.org",
        "Date": "Wed, 18 Jul 2018 11:18:09 +0300",
        "Message-Id": "<20180718081809.15868-1-sasha.neftin@intel.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "Subject": "[Intel-wired-lan] [PATCH v4 09/11] igc: Add code for PHY support",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.24",
        "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>",
        "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": "Sasha 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\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    | 126 +++++++-\n drivers/net/ethernet/intel/igc/igc_base.h    |   1 +\n drivers/net/ethernet/intel/igc/igc_defines.h |  95 ++++++\n drivers/net/ethernet/intel/igc/igc_hw.h      |  62 +++-\n drivers/net/ethernet/intel/igc/igc_mac.c     |  47 ++-\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     | 458 +++++++++++++++++++++++++++\n drivers/net/ethernet/intel/igc/igc_phy.h     |  20 ++\n drivers/net/ethernet/intel/igc/igc_regs.h    |   3 +\n 12 files changed, 844 insertions(+), 8 deletions(-)\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 9ef6f290209c..901048fdf478 100644\n--- a/drivers/net/ethernet/intel/igc/igc.h\n+++ b/drivers/net/ethernet/intel/igc/igc.h\n@@ -365,6 +365,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 0c7cacb75643..7215f303278e 100644\n--- a/drivers/net/ethernet/intel/igc/igc_base.c\n+++ b/drivers/net/ethernet/intel/igc/igc_base.c\n@@ -12,12 +12,31 @@\n /* forward declaration */\n static s32 igc_get_invariants_base(struct igc_hw *);\n static s32 igc_check_for_link_base(struct igc_hw *);\n+static s32 igc_acquire_phy_base(struct igc_hw *);\n+static void igc_release_phy_base(struct igc_hw *);\n+static s32 igc_get_phy_id_base(struct igc_hw *);\n static s32 igc_init_hw_base(struct igc_hw *);\n static s32 igc_reset_hw_base(struct igc_hw *);\n static s32 igc_set_pcie_completion_timeout(struct igc_hw *hw);\n static s32 igc_read_mac_addr_base(struct igc_hw *hw);\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@@ -81,6 +100,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       = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;\n+\tphy->reset_delay_us     = 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@@ -105,6 +177,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@@ -113,6 +187,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@@ -200,6 +302,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@@ -283,10 +399,18 @@ 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/* TODO phy_ops */\n+\t.phy_ops\t\t= &igc_phy_ops_base,\n };\n \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 a94970289a74..6b0c5058d897 100644\n--- a/drivers/net/ethernet/intel/igc/igc_defines.h\n+++ b/drivers/net/ethernet/intel/igc/igc_defines.h\n@@ -54,11 +54,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\t\t12\n #define IGC_ERR_SWFW_SYNC\t\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@@ -131,6 +134,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@@ -216,6 +235,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@@ -280,6 +300,81 @@\n #define I225_RXPBSIZE_DEFAULT\t0x000000A2 /* RXPBSIZE default */\n #define I225_TXPBSIZE_DEFAULT\t0x04000014 /* TXPBSIZE default */\n \n+/* these buffer sizes are valid if IGC_RCTL_BSEX is 0 */\n+#define IGC_RCTL_SZ_2048\t0x00000000 /* Rx buffer size 2048 */\n+#define IGC_RCTL_SZ_1024\t0x00010000 /* Rx buffer size 1024 */\n+#define IGC_RCTL_SZ_512\t\t0x00020000 /* Rx buffer size 512 */\n+#define IGC_RCTL_SZ_256\t\t0x00030000 /* Rx buffer size 256 */\n+/* these buffer sizes are valid if IGC_RCTL_BSEX is 1 */\n+#define IGC_RCTL_SZ_16384\t0x00010000 /* Rx buffer size 16384 */\n+#define IGC_RCTL_SZ_8192\t0x00020000 /* Rx buffer size 8192 */\n+#define IGC_RCTL_SZ_4096\t0x00030000 /* Rx buffer size 4096 */\n+\n+#define IGC_RCTL_MO_SHIFT\t12 /* multicast offset shift */\n+#define IGC_RCTL_CFIEN\t\t0x00080000 /* canonical form enable */\n+#define IGC_RCTL_DPF\t\t0x00400000 /* discard pause frames */\n+#define IGC_RCTL_PMCF\t\t0x00800000 /* pass MAC control frames */\n+#define IGC_RCTL_SECRC\t\t0x04000000 /* Strip Ethernet CRC */\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\t640\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 bf4fcbe396e6..a84cf0ba78d4 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 /* Forward declaration */\n struct igc_hw;\n \n@@ -47,10 +50,10 @@ enum igc_phy_type {\n \tigc_phy_i225,\n };\n \n-enum igc_bus_type {\n-\tigc_bus_type_unknown = 0,\n-\tigc_bus_type_pci_express,\n-\tigc_bus_type_reserved\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@@ -59,6 +62,12 @@ enum igc_nvm_type {\n \tigc_nvm_invm,\n };\n \n+enum igc_bus_type {\n+\tigc_bus_type_unknown = 0,\n+\tigc_bus_type_pci_express,\n+\tigc_bus_type_reserved\n+};\n+\n enum igc_bus_speed {\n \tigc_bus_speed_unknown = 0,\n \tigc_bus_speed_2500,\n@@ -109,6 +118,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@@ -126,6 +136,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@@ -140,6 +164,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 \tenum igc_bus_type type;\n \tenum igc_bus_speed speed;\n@@ -185,6 +238,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 d08d2c6a6647..78941e2a26f0 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.c\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.c\n@@ -389,7 +389,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-\t/* TODO ret_val = igc_phy_has_link(hw, 1, 0, &link); */\n+\tret_val = igc_phy_has_link(hw, 1, 0, &link);\n \tif (ret_val)\n \t\tgoto out;\n \n@@ -401,7 +401,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-\t/* TODO igc_check_downshift(hw); */\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@@ -542,3 +542,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 7d935d581fc7..e61b9c5faa32 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@@ -26,4 +27,14 @@ s32 igc_get_bus_info_pcie(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 2514bb5e5651..24689854a0a2 100644\n--- a/drivers/net/ethernet/intel/igc/igc_main.c\n+++ b/drivers/net/ethernet/intel/igc/igc_main.c\n@@ -100,6 +100,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@@ -108,6 +110,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@@ -116,6 +124,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@@ -3401,6 +3411,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..95c9a30b96a2\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igc/igc_phy.c\n@@ -0,0 +1,458 @@\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+\tret_val = phy->ops.get_cfg_done(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 * 3); 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 * 3); 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+\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+\treturn ret_val;\n+}\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..deac52297052\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 aaeaf61b730a..68a1aa17b329 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": [
        "v4",
        "09/11"
    ]
}