get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 96748,
    "url": "http://patchwork.dpdk.org/api/patches/96748/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20210810025140.1698163-10-qi.z.zhang@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210810025140.1698163-10-qi.z.zhang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210810025140.1698163-10-qi.z.zhang@intel.com",
    "date": "2021-08-10T02:51:21",
    "name": "[09/28] net/ice/base: implement Vernier calibration logic for E822 devices",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "318631781683b87beebeff5ca16c41cb35ae3108",
    "submitter": {
        "id": 504,
        "url": "http://patchwork.dpdk.org/api/people/504/?format=api",
        "name": "Qi Zhang",
        "email": "qi.z.zhang@intel.com"
    },
    "delegate": {
        "id": 1540,
        "url": "http://patchwork.dpdk.org/api/users/1540/?format=api",
        "username": "qzhan15",
        "first_name": "Qi",
        "last_name": "Zhang",
        "email": "qi.z.zhang@intel.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20210810025140.1698163-10-qi.z.zhang@intel.com/mbox/",
    "series": [
        {
            "id": 18242,
            "url": "http://patchwork.dpdk.org/api/series/18242/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=18242",
            "date": "2021-08-10T02:51:12",
            "name": "ice: base code update",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/18242/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/96748/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/96748/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 5F35AA0C54;\n\tTue, 10 Aug 2021 04:49:35 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 6E3AA41167;\n\tTue, 10 Aug 2021 04:48:57 +0200 (CEST)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n by mails.dpdk.org (Postfix) with ESMTP id 7884B41192\n for <dev@dpdk.org>; Tue, 10 Aug 2021 04:48:55 +0200 (CEST)",
            "from fmsmga008.fm.intel.com ([10.253.24.58])\n by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 09 Aug 2021 19:48:55 -0700",
            "from dpdk51.sh.intel.com ([10.67.111.142])\n by fmsmga008.fm.intel.com with ESMTP; 09 Aug 2021 19:48:52 -0700"
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10070\"; a=\"214808433\"",
            "E=Sophos;i=\"5.84,309,1620716400\"; d=\"scan'208\";a=\"214808433\"",
            "E=Sophos;i=\"5.84,309,1620716400\"; d=\"scan'208\";a=\"483823611\""
        ],
        "X-ExtLoop1": "1",
        "From": "Qi Zhang <qi.z.zhang@intel.com>",
        "To": "qiming.yang@intel.com",
        "Cc": "junfeng.guo@intel.com, dev@dpdk.org, Qi Zhang <qi.z.zhang@intel.com>,\n Jacob Keller <jacob.e.keller@intel.com>",
        "Date": "Tue, 10 Aug 2021 10:51:21 +0800",
        "Message-Id": "<20210810025140.1698163-10-qi.z.zhang@intel.com>",
        "X-Mailer": "git-send-email 2.26.2",
        "In-Reply-To": "<20210810025140.1698163-1-qi.z.zhang@intel.com>",
        "References": "<20210810025140.1698163-1-qi.z.zhang@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH 09/28] net/ice/base: implement Vernier\n calibration logic for E822 devices",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Move the implementation of Vernier calibration from Linux core ice_ptp.c\ninto the shared ice_ptp_hw.c file.\n\nThis implementation was recently refactored in Linux, so the move should\nbe verbatim with the latest Linux code that we had implemented.\n\nThis includes a new constant table with pre-determined values based on\nlink speed, new functions to aide in reading the multi-register values\nfrom the PHY, functions to program the PAR/PCS conversion ratios, and\nthe UIX conversion ratios, functions to program the total Tx and Rx\noffset after vernier calibration in the hardware completes, and finally\na function to start and stop the PHY timestamping block.\n\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\nSigned-off-by: Qi Zhang <qi.z.zhang@intel.com>\n---\n drivers/net/ice/base/ice_ptp_consts.h | 216 ++++++\n drivers/net/ice/base/ice_ptp_hw.c     | 999 ++++++++++++++++++++++++++\n drivers/net/ice/base/ice_ptp_hw.h     |  47 ++\n 3 files changed, 1262 insertions(+)",
    "diff": "diff --git a/drivers/net/ice/base/ice_ptp_consts.h b/drivers/net/ice/base/ice_ptp_consts.h\nindex 4583dd42ff..32eb60ab48 100644\n--- a/drivers/net/ice/base/ice_ptp_consts.h\n+++ b/drivers/net/ice/base/ice_ptp_consts.h\n@@ -157,4 +157,220 @@ const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = {\n \t},\n };\n \n+/* struct ice_vernier_info_e822\n+ *\n+ * E822 hardware calibrates the delay of the timestamp indication from the\n+ * actual packet transmission or reception during the initialization of the\n+ * PHY. To do this, the hardware mechanism uses some conversions between the\n+ * various clocks within the PHY block. This table defines constants used to\n+ * calculate the correct conversion ratios in the PHY registers.\n+ *\n+ * Many of the values relate to the PAR/PCS clock conversion registers. For\n+ * these registers, a value of 0 means that the associated register is not\n+ * used by this link speed, and that the register should be cleared by writing\n+ * 0. Other values specify the clock frequency in Hz.\n+ */\n+const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD] = {\n+\t/* ICE_PTP_LNK_SPD_1G */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t31250000, /* 31.25 MHz */\n+\t\t/* rx_par_clk */\n+\t\t31250000, /* 31.25 MHz */\n+\t\t/* tx_pcs_clk */\n+\t\t125000000, /* 125 MHz */\n+\t\t/* rx_pcs_clk */\n+\t\t125000000, /* 125 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* tx_fixed_delay */\n+\t\t25140,\n+\t\t/* pmd_adj_divisor */\n+\t\t10000000,\n+\t\t/* rx_fixed_delay */\n+\t\t17372,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_10G */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t257812500, /* 257.8125 MHz */\n+\t\t/* rx_par_clk */\n+\t\t257812500, /* 257.8125 MHz */\n+\t\t/* tx_pcs_clk */\n+\t\t156250000, /* 156.25 MHz */\n+\t\t/* rx_pcs_clk */\n+\t\t156250000, /* 156.25 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* tx_fixed_delay */\n+\t\t6938,\n+\t\t/* pmd_adj_divisor */\n+\t\t82500000,\n+\t\t/* rx_fixed_delay */\n+\t\t6212,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_25G */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t644531250, /* 644.53125 MHZ */\n+\t\t/* rx_par_clk */\n+\t\t644531250, /* 644.53125 MHz */\n+\t\t/* tx_pcs_clk */\n+\t\t390625000, /* 390.625 MHz */\n+\t\t/* rx_pcs_clk */\n+\t\t390625000, /* 390.625 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* tx_fixed_delay */\n+\t\t2778,\n+\t\t/* pmd_adj_divisor */\n+\t\t206250000,\n+\t\t/* rx_fixed_delay */\n+\t\t2491,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_25G_RS */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t0, /* unused */\n+\t\t/* rx_par_clk */\n+\t\t0, /* unused */\n+\t\t/* tx_pcs_clk */\n+\t\t0, /* unused */\n+\t\t/* rx_pcs_clk */\n+\t\t0, /* unused */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t161132812, /* 162.1328125 MHz Reed Solomon gearbox */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t161132812, /* 162.1328125 MHz Reed Solomon gearbox */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t97656250, /* 97.62625 MHz Reed Solomon gearbox */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t97656250, /* 97.62625 MHz Reed Solomon gearbox */\n+\t\t/* tx_fixed_delay */\n+\t\t3928,\n+\t\t/* pmd_adj_divisor */\n+\t\t206250000,\n+\t\t/* rx_fixed_delay */\n+\t\t29535,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_40G */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t257812500,\n+\t\t/* rx_par_clk */\n+\t\t257812500,\n+\t\t/* tx_pcs_clk */\n+\t\t156250000, /* 156.25 MHz */\n+\t\t/* rx_pcs_clk */\n+\t\t156250000, /* 156.25 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t156250000, /* 156.25 MHz deskew clock */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t156250000, /* 156.25 MHz deskew clock */\n+\t\t/* tx_fixed_delay */\n+\t\t5666,\n+\t\t/* pmd_adj_divisor */\n+\t\t82500000,\n+\t\t/* rx_fixed_delay */\n+\t\t4244,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_50G */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t644531250, /* 644.53125 MHZ */\n+\t\t/* rx_par_clk */\n+\t\t644531250, /* 644.53125 MHZ */\n+\t\t/* tx_pcs_clk */\n+\t\t390625000, /* 390.625 MHz */\n+\t\t/* rx_pcs_clk */\n+\t\t390625000, /* 390.625 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t195312500, /* 193.3125 MHz deskew clock */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t0, /* unused */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t195312500, /* 193.3125 MHz deskew clock */\n+\t\t/* tx_fixed_delay */\n+\t\t2778,\n+\t\t/* pmd_adj_divisor */\n+\t\t206250000,\n+\t\t/* rx_fixed_delay */\n+\t\t2868,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_50G_RS */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t0, /* unused */\n+\t\t/* rx_par_clk */\n+\t\t644531250, /* 644.53125 MHz */\n+\t\t/* tx_pcs_clk */\n+\t\t0, /* unused */\n+\t\t/* rx_pcs_clk */\n+\t\t644531250, /* 644.53125 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t322265625, /* 322.265625 MHz Reed Solomon gearbox */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t322265625, /* 322.265625 MHz Reed Solomon gearbox */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t644531250, /* 644.53125 MHz Reed Solomon gearbox */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t644531250, /* 644.53125 MHz Reed Solomon gearbox */\n+\t\t/* tx_fixed_delay */\n+\t\t2095,\n+\t\t/* pmd_adj_divisor */\n+\t\t206250000,\n+\t\t/* rx_fixed_delay */\n+\t\t14524,\n+\t},\n+\t/* ICE_PTP_LNK_SPD_100G_RS */\n+\t{\n+\t\t/* tx_par_clk */\n+\t\t0, /* unused */\n+\t\t/* rx_par_clk */\n+\t\t644531250, /* 644.53125 MHz */\n+\t\t/* tx_pcs_clk */\n+\t\t0, /* unused */\n+\t\t/* rx_pcs_clk */\n+\t\t644531250, /* 644.53125 MHz */\n+\t\t/* tx_desk_rsgb_par */\n+\t\t644531250, /* 644.53125 MHz Reed Solomon gearbox */\n+\t\t/* rx_desk_rsgb_par */\n+\t\t644531250, /* 644.53125 MHz Reed Solomon gearbox */\n+\t\t/* tx_desk_rsgb_pcs */\n+\t\t644531250, /* 644.53125 MHz Reed Solomon gearbox */\n+\t\t/* rx_desk_rsgb_pcs */\n+\t\t644531250, /* 644.53125 MHz Reed Solomon gearbox */\n+\t\t/* tx_fixed_delay */\n+\t\t1620,\n+\t\t/* pmd_adj_divisor */\n+\t\t206250000,\n+\t\t/* rx_fixed_delay */\n+\t\t7775,\n+\t},\n+};\n+\n #endif /* _ICE_PTP_CONSTS_H_ */\ndiff --git a/drivers/net/ice/base/ice_ptp_hw.c b/drivers/net/ice/base/ice_ptp_hw.c\nindex cb32a4fb48..bf6889029a 100644\n--- a/drivers/net/ice/base/ice_ptp_hw.c\n+++ b/drivers/net/ice/base/ice_ptp_hw.c\n@@ -1573,6 +1573,1005 @@ void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)\n \t}\n }\n \n+/**\n+ * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822\n+ * @hw: pointer to the HW structure\n+ * @port: the port to configure\n+ *\n+ * Program the conversion ration of Serdes clock \"unit intervals\" (UIs) to PHC\n+ * hardware clock time units (TUs). That is, determine the number of TUs per\n+ * serdes unit interval, and program the UIX registers with this conversion.\n+ *\n+ * This conversion is used as part of the calibration process when determining\n+ * the additional error of a timestamp vs the real time of transmission or\n+ * receipt of the packet.\n+ *\n+ * Hardware uses the number of TUs per 66 UIs, written to the UIX registers\n+ * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks.\n+ *\n+ * To calculate the conversion ratio, we use the following facts:\n+ *\n+ * a) the clock frequency in Hz (cycles per second)\n+ * b) the number of TUs per cycle (the increment value of the clock)\n+ * c) 1 second per 1 billion nanoseconds\n+ * d) the duration of 66 UIs in nanoseconds\n+ *\n+ * Given these facts, we can use the following table to work out what ratios\n+ * to multiply in order to get the number of TUs per 66 UIs:\n+ *\n+ * cycles |   1 second   | incval (TUs) | nanoseconds\n+ * -------+--------------+--------------+-------------\n+ * second | 1 billion ns |    cycle     |   66 UIs\n+ *\n+ * To perform the multiplication using integers without too much loss of\n+ * precision, we can take use the following equation:\n+ *\n+ * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion)\n+ *\n+ * We scale up to using 6600 UI instead of 66 in order to avoid fractional\n+ * nanosecond UIs (66 UI at 10G/40G is 6.4 ns)\n+ *\n+ * The increment value has a maximum expected range of about 34 bits, while\n+ * the frequency value is about 29 bits. Multiplying these values shouldn't\n+ * overflow the 64 bits. However, we must then further multiply them again by\n+ * the Serdes unit interval duration. To avoid overflow here, we split the\n+ * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and\n+ * a divide by 390,625,000. This does lose some precision, but avoids\n+ * miscalculation due to arithmetic overflow.\n+ */\n+static enum ice_status ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)\n+{\n+\tu64 cur_freq, clk_incval, tu_per_sec, uix;\n+\tenum ice_status status;\n+\n+\tcur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));\n+\tclk_incval = ice_ptp_read_src_incval(hw);\n+\n+\t/* Calculate TUs per second divided by 256 */\n+\ttu_per_sec = (cur_freq * clk_incval) >> 8;\n+\n+#define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */\n+#define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */\n+\n+\t/* Program the 10Gb/40Gb conversion ratio */\n+\tuix = (tu_per_sec * LINE_UI_10G_40G) / 390625000;\n+\n+\tstatus = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,\n+\t\t\t\t\t    uix);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write UIX66_10G_40G, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* Program the 25Gb/100Gb conversion ratio */\n+\tuix = (tu_per_sec * LINE_UI_25G_100G) / 390625000;\n+\n+\tstatus = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,\n+\t\t\t\t\t    uix);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write UIX66_25G_100G, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle\n+ * @hw: pointer to the HW struct\n+ * @port: port to configure\n+ *\n+ * Configure the number of TUs for the PAR and PCS clocks used as part of the\n+ * timestamp calibration process. This depends on the link speed, as the PHY\n+ * uses different markers depending on the speed.\n+ *\n+ * 1Gb/10Gb/25Gb:\n+ * - Tx/Rx PAR/PCS markers\n+ *\n+ * 25Gb RS:\n+ * - Tx/Rx Reed Solomon gearbox PAR/PCS markers\n+ *\n+ * 40Gb/50Gb:\n+ * - Tx/Rx PAR/PCS markers\n+ * - Rx Deskew PAR/PCS markers\n+ *\n+ * 50G RS and 100GB RS:\n+ * - Tx/Rx Reed Solomon gearbox PAR/PCS markers\n+ * - Rx Deskew PAR/PCS markers\n+ * - Tx PAR/PCS markers\n+ *\n+ * To calculate the conversion, we use the PHC clock frequency (cycles per\n+ * second), the increment value (TUs per cycle), and the related PHY clock\n+ * frequency to calculate the TUs per unit of the PHY link clock. The\n+ * following table shows how the units convert:\n+ *\n+ * cycles |  TUs  | second\n+ * -------+-------+--------\n+ * second | cycle | cycles\n+ *\n+ * For each conversion register, look up the appropriate frequency from the\n+ * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program\n+ * this to the appropriate register, preparing hardware to perform timestamp\n+ * calibration to calculate the total Tx or Rx offset to adjust the timestamp\n+ * in order to calibrate for the internal PHY delays.\n+ *\n+ * Note that the increment value ranges up to ~34 bits, and the clock\n+ * frequency is ~29 bits, so multiplying them together should fit within the\n+ * 64 bit arithmetic.\n+ */\n+static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)\n+{\n+\tu64 cur_freq, clk_incval, tu_per_sec, phy_tus;\n+\tenum ice_ptp_link_spd link_spd;\n+\tenum ice_ptp_fec_mode fec_mode;\n+\tenum ice_status status;\n+\n+\tstatus = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);\n+\tif (status)\n+\t\treturn status;\n+\n+\tcur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));\n+\tclk_incval = ice_ptp_read_src_incval(hw);\n+\n+\t/* Calculate TUs per cycle of the PHC clock */\n+\ttu_per_sec = cur_freq * clk_incval;\n+\n+\t/* For each PHY conversion register, look up the appropriate link\n+\t * speed frequency and determine the TUs per that clock's cycle time.\n+\t * Split this into a high and low value and then program the\n+\t * appropriate register. If that link speed does not use the\n+\t * associated register, write zeros to clear it instead.\n+\t */\n+\n+\t/* P_REG_PAR_TX_TUS */\n+\tif (e822_vernier[link_spd].tx_par_clk)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].tx_par_clk;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_PAR_RX_TUS */\n+\tif (e822_vernier[link_spd].rx_par_clk)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].rx_par_clk;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_PCS_TX_TUS */\n+\tif (e822_vernier[link_spd].tx_pcs_clk)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].tx_pcs_clk;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_PCS_RX_TUS */\n+\tif (e822_vernier[link_spd].rx_pcs_clk)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].rx_pcs_clk;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_DESK_PAR_TX_TUS */\n+\tif (e822_vernier[link_spd].tx_desk_rsgb_par)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].tx_desk_rsgb_par;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_DESK_PAR_RX_TUS */\n+\tif (e822_vernier[link_spd].rx_desk_rsgb_par)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].rx_desk_rsgb_par;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_DESK_PCS_TX_TUS */\n+\tif (e822_vernier[link_spd].tx_desk_rsgb_pcs)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].tx_desk_rsgb_pcs;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,\n+\t\t\t\t\t    phy_tus);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* P_REG_DESK_PCS_RX_TUS */\n+\tif (e822_vernier[link_spd].rx_desk_rsgb_pcs)\n+\t\tphy_tus = tu_per_sec / e822_vernier[link_spd].rx_desk_rsgb_pcs;\n+\telse\n+\t\tphy_tus = 0;\n+\n+\treturn ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,\n+\t\t\t\t\t  phy_tus);\n+}\n+\n+/**\n+ * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port\n+ * @hw: pointer to the HW struct\n+ * @link_spd: the Link speed to calculate for\n+ *\n+ * Calculate the fixed offset due to known static latency data.\n+ */\n+static u64\n+ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)\n+{\n+\tu64 cur_freq, clk_incval, tu_per_sec, fixed_offset;\n+\n+\tcur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));\n+\tclk_incval = ice_ptp_read_src_incval(hw);\n+\n+\t/* Calculate TUs per second */\n+\ttu_per_sec = cur_freq * clk_incval;\n+\n+\t/* Calculate number of TUs to add for the fixed Tx latency. Since the\n+\t * latency measurement is in 1/100th of a nanosecond, we need to\n+\t * multiply by tu_per_sec and then divide by 1e11. This calculation\n+\t * overflows 64 bit integer arithmetic, so break it up into two\n+\t * divisions by 1e4 first then by 1e7.\n+\t */\n+\tfixed_offset = tu_per_sec / 10000;\n+\tfixed_offset *= e822_vernier[link_spd].tx_fixed_delay;\n+\tfixed_offset /= 10000000;\n+\n+\treturn fixed_offset;\n+}\n+\n+/**\n+ * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to configure\n+ *\n+ * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to\n+ * adjust Tx timestamps by. This is calculated by combining some known static\n+ * latency along with the Vernier offset computations done by hardware.\n+ *\n+ * This function must be called only after the offset registers are valid,\n+ * i.e. after the Vernier calibration wait has passed, to ensure that the PHY\n+ * has measured the offset.\n+ *\n+ * To avoid overflow, when calculating the offset based on the known static\n+ * latency values, we use measurements in 1/100th of a nanosecond, and divide\n+ * the TUs per second up front. This avoids overflow while allowing\n+ * calculation of the adjustment using integer arithmetic.\n+ */\n+enum ice_status ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)\n+{\n+\tenum ice_ptp_link_spd link_spd;\n+\tenum ice_ptp_fec_mode fec_mode;\n+\tenum ice_status status;\n+\tu64 total_offset, val;\n+\n+\tstatus = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);\n+\tif (status)\n+\t\treturn status;\n+\n+\ttotal_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);\n+\n+\t/* Read the first Vernier offset from the PHY register and add it to\n+\t * the total offset.\n+\t */\n+\tif (link_spd == ICE_PTP_LNK_SPD_1G ||\n+\t    link_spd == ICE_PTP_LNK_SPD_10G ||\n+\t    link_spd == ICE_PTP_LNK_SPD_25G ||\n+\t    link_spd == ICE_PTP_LNK_SPD_25G_RS ||\n+\t    link_spd == ICE_PTP_LNK_SPD_40G ||\n+\t    link_spd == ICE_PTP_LNK_SPD_50G) {\n+\t\tstatus = ice_read_64b_phy_reg_e822(hw, port,\n+\t\t\t\t\t\t   P_REG_PAR_PCS_TX_OFFSET_L,\n+\t\t\t\t\t\t   &val);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\ttotal_offset += val;\n+\t}\n+\n+\t/* For Tx, we only need to use the second Vernier offset for\n+\t * multi-lane link speeds with RS-FEC. The lanes will always be\n+\t * aligned.\n+\t */\n+\tif (link_spd == ICE_PTP_LNK_SPD_50G_RS ||\n+\t    link_spd == ICE_PTP_LNK_SPD_100G_RS) {\n+\t\tstatus = ice_read_64b_phy_reg_e822(hw, port,\n+\t\t\t\t\t\t   P_REG_PAR_TX_TIME_L,\n+\t\t\t\t\t\t   &val);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\ttotal_offset += val;\n+\t}\n+\n+\t/* Now that the total offset has been calculated, program it to the\n+\t * PHY and indicate that the Tx offset is ready. After this,\n+\t * timestamps will be enabled.\n+\t */\n+\tstatus = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,\n+\t\t\t\t\t    total_offset);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to configure\n+ *\n+ * Calculate and program the fixed Tx offset, and indicate that the offset is\n+ * ready. This can be used when operating in bypass mode.\n+ */\n+static enum ice_status\n+ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port)\n+{\n+\tenum ice_ptp_link_spd link_spd;\n+\tenum ice_ptp_fec_mode fec_mode;\n+\tenum ice_status status;\n+\tu64 total_offset;\n+\n+\tstatus = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);\n+\tif (status)\n+\t\treturn status;\n+\n+\ttotal_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);\n+\n+\t/* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L\n+\t * register, then indicate that the Tx offset is ready. After this,\n+\t * timestamps will be enabled.\n+\t *\n+\t * Note that this skips including the more precise offsets generated\n+\t * by the Vernier calibration.\n+\t */\n+\tstatus = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,\n+\t\t\t\t\t    total_offset);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to adjust for\n+ * @link_spd: the current link speed of the PHY\n+ * @fec_mode: the current FEC mode of the PHY\n+ * @pmd_adj: on return, the amount to adjust the Rx total offset by\n+ *\n+ * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY.\n+ * This varies by link speed and FEC mode. The value calculated accounts for\n+ * various delays caused when receiving a packet.\n+ */\n+static enum ice_status\n+ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,\n+\t\t\t  enum ice_ptp_link_spd link_spd,\n+\t\t\t  enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj)\n+{\n+\tu64 cur_freq, clk_incval, tu_per_sec, mult, adj;\n+\tenum ice_status status;\n+\tu8 pmd_align;\n+\tu32 val;\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read PMD alignment, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tpmd_align = (u8)val;\n+\n+\tcur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));\n+\tclk_incval = ice_ptp_read_src_incval(hw);\n+\n+\t/* Calculate TUs per second */\n+\ttu_per_sec = cur_freq * clk_incval;\n+\n+\t/* The PMD alignment adjustment measurement depends on the link speed,\n+\t * and whether FEC is enabled. For each link speed, the alignment\n+\t * adjustment is calculated by dividing a value by the length of\n+\t * a Time Unit in nanoseconds.\n+\t *\n+\t * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8\n+\t * 10G: align == 65 ? 0 : (align * 0.1 * 32/33)\n+\t * 10G w/FEC: align * 0.1 * 32/33\n+\t * 25G: align == 65 ? 0 : (align * 0.4 * 32/33)\n+\t * 25G w/FEC: align * 0.4 * 32/33\n+\t * 40G: align == 65 ? 0 : (align * 0.1 * 32/33)\n+\t * 40G w/FEC: align * 0.1 * 32/33\n+\t * 50G: align == 65 ? 0 : (align * 0.4 * 32/33)\n+\t * 50G w/FEC: align * 0.8 * 32/33\n+\t *\n+\t * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33.\n+\t *\n+\t * To allow for calculating this value using integer arithmetic, we\n+\t * instead start with the number of TUs per second, (inverse of the\n+\t * length of a Time Unit in nanoseconds), multiply by a value based\n+\t * on the PMD alignment register, and then divide by the right value\n+\t * calculated based on the table above. To avoid integer overflow this\n+\t * division is broken up into a step of dividing by 125 first.\n+\t */\n+\tif (link_spd == ICE_PTP_LNK_SPD_1G) {\n+\t\tif (pmd_align == 4)\n+\t\t\tmult = 10;\n+\t\telse\n+\t\t\tmult = (pmd_align + 6) % 10;\n+\t} else if (link_spd == ICE_PTP_LNK_SPD_10G ||\n+\t\t   link_spd == ICE_PTP_LNK_SPD_25G ||\n+\t\t   link_spd == ICE_PTP_LNK_SPD_40G ||\n+\t\t   link_spd == ICE_PTP_LNK_SPD_50G) {\n+\t\t/* If Clause 74 FEC, always calculate PMD adjust */\n+\t\tif (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74)\n+\t\t\tmult = pmd_align;\n+\t\telse\n+\t\t\tmult = 0;\n+\t} else if (link_spd == ICE_PTP_LNK_SPD_25G_RS ||\n+\t\t   link_spd == ICE_PTP_LNK_SPD_50G_RS ||\n+\t\t   link_spd == ICE_PTP_LNK_SPD_100G_RS) {\n+\t\tif (pmd_align < 17)\n+\t\t\tmult = pmd_align + 40;\n+\t\telse\n+\t\t\tmult = pmd_align;\n+\t} else {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Unknown link speed %d, skipping PMD adjustment\\n\",\n+\t\t\t  link_spd);\n+\t\tmult = 0;\n+\t}\n+\n+\t/* In some cases, there's no need to adjust for the PMD alignment */\n+\tif (!mult) {\n+\t\t*pmd_adj = 0;\n+\t\treturn ICE_SUCCESS;\n+\t}\n+\n+\t/* Calculate the adjustment by multiplying TUs per second by the\n+\t * appropriate multiplier and divisor. To avoid overflow, we first\n+\t * divide by 125, and then handle remaining divisor based on the link\n+\t * speed pmd_adj_divisor value.\n+\t */\n+\tadj = tu_per_sec / 125;\n+\tadj *= mult;\n+\tadj /= e822_vernier[link_spd].pmd_adj_divisor;\n+\n+\t/* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx\n+\t * cycle count is necessary.\n+\t */\n+\tif (link_spd == ICE_PTP_LNK_SPD_25G_RS) {\n+\t\tu64 cycle_adj;\n+\t\tu8 rx_cycle;\n+\n+\t\tstatus = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT,\n+\t\t\t\t\t       &val);\n+\t\tif (status) {\n+\t\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read 25G-RS Rx cycle count, status %d\\n\",\n+\t\t\t\t  status);\n+\t\t\treturn status;\n+\t\t}\n+\n+\t\trx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M;\n+\t\tif (rx_cycle) {\n+\t\t\tmult = (4 - rx_cycle) * 40;\n+\n+\t\t\tcycle_adj = tu_per_sec / 125;\n+\t\t\tcycle_adj *= mult;\n+\t\t\tcycle_adj /= e822_vernier[link_spd].pmd_adj_divisor;\n+\n+\t\t\tadj += cycle_adj;\n+\t\t}\n+\t} else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) {\n+\t\tu64 cycle_adj;\n+\t\tu8 rx_cycle;\n+\n+\t\tstatus = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT,\n+\t\t\t\t\t       &val);\n+\t\tif (status) {\n+\t\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read 50G-RS Rx cycle count, status %d\\n\",\n+\t\t\t\t  status);\n+\t\t\treturn status;\n+\t\t}\n+\n+\t\trx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M;\n+\t\tif (rx_cycle) {\n+\t\t\tmult = rx_cycle * 40;\n+\n+\t\t\tcycle_adj = tu_per_sec / 125;\n+\t\t\tcycle_adj *= mult;\n+\t\t\tcycle_adj /= e822_vernier[link_spd].pmd_adj_divisor;\n+\n+\t\t\tadj += cycle_adj;\n+\t\t}\n+\t}\n+\n+\t/* Return the calculated adjustment */\n+\t*pmd_adj = adj;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port\n+ * @hw: pointer to HW struct\n+ * @link_spd: The Link speed to calculate for\n+ *\n+ * Determine the fixed Rx latency for a given link speed.\n+ */\n+static u64\n+ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)\n+{\n+\tu64 cur_freq, clk_incval, tu_per_sec, fixed_offset;\n+\n+\tcur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));\n+\tclk_incval = ice_ptp_read_src_incval(hw);\n+\n+\t/* Calculate TUs per second */\n+\ttu_per_sec = cur_freq * clk_incval;\n+\n+\t/* Calculate number of TUs to add for the fixed Rx latency. Since the\n+\t * latency measurement is in 1/100th of a nanosecond, we need to\n+\t * multiply by tu_per_sec and then divide by 1e11. This calculation\n+\t * overflows 64 bit integer arithmetic, so break it up into two\n+\t * divisions by 1e4 first then by 1e7.\n+\t */\n+\tfixed_offset = tu_per_sec / 10000;\n+\tfixed_offset *= e822_vernier[link_spd].rx_fixed_delay;\n+\tfixed_offset /= 10000000;\n+\n+\treturn fixed_offset;\n+}\n+\n+/**\n+ * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to configure\n+ *\n+ * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to\n+ * adjust Rx timestamps by. This combines calculations from the Vernier offset\n+ * measurements taken in hardware with some data about known fixed delay as\n+ * well as adjusting for multi-lane alignment delay.\n+ *\n+ * This function must be called only after the offset registers are valid,\n+ * i.e. after the Vernier calibration wait has passed, to ensure that the PHY\n+ * has measured the offset.\n+ *\n+ * To avoid overflow, when calculating the offset based on the known static\n+ * latency values, we use measurements in 1/100th of a nanosecond, and divide\n+ * the TUs per second up front. This avoids overflow while allowing\n+ * calculation of the adjustment using integer arithmetic.\n+ */\n+enum ice_status ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)\n+{\n+\tenum ice_ptp_link_spd link_spd;\n+\tenum ice_ptp_fec_mode fec_mode;\n+\tu64 total_offset, pmd, val;\n+\tenum ice_status status;\n+\n+\tstatus = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);\n+\tif (status)\n+\t\treturn status;\n+\n+\ttotal_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);\n+\n+\t/* Read the first Vernier offset from the PHY register and add it to\n+\t * the total offset.\n+\t */\n+\tstatus = ice_read_64b_phy_reg_e822(hw, port,\n+\t\t\t\t\t   P_REG_PAR_PCS_RX_OFFSET_L,\n+\t\t\t\t\t   &val);\n+\tif (status)\n+\t\treturn status;\n+\n+\ttotal_offset += val;\n+\n+\t/* For Rx, all multi-lane link speeds include a second Vernier\n+\t * calibration, because the lanes might not be aligned.\n+\t */\n+\tif (link_spd == ICE_PTP_LNK_SPD_40G ||\n+\t    link_spd == ICE_PTP_LNK_SPD_50G ||\n+\t    link_spd == ICE_PTP_LNK_SPD_50G_RS ||\n+\t    link_spd == ICE_PTP_LNK_SPD_100G_RS) {\n+\t\tstatus = ice_read_64b_phy_reg_e822(hw, port,\n+\t\t\t\t\t\t   P_REG_PAR_RX_TIME_L,\n+\t\t\t\t\t\t   &val);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\ttotal_offset += val;\n+\t}\n+\n+\t/* In addition, Rx must account for the PMD alignment */\n+\tstatus = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* For RS-FEC, this adjustment adds delay, but for other modes, it\n+\t * subtracts delay.\n+\t */\n+\tif (fec_mode == ICE_PTP_FEC_MODE_RS_FEC)\n+\t\ttotal_offset += pmd;\n+\telse\n+\t\ttotal_offset -= pmd;\n+\n+\t/* Now that the total offset has been calculated, program it to the\n+\t * PHY and indicate that the Rx offset is ready. After this,\n+\t * timestamps will be enabled.\n+\t */\n+\tstatus = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,\n+\t\t\t\t\t    total_offset);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to configure\n+ *\n+ * Calculate and program the fixed Rx offset, and indicate that the offset is\n+ * ready. This can be used when operating in bypass mode.\n+ */\n+static enum ice_status\n+ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port)\n+{\n+\tenum ice_ptp_link_spd link_spd;\n+\tenum ice_ptp_fec_mode fec_mode;\n+\tenum ice_status status;\n+\tu64 total_offset;\n+\n+\tstatus = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);\n+\tif (status)\n+\t\treturn status;\n+\n+\ttotal_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);\n+\n+\t/* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L\n+\t * register, then indicate that the Rx offset is ready. After this,\n+\t * timestamps will be enabled.\n+\t *\n+\t * Note that this skips including the more precise offsets generated\n+\t * by Vernier calibration.\n+\t */\n+\tstatus = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,\n+\t\t\t\t\t    total_offset);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to read\n+ * @phy_time: on return, the 64bit PHY timer value\n+ * @phc_time: on return, the lower 64bits of PHC time\n+ *\n+ * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC\n+ * timer values.\n+ */\n+static enum ice_status\n+ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,\n+\t\t\t       u64 *phc_time)\n+{\n+\tenum ice_status status;\n+\tu64 tx_time, rx_time;\n+\tu32 zo, lo;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = ice_get_ptp_src_clock_index(hw);\n+\n+\t/* Prepare the PHC timer for a READ_TIME capture command */\n+\tice_ptp_src_cmd(hw, READ_TIME);\n+\n+\t/* Prepare the PHY timer for a READ_TIME capture command */\n+\tstatus = ice_ptp_one_port_cmd(hw, port, READ_TIME, true);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* Issue the sync to start the READ_TIME capture */\n+\tice_ptp_exec_tmr_cmd(hw);\n+\n+\t/* Read the captured PHC time from the shadow time registers */\n+\tzo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));\n+\tlo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));\n+\t*phc_time = (u64)lo << 32 | zo;\n+\n+\t/* Read the captured PHY time from the PHY shadow registers */\n+\tstatus = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* If the PHY Tx and Rx timers don't match, log a warning message.\n+\t * Note that this should not happen in normal circumstances since the\n+\t * driver always programs them together.\n+\t */\n+\tif (tx_time != rx_time)\n+\t\tice_warn(hw, \"PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\\n\",\n+\t\t\t port, (unsigned long long)tx_time,\n+\t\t\t (unsigned long long)rx_time);\n+\n+\t*phy_time = tx_time;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to synchronize\n+ *\n+ * Perform an adjustment to ensure that the PHY and PHC timers are in sync.\n+ * This is done by issuing a READ_TIME command which triggers a simultaneous\n+ * read of the PHY timer and PHC timer. Then we use the difference to\n+ * calculate an appropriate 2s complement addition to add to the PHY timer in\n+ * order to ensure it reads the same value as the primary PHC timer.\n+ */\n+static enum ice_status ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)\n+{\n+\tu64 phc_time, phy_time, difference;\n+\tenum ice_status status;\n+\n+\tif (!ice_ptp_lock(hw)) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to acquire PTP semaphore\\n\");\n+\t\treturn ICE_ERR_NOT_READY;\n+\t}\n+\n+\tstatus = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);\n+\tif (status)\n+\t\tgoto err_unlock;\n+\n+\t/* Calculate the amount required to add to the port time in order for\n+\t * it to match the PHC time.\n+\t *\n+\t * Note that the port adjustment is done using 2s complement\n+\t * arithmetic. This is convenient since it means that we can simply\n+\t * calculate the difference between the PHC time and the port time,\n+\t * and it will be interpreted correctly.\n+\t */\n+\tdifference = phc_time - phy_time;\n+\n+\tstatus = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference, true);\n+\tif (status)\n+\t\tgoto err_unlock;\n+\n+\tstatus = ice_ptp_one_port_cmd(hw, port, ADJ_TIME, true);\n+\tif (status)\n+\t\tgoto err_unlock;\n+\n+\t/* Issue the sync to activate the time adjustment */\n+\tice_ptp_exec_tmr_cmd(hw);\n+\n+\t/* Re-capture the timer values to flush the command registers and\n+\t * verify that the time was properly adjusted.\n+\t */\n+\tstatus = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);\n+\tif (status)\n+\t\tgoto err_unlock;\n+\n+\tice_info(hw, \"Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\\n\",\n+\t\t port, (unsigned long long)phy_time,\n+\t\t (unsigned long long)phc_time);\n+\n+\tice_ptp_unlock(hw);\n+\n+\treturn ICE_SUCCESS;\n+\n+err_unlock:\n+\tice_ptp_unlock(hw);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_stop_phy_timer_e822 - Stop the PHY clock timer\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to stop\n+ * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS\n+ *\n+ * Stop the clock of a PHY port. This must be done as part of the flow to\n+ * re-calibrate Tx and Rx timestamping offsets whenever the clock time is\n+ * initialized or when link speed changes.\n+ */\n+enum ice_status\n+ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)\n+{\n+\tenum ice_status status;\n+\tu32 val;\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tval &= ~P_REG_PS_START_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tval &= ~P_REG_PS_ENA_CLK_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tif (soft_reset) {\n+\t\tval |= P_REG_PS_SFT_RESET_M;\n+\t\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\tice_debug(hw, ICE_DBG_PTP, \"Disabled clock on PHY port %u\\n\", port);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_start_phy_timer_e822 - Start the PHY clock timer\n+ * @hw: pointer to the HW struct\n+ * @port: the PHY port to start\n+ * @bypass: if true, start the PHY in bypass mode\n+ *\n+ * Start the clock of a PHY port. This must be done as part of the flow to\n+ * re-calibrate Tx and Rx timestamping offsets whenever the clock time is\n+ * initialized or when link speed changes.\n+ *\n+ * Bypass mode enables timestamps immediately without waiting for Vernier\n+ * calibration to complete. Hardware will still continue taking Vernier\n+ * measurements on Tx or Rx of packets, but they will not be applied to\n+ * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware\n+ * has completed offset calculation.\n+ */\n+enum ice_status\n+ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass)\n+{\n+\tenum ice_status status;\n+\tu32 lo, hi, val;\n+\tu64 incval;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = ice_get_ptp_src_clock_index(hw);\n+\n+\tstatus = ice_stop_phy_timer_e822(hw, port, false);\n+\tif (status)\n+\t\treturn status;\n+\n+\tice_phy_cfg_lane_e822(hw, port);\n+\n+\tstatus = ice_phy_cfg_uix_e822(hw, port);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_phy_cfg_parpcs_e822(hw, port);\n+\tif (status)\n+\t\treturn status;\n+\n+\tlo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));\n+\thi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));\n+\tincval = (u64)hi << 32 | lo;\n+\n+\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL, true);\n+\tif (status)\n+\t\treturn status;\n+\n+\tice_ptp_exec_tmr_cmd(hw);\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tval |= P_REG_PS_SFT_RESET_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tval |= P_REG_PS_START_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tval &= ~P_REG_PS_SFT_RESET_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tstatus = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL, true);\n+\tif (status)\n+\t\treturn status;\n+\n+\tice_ptp_exec_tmr_cmd(hw);\n+\n+\tval |= P_REG_PS_ENA_CLK_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tval |= P_REG_PS_LOAD_OFFSET_M;\n+\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\tif (status)\n+\t\treturn status;\n+\n+\tice_ptp_exec_tmr_cmd(hw);\n+\n+\tstatus = ice_sync_phy_timer_e822(hw, port);\n+\tif (status)\n+\t\treturn status;\n+\n+\tif (bypass) {\n+\t\tval |= P_REG_PS_BYPASS_MODE_M;\n+\t\t/* Enter BYPASS mode, enabling timestamps immediately. */\n+\t\tstatus = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\t/* Program the fixed Tx offset */\n+\t\tstatus = ice_phy_cfg_fixed_tx_offset_e822(hw, port);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\t/* Program the fixed Rx offset */\n+\t\tstatus = ice_phy_cfg_fixed_rx_offset_e822(hw, port);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\tice_debug(hw, ICE_DBG_PTP, \"Enabled clock on PHY port %u\\n\", port);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n /* E810 functions\n  *\n  * The following functions operate on the E810 series devices which use\ndiff --git a/drivers/net/ice/base/ice_ptp_hw.h b/drivers/net/ice/base/ice_ptp_hw.h\nindex ad2349f60a..f2d87ca1e6 100644\n--- a/drivers/net/ice/base/ice_ptp_hw.h\n+++ b/drivers/net/ice/base/ice_ptp_hw.h\n@@ -55,6 +55,44 @@ struct ice_time_ref_info_e822 {\n \tu8 pps_delay;\n };\n \n+/**\n+ * struct ice_vernier_info_e822\n+ * @tx_par_clk: Frequency used to calculate P_REG_PAR_TX_TUS\n+ * @rx_par_clk: Frequency used to calculate P_REG_PAR_RX_TUS\n+ * @tx_pcs_clk: Frequency used to calculate P_REG_PCS_TX_TUS\n+ * @rx_pcs_clk: Frequency used to calculate P_REG_PCS_RX_TUS\n+ * @tx_desk_rsgb_par: Frequency used to calculate P_REG_DESK_PAR_TX_TUS\n+ * @rx_desk_rsgb_par: Frequency used to calculate P_REG_DESK_PAR_RX_TUS\n+ * @tx_desk_rsgb_pcs: Frequency used to calculate P_REG_DESK_PCS_TX_TUS\n+ * @rx_desk_rsgb_pcs: Frequency used to calculate P_REG_DESK_PCS_RX_TUS\n+ * @tx_fixed_delay: Fixed Tx latency measured in 1/100th nanoseconds\n+ * @pmd_adj_divisor: Divisor used to calculate PDM alignment adjustment\n+ * @rx_fixed_delay: Fixed Rx latency measured in 1/100th nanoseconds\n+ *\n+ * Table of constants used during as part of the Vernier calibration of the Tx\n+ * and Rx timestamps. This includes frequency values used to compute TUs per\n+ * PAR/PCS clock cycle, and static delay values measured during hardware\n+ * design.\n+ *\n+ * Note that some values are not used for all link speeds, and the\n+ * P_REG_DESK_PAR* registers may represent different clock markers at\n+ * different link speeds, either the deskew marker for multi-lane link speeds\n+ * or the Reed Solomon gearbox marker for RS-FEC.\n+ */\n+struct ice_vernier_info_e822 {\n+\tu32 tx_par_clk;\n+\tu32 rx_par_clk;\n+\tu32 tx_pcs_clk;\n+\tu32 rx_pcs_clk;\n+\tu32 tx_desk_rsgb_par;\n+\tu32 rx_desk_rsgb_par;\n+\tu32 tx_desk_rsgb_pcs;\n+\tu32 rx_desk_rsgb_pcs;\n+\tu32 tx_fixed_delay;\n+\tu32 pmd_adj_divisor;\n+\tu32 rx_fixed_delay;\n+};\n+\n /**\n  * struct ice_cgu_pll_params_e822\n  * @refclk_pre_div: Reference clock pre-divisor\n@@ -78,6 +116,9 @@ ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ];\n /* Table of constants related to possible TIME_REF sources */\n extern const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ];\n \n+/* Table of constants for Vernier calibration on E822 */\n+extern const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD];\n+\n /* Increment value to generate nanoseconds in the GLTSYN_TIME_L register for\n  * the E810 devices. Based off of a PLL with an 812.5 MHz frequency.\n  */\n@@ -171,6 +212,12 @@ ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,\n \t\t\t       enum ice_ptp_link_spd *link_out,\n \t\t\t       enum ice_ptp_fec_mode *fec_out);\n void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port);\n+enum ice_status\n+ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset);\n+enum ice_status\n+ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass);\n+enum ice_status ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port);\n+enum ice_status ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port);\n \n /* E810 family functions */\n enum ice_status ice_ptp_init_phy_e810(struct ice_hw *hw);\n",
    "prefixes": [
        "09/28"
    ]
}