get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 982295,
    "url": "http://patchwork.ozlabs.org/api/patches/982295/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20181011071728.1908-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": "<20181011071728.1908-1-sasha.neftin@intel.com>",
    "list_archive_url": null,
    "date": "2018-10-11T07:17:28",
    "name": "[v8,08/11] igc: Add NVM support",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "782f02a48fbbbbec0aabbd3d560a2f1395d3fb49",
    "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/20181011071728.1908-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/982295/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/982295/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 42W2P61SsXz9s8F\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 11 Oct 2018 18:18:01 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 8397E880E2;\n\tThu, 11 Oct 2018 07:18:00 +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 vgWpff4AsJM2; Thu, 11 Oct 2018 07:17:58 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 4D9EC880C7;\n\tThu, 11 Oct 2018 07:17:58 +0000 (UTC)",
            "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id B25211C1507\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:57 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id AF2E085773\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:57 +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 uC11R8XyVE0I for <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:55 +0000 (UTC)",
            "from mga03.intel.com (mga03.intel.com [134.134.136.65])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id 97ED985BDF\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 11 Oct 2018 07:17:55 +0000 (UTC)",
            "from fmsmga001.fm.intel.com ([10.253.24.23])\n\tby orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t11 Oct 2018 00:17:54 -0700",
            "from ccdlinuxdev08.iil.intel.com ([143.185.161.150])\n\tby fmsmga001.fm.intel.com with ESMTP; 11 Oct 2018 00:17:29 -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=\"98220116\"",
        "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:28 +0300",
        "Message-Id": "<20181011071728.1908-1-sasha.neftin@intel.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "Subject": "[Intel-wired-lan] [PATCH v8 08/11] igc: Add NVM 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 code for NVM support and get MAC address, complete probe\nmethod.\n\nSasha Neftin (v2):\nminor cosmetic changes\n\nAlexander Duyck (v3):\nNVM access code optimization\n\nSasha Neftin (v4):\nfix xmas tree layout\nremove no need spaces\nrework igc_read_nvm_srrd/srwr and igc_validate_nvm_checksum_i225\nfix few methods as suggested by Shannon Nelson's approach\nremove obsolete comments\nreplace e1000_ prefix with igc_ prefix\nremove unused NVM control definitions\nremove unused NVM Word offsets\nremove unused SW FW SYNC definition\nfix duplication of mask definition\n\nSasha Neftin (v5):\nno changes\n\nSasha Neftin (v6):\nminor cosmetic changes\nremove duplication of defines\n\nSasha Neftin (v7):\nfix kbuild test robot warning\nremove unneeded ret_val from igc_init_nvm_params_i225 method\n\nSasha Neftin (v8):\nfix whitespaces in comments\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         |   6 +\n drivers/net/ethernet/intel/igc/igc_base.c    | 109 +++++++++\n drivers/net/ethernet/intel/igc/igc_defines.h |  52 ++++\n drivers/net/ethernet/intel/igc/igc_hw.h      |   3 +\n drivers/net/ethernet/intel/igc/igc_i225.c    | 349 +++++++++++++++++++++++++++\n drivers/net/ethernet/intel/igc/igc_i225.h    |   3 +\n drivers/net/ethernet/intel/igc/igc_mac.c     | 170 +++++++++++++\n drivers/net/ethernet/intel/igc/igc_mac.h     |   6 +\n drivers/net/ethernet/intel/igc/igc_main.c    |  20 +-\n drivers/net/ethernet/intel/igc/igc_nvm.c     | 215 +++++++++++++++++\n drivers/net/ethernet/intel/igc/igc_nvm.h     |  14 ++\n drivers/net/ethernet/intel/igc/igc_regs.h    |   3 +\n 13 files changed, 949 insertions(+), 3 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/igc/igc_nvm.c\n create mode 100644 drivers/net/ethernet/intel/igc/igc_nvm.h",
    "diff": "diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile\nindex 8b8022ea590a..2b5378d96c7b 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\n+igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o\ndiff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h\nindex 88ee451e36fd..6dcf51c112f4 100644\n--- a/drivers/net/ethernet/intel/igc/igc.h\n+++ b/drivers/net/ethernet/intel/igc/igc.h\n@@ -131,6 +131,10 @@ enum igc_tx_flags {\n \tIGC_TX_FLAGS_CSUM\t= 0x20,\n };\n \n+enum igc_boards {\n+\tboard_base,\n+};\n+\n /* The largest size we can write to the descriptor is 65535.  In order to\n  * maintain a power of two alignment we have to limit ourselves to 32K.\n  */\n@@ -342,6 +346,8 @@ struct igc_adapter {\n \tspinlock_t nfc_lock;\n \n \tstruct igc_mac_addr *mac_table;\n+\n+\tstruct igc_info ei;\n };\n \n /* igc_desc_unused - calculate if we have unused descriptors */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c\nindex 4efb47497e6b..2d49814966d3 100644\n--- a/drivers/net/ethernet/intel/igc/igc_base.c\n+++ b/drivers/net/ethernet/intel/igc/igc_base.c\n@@ -54,6 +54,22 @@ static s32 igc_set_pcie_completion_timeout(struct igc_hw *hw)\n }\n \n /**\n+ * igc_check_for_link_base - Check for link\n+ * @hw: pointer to the HW structure\n+ *\n+ * If sgmii is enabled, then use the pcs register to determine link, otherwise\n+ * use the generic interface for determining link.\n+ */\n+static s32 igc_check_for_link_base(struct igc_hw *hw)\n+{\n+\ts32 ret_val = 0;\n+\n+\tret_val = igc_check_for_copper_link(hw);\n+\n+\treturn ret_val;\n+}\n+\n+/**\n  * igc_reset_hw_base - Reset hardware\n  * @hw: pointer to the HW structure\n  *\n@@ -108,11 +124,50 @@ static s32 igc_reset_hw_base(struct igc_hw *hw)\n }\n \n /**\n+ * igc_init_nvm_params_base - Init NVM func ptrs.\n+ * @hw: pointer to the HW structure\n+ */\n+static s32 igc_init_nvm_params_base(struct igc_hw *hw)\n+{\n+\tstruct igc_nvm_info *nvm = &hw->nvm;\n+\tu32 eecd = rd32(IGC_EECD);\n+\tu16 size;\n+\n+\tsize = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>\n+\t\t     IGC_EECD_SIZE_EX_SHIFT);\n+\n+\t/* Added to a constant, \"size\" becomes the left-shift value\n+\t * for setting word_size.\n+\t */\n+\tsize += NVM_WORD_SIZE_BASE_SHIFT;\n+\n+\t/* Just in case size is out of range, cap it to the largest\n+\t * EEPROM size supported\n+\t */\n+\tif (size > 15)\n+\t\tsize = 15;\n+\n+\tnvm->word_size = BIT(size);\n+\tnvm->opcode_bits = 8;\n+\tnvm->delay_usec = 1;\n+\n+\tnvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;\n+\tnvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?\n+\t\t\t    16 : 8;\n+\n+\tif (nvm->word_size == BIT(15))\n+\t\tnvm->page_size = 128;\n+\n+\treturn 0;\n+}\n+\n+/**\n  * igc_init_mac_params_base - Init MAC func ptrs.\n  * @hw: pointer to the HW structure\n  */\n static s32 igc_init_mac_params_base(struct igc_hw *hw)\n {\n+\tstruct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;\n \tstruct igc_mac_info *mac = &hw->mac;\n \n \t/* Set mta register count */\n@@ -125,6 +180,10 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw)\n \tmac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;\n \tmac->ops.release_swfw_sync = igc_release_swfw_sync_i225;\n \n+\t/* Allow a single clear of the SW semaphore on I225 */\n+\tif (mac->type == igc_i225)\n+\t\tdev_spec->clear_semaphore_once = true;\n+\n \treturn 0;\n }\n \n@@ -142,11 +201,44 @@ static s32 igc_get_invariants_base(struct igc_hw *hw)\n \tif (ret_val)\n \t\tgoto out;\n \n+\t/* NVM initialization */\n+\tret_val = igc_init_nvm_params_base(hw);\n+\tswitch (hw->mac.type) {\n+\tcase igc_i225:\n+\t\tret_val = igc_init_nvm_params_i225(hw);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (ret_val)\n+\t\tgoto out;\n+\n out:\n \treturn ret_val;\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+ * @duplex: stores the current duplex\n+ *\n+ * This is a wrapper function, if using the serial gigabit media independent\n+ * interface, use PCS to retrieve the link speed and duplex information.\n+ * Otherwise, use the generic function to get the link speed and duplex info.\n+ */\n+static s32 igc_get_link_up_info_base(struct igc_hw *hw, u16 *speed,\n+\t\t\t\t     u16 *duplex)\n+{\n+\ts32 ret_val;\n+\n+\tret_val = igc_get_speed_and_duplex_copper(hw, speed, duplex);\n+\n+\treturn ret_val;\n+}\n+\n+/**\n  * igc_init_hw_base - Initialize hardware\n  * @hw: pointer to the HW structure\n  *\n@@ -185,6 +277,19 @@ static s32 igc_init_hw_base(struct igc_hw *hw)\n }\n \n /**\n+ * igc_read_mac_addr_base - Read device MAC address\n+ * @hw: pointer to the HW structure\n+ */\n+static s32 igc_read_mac_addr_base(struct igc_hw *hw)\n+{\n+\ts32 ret_val = 0;\n+\n+\tret_val = igc_read_mac_addr(hw);\n+\n+\treturn ret_val;\n+}\n+\n+/**\n  * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable\n  * @hw: pointer to the HW structure\n  *\n@@ -262,6 +367,10 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw)\n \n static struct igc_mac_operations igc_mac_ops_base = {\n \t.init_hw\t\t= igc_init_hw_base,\n+\t.check_for_link\t\t= igc_check_for_link_base,\n+\t.rar_set\t\t= igc_rar_set,\n+\t.read_mac_addr\t\t= igc_read_mac_addr_base,\n+\t.get_speed_and_duplex\t= igc_get_link_up_info_base,\n };\n \n const struct igc_info igc_base_info = {\ndiff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h\nindex 3d6c2cee0ad3..e5736577009a 100644\n--- a/drivers/net/ethernet/intel/igc/igc_defines.h\n+++ b/drivers/net/ethernet/intel/igc/igc_defines.h\n@@ -35,6 +35,8 @@\n  */\n #define IGC_RAH_AV\t\t0x80000000 /* Receive descriptor valid */\n #define IGC_RAH_POOL_1\t\t0x00040000\n+#define IGC_RAL_MAC_ADDR_LEN\t4\n+#define IGC_RAH_MAC_ADDR_LEN\t2\n \n /* Error Codes */\n #define IGC_SUCCESS\t\t\t0\n@@ -57,9 +59,51 @@\n #define IGC_SWSM_SMBI\t\t0x00000001 /* Driver Semaphore bit */\n #define IGC_SWSM_SWESMBI\t0x00000002 /* FW Semaphore bit */\n \n+/* SWFW_SYNC Definitions */\n+#define IGC_SWFW_EEP_SM\t\t0x1\n+#define IGC_SWFW_PHY0_SM\t0x2\n+\n+/* NVM Control */\n /* Number of milliseconds for NVM auto read done after MAC reset. */\n #define AUTO_READ_DONE_TIMEOUT\t\t10\n #define IGC_EECD_AUTO_RD\t\t0x00000200  /* NVM Auto Read done */\n+#define IGC_EECD_REQ\t\t0x00000040 /* NVM Access Request */\n+#define IGC_EECD_GNT\t\t0x00000080 /* NVM Access Grant */\n+/* NVM Addressing bits based on type 0=small, 1=large */\n+#define IGC_EECD_ADDR_BITS\t\t0x00000400\n+#define IGC_NVM_GRANT_ATTEMPTS\t\t1000 /* NVM # attempts to gain grant */\n+#define IGC_EECD_SIZE_EX_MASK\t\t0x00007800  /* NVM Size */\n+#define IGC_EECD_SIZE_EX_SHIFT\t\t11\n+#define IGC_EECD_FLUPD_I225\t\t0x00800000 /* Update FLASH */\n+#define IGC_EECD_FLUDONE_I225\t\t0x04000000 /* Update FLASH done*/\n+#define IGC_EECD_FLASH_DETECTED_I225\t0x00080000 /* FLASH detected */\n+#define IGC_FLUDONE_ATTEMPTS\t\t20000\n+#define IGC_EERD_EEWR_MAX_COUNT\t\t512 /* buffered EEPROM words rw */\n+\n+/* Offset to data in NVM read/write registers */\n+#define IGC_NVM_RW_REG_DATA\t16\n+#define IGC_NVM_RW_REG_DONE\t2    /* Offset to READ/WRITE done bit */\n+#define IGC_NVM_RW_REG_START\t1    /* Start operation */\n+#define IGC_NVM_RW_ADDR_SHIFT\t2    /* Shift to the address bits */\n+#define IGC_NVM_POLL_READ\t0    /* Flag for polling for read complete */\n+\n+/* NVM Word Offsets */\n+#define NVM_CHECKSUM_REG\t\t0x003F\n+\n+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */\n+#define NVM_SUM\t\t\t\t0xBABA\n+\n+#define NVM_PBA_OFFSET_0\t\t8\n+#define NVM_PBA_OFFSET_1\t\t9\n+#define NVM_RESERVED_WORD\t\t0xFFFF\n+#define NVM_PBA_PTR_GUARD\t\t0xFAFA\n+#define NVM_WORD_SIZE_BASE_SHIFT\t6\n+\n+/* Collision related configuration parameters */\n+#define IGC_COLLISION_THRESHOLD\t\t15\n+#define IGC_CT_SHIFT\t\t\t4\n+#define IGC_COLLISION_DISTANCE\t\t63\n+#define IGC_COLD_SHIFT\t\t\t12\n \n /* Device Status */\n #define IGC_STATUS_FD\t\t0x00000001      /* Full duplex.0=half,1=full */\n@@ -70,6 +114,14 @@\n #define IGC_STATUS_TXOFF\t0x00000010      /* transmission paused */\n #define IGC_STATUS_SPEED_100\t0x00000040      /* Speed 100Mb/s */\n #define IGC_STATUS_SPEED_1000\t0x00000080      /* Speed 1000Mb/s */\n+#define IGC_STATUS_SPEED_2500\t0x00400000\t/* Speed 2.5Gb/s */\n+\n+#define SPEED_10\t\t10\n+#define SPEED_100\t\t100\n+#define SPEED_1000\t\t1000\n+#define SPEED_2500\t\t2500\n+#define HALF_DUPLEX\t\t1\n+#define FULL_DUPLEX\t\t2\n \n /* Interrupt Cause Read */\n #define IGC_ICR_TXDW\t\tBIT(0)\t/* Transmit desc written back */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h\nindex e31d85f1ee12..107d6461924b 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_nvm.h\"\n #include \"igc_i225.h\"\n #include \"igc_base.h\"\n \n@@ -56,6 +57,8 @@ struct igc_info {\n \tstruct igc_nvm_operations *nvm_ops;\n };\n \n+extern const struct igc_info igc_base_info;\n+\n struct igc_mac_info {\n \tstruct igc_mac_operations ops;\n \ndiff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c\nindex fb1487727d79..c25f555aaf82 100644\n--- a/drivers/net/ethernet/intel/igc/igc_i225.c\n+++ b/drivers/net/ethernet/intel/igc/igc_i225.c\n@@ -9,6 +9,32 @@\n  * igc_get_hw_semaphore_i225 - Acquire hardware semaphore\n  * @hw: pointer to the HW structure\n  *\n+ * Acquire the necessary semaphores for exclusive access to the EEPROM.\n+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.\n+ * Return successful if access grant bit set, else clear the request for\n+ * EEPROM access and return -IGC_ERR_NVM (-1).\n+ */\n+static s32 igc_acquire_nvm_i225(struct igc_hw *hw)\n+{\n+\treturn igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);\n+}\n+\n+/**\n+ * igc_release_nvm_i225 - Release exclusive access to EEPROM\n+ * @hw: pointer to the HW structure\n+ *\n+ * Stop any current commands to the EEPROM and clear the EEPROM request bit,\n+ * then release the semaphores acquired.\n+ */\n+static void igc_release_nvm_i225(struct igc_hw *hw)\n+{\n+\tigc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);\n+}\n+\n+/**\n+ * igc_get_hw_semaphore_i225 - Acquire hardware semaphore\n+ * @hw: pointer to the HW structure\n+ *\n  * Acquire the HW semaphore to access the PHY or NVM\n  */\n static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)\n@@ -139,3 +165,326 @@ void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)\n \n \tigc_put_hw_semaphore(hw);\n }\n+\n+/**\n+ * igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register\n+ * @hw: pointer to the HW structure\n+ * @offset: offset of word in the Shadow Ram to read\n+ * @words: number of words to read\n+ * @data: word read from the Shadow Ram\n+ *\n+ * Reads a 16 bit word from the Shadow Ram using the EERD register.\n+ * Uses necessary synchronization semaphores.\n+ */\n+static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,\n+\t\t\t\t  u16 *data)\n+{\n+\ts32 status = 0;\n+\tu16 i, count;\n+\n+\t/* We cannot hold synchronization semaphores for too long,\n+\t * because of forceful takeover procedure. However it is more efficient\n+\t * to read in bursts than synchronizing access for each word.\n+\t */\n+\tfor (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {\n+\t\tcount = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?\n+\t\t\tIGC_EERD_EEWR_MAX_COUNT : (words - i);\n+\n+\t\tstatus = hw->nvm.ops.acquire(hw);\n+\t\tif (status)\n+\t\t\tbreak;\n+\n+\t\tstatus = igc_read_nvm_eerd(hw, offset, count, data + i);\n+\t\thw->nvm.ops.release(hw);\n+\t\tif (status)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * igc_write_nvm_srwr - Write to Shadow Ram using EEWR\n+ * @hw: pointer to the HW structure\n+ * @offset: offset within the Shadow Ram to be written to\n+ * @words: number of words to write\n+ * @data: 16 bit word(s) to be written to the Shadow Ram\n+ *\n+ * Writes data to Shadow Ram at offset using EEWR register.\n+ *\n+ * If igc_update_nvm_checksum is not called after this function , the\n+ * Shadow Ram will most likely contain an invalid checksum.\n+ */\n+static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,\n+\t\t\t      u16 *data)\n+{\n+\tstruct igc_nvm_info *nvm = &hw->nvm;\n+\tu32 attempts = 100000;\n+\tu32 i, k, eewr = 0;\n+\ts32 ret_val = 0;\n+\n+\t/* A check for invalid values:  offset too large, too many words,\n+\t * too many words for the offset, and not enough words.\n+\t */\n+\tif (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||\n+\t    words == 0) {\n+\t\thw_dbg(\"nvm parameter(s) out of bounds\\n\");\n+\t\tret_val = -IGC_ERR_NVM;\n+\t\tgoto out;\n+\t}\n+\n+\tfor (i = 0; i < words; i++) {\n+\t\teewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |\n+\t\t\t(data[i] << IGC_NVM_RW_REG_DATA) |\n+\t\t\tIGC_NVM_RW_REG_START;\n+\n+\t\twr32(IGC_SRWR, eewr);\n+\n+\t\tfor (k = 0; k < attempts; k++) {\n+\t\t\tif (IGC_NVM_RW_REG_DONE &\n+\t\t\t    rd32(IGC_SRWR)) {\n+\t\t\t\tret_val = 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tudelay(5);\n+\t\t}\n+\n+\t\tif (ret_val) {\n+\t\t\thw_dbg(\"Shadow RAM write EEWR timed out\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR\n+ * @hw: pointer to the HW structure\n+ * @offset: offset within the Shadow RAM to be written to\n+ * @words: number of words to write\n+ * @data: 16 bit word(s) to be written to the Shadow RAM\n+ *\n+ * Writes data to Shadow RAM at offset using EEWR register.\n+ *\n+ * If igc_update_nvm_checksum is not called after this function , the\n+ * data will not be committed to FLASH and also Shadow RAM will most likely\n+ * contain an invalid checksum.\n+ *\n+ * If error code is returned, data and Shadow RAM may be inconsistent - buffer\n+ * partially written.\n+ */\n+static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,\n+\t\t\t\t   u16 *data)\n+{\n+\ts32 status = 0;\n+\tu16 i, count;\n+\n+\t/* We cannot hold synchronization semaphores for too long,\n+\t * because of forceful takeover procedure. However it is more efficient\n+\t * to write in bursts than synchronizing access for each word.\n+\t */\n+\tfor (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {\n+\t\tcount = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?\n+\t\t\tIGC_EERD_EEWR_MAX_COUNT : (words - i);\n+\n+\t\tstatus = hw->nvm.ops.acquire(hw);\n+\t\tif (status)\n+\t\t\tbreak;\n+\n+\t\tstatus = igc_write_nvm_srwr(hw, offset, count, data + i);\n+\t\thw->nvm.ops.release(hw);\n+\t\tif (status)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * igc_validate_nvm_checksum_i225 - Validate EEPROM checksum\n+ * @hw: pointer to the HW structure\n+ *\n+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM\n+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.\n+ */\n+static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)\n+{\n+\ts32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count,\n+\t\t\t   u16 *data);\n+\ts32 status = 0;\n+\n+\tstatus = hw->nvm.ops.acquire(hw);\n+\tif (status)\n+\t\tgoto out;\n+\n+\t/* Replace the read function with semaphore grabbing with\n+\t * the one that skips this for a while.\n+\t * We have semaphore taken already here.\n+\t */\n+\tread_op_ptr = hw->nvm.ops.read;\n+\thw->nvm.ops.read = igc_read_nvm_eerd;\n+\n+\tstatus = igc_validate_nvm_checksum(hw);\n+\n+\t/* Revert original read operation. */\n+\thw->nvm.ops.read = read_op_ptr;\n+\n+\thw->nvm.ops.release(hw);\n+\n+out:\n+\treturn status;\n+}\n+\n+/**\n+ * igc_pool_flash_update_done_i225 - Pool FLUDONE status\n+ * @hw: pointer to the HW structure\n+ */\n+static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)\n+{\n+\ts32 ret_val = -IGC_ERR_NVM;\n+\tu32 i, reg;\n+\n+\tfor (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {\n+\t\treg = rd32(IGC_EECD);\n+\t\tif (reg & IGC_EECD_FLUDONE_I225) {\n+\t\t\tret_val = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t\tudelay(5);\n+\t}\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_update_flash_i225 - Commit EEPROM to the flash\n+ * @hw: pointer to the HW structure\n+ */\n+static s32 igc_update_flash_i225(struct igc_hw *hw)\n+{\n+\ts32 ret_val = 0;\n+\tu32 flup;\n+\n+\tret_val = igc_pool_flash_update_done_i225(hw);\n+\tif (ret_val == -IGC_ERR_NVM) {\n+\t\thw_dbg(\"Flash update time out\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tflup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225;\n+\twr32(IGC_EECD, flup);\n+\n+\tret_val = igc_pool_flash_update_done_i225(hw);\n+\tif (ret_val)\n+\t\thw_dbg(\"Flash update time out\\n\");\n+\telse\n+\t\thw_dbg(\"Flash update complete\\n\");\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_update_nvm_checksum_i225 - Update EEPROM checksum\n+ * @hw: pointer to the HW structure\n+ *\n+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM\n+ * up to the checksum.  Then calculates the EEPROM checksum and writes the\n+ * value to the EEPROM. Next commit EEPROM data onto the Flash.\n+ */\n+static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)\n+{\n+\tu16 checksum = 0;\n+\ts32 ret_val = 0;\n+\tu16 i, nvm_data;\n+\n+\t/* Read the first word from the EEPROM. If this times out or fails, do\n+\t * not continue or we could be in for a very long wait while every\n+\t * EEPROM read fails\n+\t */\n+\tret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);\n+\tif (ret_val) {\n+\t\thw_dbg(\"EEPROM read failed\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tret_val = hw->nvm.ops.acquire(hw);\n+\tif (ret_val)\n+\t\tgoto out;\n+\n+\t/* Do not use hw->nvm.ops.write, hw->nvm.ops.read\n+\t * because we do not want to take the synchronization\n+\t * semaphores twice here.\n+\t */\n+\n+\tfor (i = 0; i < NVM_CHECKSUM_REG; i++) {\n+\t\tret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);\n+\t\tif (ret_val) {\n+\t\t\thw->nvm.ops.release(hw);\n+\t\t\thw_dbg(\"NVM Read Error while updating checksum.\\n\");\n+\t\t\tgoto out;\n+\t\t}\n+\t\tchecksum += nvm_data;\n+\t}\n+\tchecksum = (u16)NVM_SUM - checksum;\n+\tret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,\n+\t\t\t\t     &checksum);\n+\tif (ret_val) {\n+\t\thw->nvm.ops.release(hw);\n+\t\thw_dbg(\"NVM Write Error while updating checksum.\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\thw->nvm.ops.release(hw);\n+\n+\tret_val = igc_update_flash_i225(hw);\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_get_flash_presence_i225 - Check if flash device is detected\n+ * @hw: pointer to the HW structure\n+ */\n+bool igc_get_flash_presence_i225(struct igc_hw *hw)\n+{\n+\tbool ret_val = false;\n+\tu32 eec = 0;\n+\n+\teec = rd32(IGC_EECD);\n+\tif (eec & IGC_EECD_FLASH_DETECTED_I225)\n+\t\tret_val = true;\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_init_nvm_params_i225 - Init NVM func ptrs.\n+ * @hw: pointer to the HW structure\n+ */\n+s32 igc_init_nvm_params_i225(struct igc_hw *hw)\n+{\n+\tstruct igc_nvm_info *nvm = &hw->nvm;\n+\n+\tnvm->ops.acquire = igc_acquire_nvm_i225;\n+\tnvm->ops.release = igc_release_nvm_i225;\n+\n+\t/* NVM Function Pointers */\n+\tif (igc_get_flash_presence_i225(hw)) {\n+\t\thw->nvm.type = igc_nvm_flash_hw;\n+\t\tnvm->ops.read = igc_read_nvm_srrd_i225;\n+\t\tnvm->ops.write = igc_write_nvm_srwr_i225;\n+\t\tnvm->ops.validate = igc_validate_nvm_checksum_i225;\n+\t\tnvm->ops.update = igc_update_nvm_checksum_i225;\n+\t} else {\n+\t\thw->nvm.type = igc_nvm_invm;\n+\t\tnvm->ops.read = igc_read_nvm_eerd;\n+\t\tnvm->ops.write = NULL;\n+\t\tnvm->ops.validate = NULL;\n+\t\tnvm->ops.update = NULL;\n+\t}\n+\treturn 0;\n+}\ndiff --git a/drivers/net/ethernet/intel/igc/igc_i225.h b/drivers/net/ethernet/intel/igc/igc_i225.h\nindex 461cd8c7e352..7b66e1f9c0e6 100644\n--- a/drivers/net/ethernet/intel/igc/igc_i225.h\n+++ b/drivers/net/ethernet/intel/igc/igc_i225.h\n@@ -7,4 +7,7 @@\n s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask);\n void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask);\n \n+s32 igc_init_nvm_params_i225(struct igc_hw *hw);\n+bool igc_get_flash_presence_i225(struct igc_hw *hw);\n+\n #endif\ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c\nindex 90a98ee14550..249ac03b05d8 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.c\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.c\n@@ -275,6 +275,129 @@ void igc_clear_hw_cntrs_base(struct igc_hw *hw)\n }\n \n /**\n+ * igc_rar_set - Set receive address register\n+ * @hw: pointer to the HW structure\n+ * @addr: pointer to the receive address\n+ * @index: receive address array register\n+ *\n+ * Sets the receive address array register at index to the address passed\n+ * in by addr.\n+ */\n+void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)\n+{\n+\tu32 rar_low, rar_high;\n+\n+\t/* HW expects these in little endian so we reverse the byte order\n+\t * from network order (big endian) to little endian\n+\t */\n+\trar_low = ((u32)addr[0] |\n+\t\t   ((u32)addr[1] << 8) |\n+\t\t   ((u32)addr[2] << 16) | ((u32)addr[3] << 24));\n+\n+\trar_high = ((u32)addr[4] | ((u32)addr[5] << 8));\n+\n+\t/* If MAC address zero, no need to set the AV bit */\n+\tif (rar_low || rar_high)\n+\t\trar_high |= IGC_RAH_AV;\n+\n+\t/* Some bridges will combine consecutive 32-bit writes into\n+\t * a single burst write, which will malfunction on some parts.\n+\t * The flushes avoid this.\n+\t */\n+\twr32(IGC_RAL(index), rar_low);\n+\twrfl();\n+\twr32(IGC_RAH(index), rar_high);\n+\twrfl();\n+}\n+\n+/**\n+ * igc_check_for_copper_link - Check for link (Copper)\n+ * @hw: pointer to the HW structure\n+ *\n+ * Checks to see of the link status of the hardware has changed.  If a\n+ * change in link status has been detected, then we read the PHY registers\n+ * to get the current speed/duplex if link exists.\n+ */\n+s32 igc_check_for_copper_link(struct igc_hw *hw)\n+{\n+\tstruct igc_mac_info *mac = &hw->mac;\n+\ts32 ret_val;\n+\tbool link;\n+\n+\t/* We only want to go out to the PHY registers to see if Auto-Neg\n+\t * has completed and/or if our link status has changed.  The\n+\t * get_link_status flag is set upon receiving a Link Status\n+\t * Change or Rx Sequence Error interrupt.\n+\t */\n+\tif (!mac->get_link_status) {\n+\t\tret_val = 0;\n+\t\tgoto out;\n+\t}\n+\n+\t/* First we want to see if the MII Status Register reports\n+\t * link.  If so, then we want to get the current speed/duplex\n+\t * of the PHY.\n+\t */\n+\tif (ret_val)\n+\t\tgoto out;\n+\n+\tif (!link)\n+\t\tgoto out; /* No link detected */\n+\n+\tmac->get_link_status = false;\n+\n+\t/* Check if there was DownShift, must be checked\n+\t * immediately after link-up\n+\t */\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+\t */\n+\tif (!mac->autoneg) {\n+\t\tret_val = -IGC_ERR_CONFIG;\n+\t\tgoto out;\n+\t}\n+\n+\t/* Auto-Neg is enabled.  Auto Speed Detection takes care\n+\t * of MAC speed/duplex configuration.  So we only need to\n+\t * configure Collision Distance in the MAC.\n+\t */\n+\tigc_config_collision_dist(hw);\n+\n+\t/* Configure Flow Control now that Auto-Neg has completed.\n+\t * First, we need to restore the desired flow control\n+\t * settings because we may have had to re-autoneg with a\n+\t * different link partner.\n+\t */\n+\tif (ret_val)\n+\t\thw_dbg(\"Error configuring flow control\\n\");\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_config_collision_dist - Configure collision distance\n+ * @hw: pointer to the HW structure\n+ *\n+ * Configures the collision distance to the default value and is used\n+ * during link setup. Currently no func pointer exists and all\n+ * implementations are handled in the generic version of this function.\n+ */\n+void igc_config_collision_dist(struct igc_hw *hw)\n+{\n+\tu32 tctl;\n+\n+\ttctl = rd32(IGC_TCTL);\n+\n+\ttctl &= ~IGC_TCTL_COLD;\n+\ttctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;\n+\n+\twr32(IGC_TCTL, tctl);\n+\twrfl();\n+}\n+\n+/**\n  * igc_get_auto_rd_done - Check for auto read completion\n  * @hw: pointer to the HW structure\n  *\n@@ -303,6 +426,53 @@ s32 igc_get_auto_rd_done(struct igc_hw *hw)\n }\n \n /**\n+ * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex\n+ * @hw: pointer to the HW structure\n+ * @speed: stores the current speed\n+ * @duplex: stores the current duplex\n+ *\n+ * Read the status register for the current speed/duplex and store the current\n+ * speed and duplex for copper connections.\n+ */\n+s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,\n+\t\t\t\t    u16 *duplex)\n+{\n+\tu32 status;\n+\n+\tstatus = rd32(IGC_STATUS);\n+\tif (status & IGC_STATUS_SPEED_1000) {\n+\t\t/* For I225, STATUS will indicate 1G speed in both 1 Gbps\n+\t\t * and 2.5 Gbps link modes. An additional bit is used\n+\t\t * to differentiate between 1 Gbps and 2.5 Gbps.\n+\t\t */\n+\t\tif (hw->mac.type == igc_i225 &&\n+\t\t    (status & IGC_STATUS_SPEED_2500)) {\n+\t\t\t*speed = SPEED_2500;\n+\t\t\thw_dbg(\"2500 Mbs, \");\n+\t\t} else {\n+\t\t\t*speed = SPEED_1000;\n+\t\t\thw_dbg(\"1000 Mbs, \");\n+\t\t}\n+\t} else if (status & IGC_STATUS_SPEED_100) {\n+\t\t*speed = SPEED_100;\n+\t\thw_dbg(\"100 Mbs, \");\n+\t} else {\n+\t\t*speed = SPEED_10;\n+\t\thw_dbg(\"10 Mbs, \");\n+\t}\n+\n+\tif (status & IGC_STATUS_FD) {\n+\t\t*duplex = FULL_DUPLEX;\n+\t\thw_dbg(\"Full Duplex\\n\");\n+\t} else {\n+\t\t*duplex = HALF_DUPLEX;\n+\t\thw_dbg(\"Half Duplex\\n\");\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n  * igc_put_hw_semaphore - Release hardware semaphore\n  * @hw: pointer to the HW structure\n  *\ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h\nindex 88bdb8dd6f3f..88599661d017 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.h\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.h\n@@ -13,10 +13,16 @@\n \n /* forward declaration */\n s32 igc_disable_pcie_master(struct igc_hw *hw);\n+s32 igc_check_for_copper_link(struct igc_hw *hw);\n void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);\n s32 igc_setup_link(struct igc_hw *hw);\n void igc_clear_hw_cntrs_base(struct igc_hw *hw);\n s32 igc_get_auto_rd_done(struct igc_hw *hw);\n void igc_put_hw_semaphore(struct igc_hw *hw);\n+void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);\n+void igc_config_collision_dist(struct igc_hw *hw);\n+\n+s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,\n+\t\t\t\t    u16 *duplex);\n \n #endif\ndiff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c\nindex f2ad49fcd39b..115fc2a544d7 100644\n--- a/drivers/net/ethernet/intel/igc/igc_main.c\n+++ b/drivers/net/ethernet/intel/igc/igc_main.c\n@@ -27,9 +27,13 @@ static const char igc_driver_string[] = DRV_SUMMARY;\n static const char igc_copyright[] =\n \t\"Copyright(c) 2018 Intel Corporation.\";\n \n+static const struct igc_info *igc_info_tbl[] = {\n+\t[board_base] = &igc_base_info,\n+};\n+\n static const struct pci_device_id igc_pci_tbl[] = {\n-\t{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM) },\n-\t{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V) },\n+\t{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM), board_base },\n+\t{ PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V), board_base },\n \t/* required last entry */\n \t{0, }\n };\n@@ -3289,6 +3293,7 @@ static int igc_probe(struct pci_dev *pdev,\n \tstruct igc_adapter *adapter;\n \tstruct net_device *netdev;\n \tstruct igc_hw *hw;\n+\tconst struct igc_info *ei = igc_info_tbl[ent->driver_data];\n \tint err, pci_using_dac;\n \n \terr = pci_enable_device_mem(pdev);\n@@ -3370,6 +3375,14 @@ static int igc_probe(struct pci_dev *pdev,\n \thw->subsystem_vendor_id = pdev->subsystem_vendor;\n \thw->subsystem_device_id = pdev->subsystem_device;\n \n+\t/* Copy the default MAC and PHY function pointers */\n+\tmemcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));\n+\n+\t/* Initialize skew-specific constants */\n+\terr = ei->get_invariants(hw);\n+\tif (err)\n+\t\tgoto err_sw_init;\n+\n \t/* setup the private structure */\n \terr = igc_sw_init(adapter);\n \tif (err)\n@@ -3403,6 +3416,9 @@ static int igc_probe(struct pci_dev *pdev,\n \t /* carrier off reporting is important to ethtool even BEFORE open */\n \tnetif_carrier_off(netdev);\n \n+\t/* Check if Media Autosense is enabled */\n+\tadapter->ei = *ei;\n+\n \t/* print pcie link status and MAC address */\n \tpcie_print_link_status(pdev);\n \tnetdev_info(netdev, \"MAC: %pM\\n\", netdev->dev_addr);\ndiff --git a/drivers/net/ethernet/intel/igc/igc_nvm.c b/drivers/net/ethernet/intel/igc/igc_nvm.c\nnew file mode 100644\nindex 000000000000..58f81aba0144\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igc/igc_nvm.c\n@@ -0,0 +1,215 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (c)  2018 Intel Corporation */\n+\n+#include \"igc_mac.h\"\n+#include \"igc_nvm.h\"\n+\n+/**\n+ * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion\n+ * @hw: pointer to the HW structure\n+ * @ee_reg: EEPROM flag for polling\n+ *\n+ * Polls the EEPROM status bit for either read or write completion based\n+ * upon the value of 'ee_reg'.\n+ */\n+static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)\n+{\n+\ts32 ret_val = -IGC_ERR_NVM;\n+\tu32 attempts = 100000;\n+\tu32 i, reg = 0;\n+\n+\tfor (i = 0; i < attempts; i++) {\n+\t\tif (ee_reg == IGC_NVM_POLL_READ)\n+\t\t\treg = rd32(IGC_EERD);\n+\t\telse\n+\t\t\treg = rd32(IGC_EEWR);\n+\n+\t\tif (reg & IGC_NVM_RW_REG_DONE) {\n+\t\t\tret_val = 0;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tudelay(5);\n+\t}\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_acquire_nvm - Generic request for access to EEPROM\n+ * @hw: pointer to the HW structure\n+ *\n+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.\n+ * Return successful if access grant bit set, else clear the request for\n+ * EEPROM access and return -IGC_ERR_NVM (-1).\n+ */\n+s32 igc_acquire_nvm(struct igc_hw *hw)\n+{\n+\ts32 timeout = IGC_NVM_GRANT_ATTEMPTS;\n+\tu32 eecd = rd32(IGC_EECD);\n+\ts32 ret_val = 0;\n+\n+\twr32(IGC_EECD, eecd | IGC_EECD_REQ);\n+\teecd = rd32(IGC_EECD);\n+\n+\twhile (timeout) {\n+\t\tif (eecd & IGC_EECD_GNT)\n+\t\t\tbreak;\n+\t\tudelay(5);\n+\t\teecd = rd32(IGC_EECD);\n+\t\ttimeout--;\n+\t}\n+\n+\tif (!timeout) {\n+\t\teecd &= ~IGC_EECD_REQ;\n+\t\twr32(IGC_EECD, eecd);\n+\t\thw_dbg(\"Could not acquire NVM grant\\n\");\n+\t\tret_val = -IGC_ERR_NVM;\n+\t}\n+\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_release_nvm - Release exclusive access to EEPROM\n+ * @hw: pointer to the HW structure\n+ *\n+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.\n+ */\n+void igc_release_nvm(struct igc_hw *hw)\n+{\n+\tu32 eecd;\n+\n+\teecd = rd32(IGC_EECD);\n+\teecd &= ~IGC_EECD_REQ;\n+\twr32(IGC_EECD, eecd);\n+}\n+\n+/**\n+ * igc_read_nvm_eerd - Reads EEPROM using EERD register\n+ * @hw: pointer to the HW structure\n+ * @offset: offset of word in the EEPROM to read\n+ * @words: number of words to read\n+ * @data: word read from the EEPROM\n+ *\n+ * Reads a 16 bit word from the EEPROM using the EERD register.\n+ */\n+s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data)\n+{\n+\tstruct igc_nvm_info *nvm = &hw->nvm;\n+\tu32 i, eerd = 0;\n+\ts32 ret_val = 0;\n+\n+\t/* A check for invalid values:  offset too large, too many words,\n+\t * and not enough words.\n+\t */\n+\tif (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||\n+\t    words == 0) {\n+\t\thw_dbg(\"nvm parameter(s) out of bounds\\n\");\n+\t\tret_val = -IGC_ERR_NVM;\n+\t\tgoto out;\n+\t}\n+\n+\tfor (i = 0; i < words; i++) {\n+\t\teerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +\n+\t\t\tIGC_NVM_RW_REG_START;\n+\n+\t\twr32(IGC_EERD, eerd);\n+\t\tret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);\n+\t\tif (ret_val)\n+\t\t\tbreak;\n+\n+\t\tdata[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);\n+\t}\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_read_mac_addr - Read device MAC address\n+ * @hw: pointer to the HW structure\n+ */\n+s32 igc_read_mac_addr(struct igc_hw *hw)\n+{\n+\tu32 rar_high;\n+\tu32 rar_low;\n+\tu16 i;\n+\n+\trar_high = rd32(IGC_RAH(0));\n+\trar_low = rd32(IGC_RAL(0));\n+\n+\tfor (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)\n+\t\thw->mac.perm_addr[i] = (u8)(rar_low >> (i * 8));\n+\n+\tfor (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)\n+\t\thw->mac.perm_addr[i + 4] = (u8)(rar_high >> (i * 8));\n+\n+\tfor (i = 0; i < ETH_ALEN; i++)\n+\t\thw->mac.addr[i] = hw->mac.perm_addr[i];\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * igc_validate_nvm_checksum - Validate EEPROM checksum\n+ * @hw: pointer to the HW structure\n+ *\n+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM\n+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.\n+ */\n+s32 igc_validate_nvm_checksum(struct igc_hw *hw)\n+{\n+\tu16 checksum = 0;\n+\tu16 i, nvm_data;\n+\ts32 ret_val = 0;\n+\n+\tfor (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {\n+\t\tret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);\n+\t\tif (ret_val) {\n+\t\t\thw_dbg(\"NVM Read Error\\n\");\n+\t\t\tgoto out;\n+\t\t}\n+\t\tchecksum += nvm_data;\n+\t}\n+\n+\tif (checksum != (u16)NVM_SUM) {\n+\t\thw_dbg(\"NVM Checksum Invalid\\n\");\n+\t\tret_val = -IGC_ERR_NVM;\n+\t\tgoto out;\n+\t}\n+\n+out:\n+\treturn ret_val;\n+}\n+\n+/**\n+ * igc_update_nvm_checksum - Update EEPROM checksum\n+ * @hw: pointer to the HW structure\n+ *\n+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM\n+ * up to the checksum.  Then calculates the EEPROM checksum and writes the\n+ * value to the EEPROM.\n+ */\n+s32 igc_update_nvm_checksum(struct igc_hw *hw)\n+{\n+\tu16 checksum = 0;\n+\tu16 i, nvm_data;\n+\ts32  ret_val;\n+\n+\tfor (i = 0; i < NVM_CHECKSUM_REG; i++) {\n+\t\tret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);\n+\t\tif (ret_val) {\n+\t\t\thw_dbg(\"NVM Read Error while updating checksum.\\n\");\n+\t\t\tgoto out;\n+\t\t}\n+\t\tchecksum += nvm_data;\n+\t}\n+\tchecksum = (u16)NVM_SUM - checksum;\n+\tret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);\n+\tif (ret_val)\n+\t\thw_dbg(\"NVM Write Error while updating checksum.\\n\");\n+\n+out:\n+\treturn ret_val;\n+}\ndiff --git a/drivers/net/ethernet/intel/igc/igc_nvm.h b/drivers/net/ethernet/intel/igc/igc_nvm.h\nnew file mode 100644\nindex 000000000000..f9fc2e9cfb03\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igc/igc_nvm.h\n@@ -0,0 +1,14 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (c)  2018 Intel Corporation */\n+\n+#ifndef _IGC_NVM_H_\n+#define _IGC_NVM_H_\n+\n+s32 igc_acquire_nvm(struct igc_hw *hw);\n+void igc_release_nvm(struct igc_hw *hw);\n+s32 igc_read_mac_addr(struct igc_hw *hw);\n+s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data);\n+s32 igc_validate_nvm_checksum(struct igc_hw *hw);\n+s32 igc_update_nvm_checksum(struct igc_hw *hw);\n+\n+#endif\ndiff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h\nindex c57f573fb864..b5996e474c3c 100644\n--- a/drivers/net/ethernet/intel/igc/igc_regs.h\n+++ b/drivers/net/ethernet/intel/igc/igc_regs.h\n@@ -191,6 +191,9 @@\n /* Management registers */\n #define IGC_MANC\t0x05820  /* Management Control - RW */\n \n+/* Shadow Ram Write Register - RW */\n+#define IGC_SRWR\t0x12018\n+\n /* forward declaration */\n struct igc_hw;\n u32 igc_rd32(struct igc_hw *hw, u32 reg);\n",
    "prefixes": [
        "v8",
        "08/11"
    ]
}