get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 96691,
    "url": "http://patchwork.dpdk.org/api/patches/96691/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20210806013424.186010-3-simei.su@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": "<20210806013424.186010-3-simei.su@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210806013424.186010-3-simei.su@intel.com",
    "date": "2021-08-06T01:34:22",
    "name": "[2/4] net/ice/base: add low level functions for device clock control",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "e5123769d84c122c2f2a2098d54d643cf963a966",
    "submitter": {
        "id": 1298,
        "url": "http://patchwork.dpdk.org/api/people/1298/?format=api",
        "name": "Simei Su",
        "email": "simei.su@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/20210806013424.186010-3-simei.su@intel.com/mbox/",
    "series": [
        {
            "id": 18208,
            "url": "http://patchwork.dpdk.org/api/series/18208/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=18208",
            "date": "2021-08-06T01:34:20",
            "name": "net/ice: support IEEE 1588",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/18208/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/96691/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/96691/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 01A80A0C41;\n\tFri,  6 Aug 2021 03:46:43 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id D21514128F;\n\tFri,  6 Aug 2021 03:46:36 +0200 (CEST)",
            "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n by mails.dpdk.org (Postfix) with ESMTP id AD2A94129A\n for <dev@dpdk.org>; Fri,  6 Aug 2021 03:46:34 +0200 (CEST)",
            "from fmsmga002.fm.intel.com ([10.253.24.26])\n by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 05 Aug 2021 18:46:33 -0700",
            "from unknown (HELO npg-dpdk-cvl-simeisu-118d193.sh.intel.com)\n ([10.67.119.195])\n by fmsmga002.fm.intel.com with ESMTP; 05 Aug 2021 18:46:29 -0700"
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10067\"; a=\"193883158\"",
            "E=Sophos;i=\"5.84,299,1620716400\"; d=\"scan'208\";a=\"193883158\"",
            "E=Sophos;i=\"5.84,299,1620716400\"; d=\"scan'208\";a=\"523228523\""
        ],
        "X-ExtLoop1": "1",
        "From": "Simei Su <simei.su@intel.com>",
        "To": "qi.z.zhang@intel.com",
        "Cc": "dev@dpdk.org, haiyue.wang@intel.com,\n Jacob Keller <jacob.e.keller@intel.com>",
        "Date": "Fri,  6 Aug 2021 09:34:22 +0800",
        "Message-Id": "<20210806013424.186010-3-simei.su@intel.com>",
        "X-Mailer": "git-send-email 2.9.5",
        "In-Reply-To": "<20210806013424.186010-1-simei.su@intel.com>",
        "References": "<20210806013424.186010-1-simei.su@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 2/4] net/ice/base: add low level functions for\n device clock control",
        "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": "From: Qi Zhang <qi.z.zhang@intel.com>\n\nThe ice hardware supports exposing a hardware clock for high precision\ntimestamping. This is primarily intended for accelerating the Precision\nTime Protocol.\n\nAdd several low level functions intended to be used as the basis for\nenabling the device clock, and ensuring that the port timers are\nsynchronized properly.\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_adminq_cmd.h |    1 +\n drivers/net/ice/base/ice_common.c     |  143 +++\n drivers/net/ice/base/ice_common.h     |   11 +\n drivers/net/ice/base/ice_controlq.c   |   52 +-\n drivers/net/ice/base/ice_controlq.h   |    2 +\n drivers/net/ice/base/ice_ptp_consts.h |   86 ++\n drivers/net/ice/base/ice_ptp_hw.c     | 2023 +++++++++++++++++++++++++++++++++\n drivers/net/ice/base/ice_ptp_hw.h     |  376 ++++++\n drivers/net/ice/base/ice_type.h       |    3 +\n drivers/net/ice/base/meson.build      |    1 +\n 10 files changed, 2697 insertions(+), 1 deletion(-)\n create mode 100644 drivers/net/ice/base/ice_ptp_consts.h\n create mode 100644 drivers/net/ice/base/ice_ptp_hw.c\n create mode 100644 drivers/net/ice/base/ice_ptp_hw.h",
    "diff": "diff --git a/drivers/net/ice/base/ice_adminq_cmd.h b/drivers/net/ice/base/ice_adminq_cmd.h\nindex a0af35c..470aa89 100644\n--- a/drivers/net/ice/base/ice_adminq_cmd.h\n+++ b/drivers/net/ice/base/ice_adminq_cmd.h\n@@ -3120,6 +3120,7 @@ enum ice_adminq_opc {\n \tice_aqc_opc_set_event_mask\t\t\t= 0x0613,\n \tice_aqc_opc_set_mac_lb\t\t\t\t= 0x0620,\n \tice_aqc_opc_get_link_topo\t\t\t= 0x06E0,\n+\tice_aqc_opc_get_link_topo_pin\t\t\t= 0x06E1,\n \tice_aqc_opc_read_i2c\t\t\t\t= 0x06E2,\n \tice_aqc_opc_write_i2c\t\t\t\t= 0x06E3,\n \tice_aqc_opc_set_port_id_led\t\t\t= 0x06E9,\ndiff --git a/drivers/net/ice/base/ice_common.c b/drivers/net/ice/base/ice_common.c\nindex 56a4696..4748ca5 100644\n--- a/drivers/net/ice/base/ice_common.c\n+++ b/drivers/net/ice/base/ice_common.c\n@@ -65,6 +65,28 @@ static enum ice_status ice_set_mac_type(struct ice_hw *hw)\n }\n \n /**\n+ * ice_is_generic_mac\n+ * @hw: pointer to the hardware structure\n+ *\n+ * returns true if mac_type is ICE_MAC_GENERIC, false if not\n+ */\n+bool ice_is_generic_mac(struct ice_hw *hw)\n+{\n+\treturn hw->mac_type == ICE_MAC_GENERIC;\n+}\n+\n+/**\n+ * ice_is_e810\n+ * @hw: pointer to the hardware structure\n+ *\n+ * returns true if the device is E810 based, false if not.\n+ */\n+bool ice_is_e810(struct ice_hw *hw)\n+{\n+\treturn hw->mac_type == ICE_MAC_E810;\n+}\n+\n+/**\n  * ice_clear_pf_cfg - Clear PF configuration\n  * @hw: pointer to the hardware structure\n  *\n@@ -1354,6 +1376,127 @@ ice_clear_tx_drbell_q_ctx(struct ice_hw *hw, u32 tx_drbell_q_index)\n \treturn ICE_SUCCESS;\n }\n \n+/* Sideband Queue command wrappers */\n+\n+/**\n+ * ice_get_sbq - returns the right control queue to use for sideband\n+ * @hw: pointer to the hardware structure\n+ */\n+static struct ice_ctl_q_info *ice_get_sbq(struct ice_hw *hw)\n+{\n+\tif (!ice_is_generic_mac(hw))\n+\t\treturn &hw->adminq;\n+\treturn &hw->sbq;\n+}\n+\n+/**\n+ * ice_sbq_send_cmd - send Sideband Queue command to Sideband Queue\n+ * @hw: pointer to the HW struct\n+ * @desc: descriptor describing the command\n+ * @buf: buffer to use for indirect commands (NULL for direct commands)\n+ * @buf_size: size of buffer for indirect commands (0 for direct commands)\n+ * @cd: pointer to command details structure\n+ */\n+static enum ice_status\n+ice_sbq_send_cmd(struct ice_hw *hw, struct ice_sbq_cmd_desc *desc,\n+\t\t void *buf, u16 buf_size, struct ice_sq_cd *cd)\n+{\n+\treturn ice_sq_send_cmd(hw, ice_get_sbq(hw), (struct ice_aq_desc *)desc,\n+\t\t\t       buf, buf_size, cd);\n+}\n+\n+/**\n+ * ice_sbq_send_cmd_nolock - send Sideband Queue command to Sideband Queue\n+ *                           but do not lock sq_lock\n+ * @hw: pointer to the HW struct\n+ * @desc: descriptor describing the command\n+ * @buf: buffer to use for indirect commands (NULL for direct commands)\n+ * @buf_size: size of buffer for indirect commands (0 for direct commands)\n+ * @cd: pointer to command details structure\n+ */\n+static enum ice_status\n+ice_sbq_send_cmd_nolock(struct ice_hw *hw, struct ice_sbq_cmd_desc *desc,\n+\t\t\tvoid *buf, u16 buf_size, struct ice_sq_cd *cd)\n+{\n+\treturn ice_sq_send_cmd_nolock(hw, ice_get_sbq(hw),\n+\t\t\t\t      (struct ice_aq_desc *)desc, buf,\n+\t\t\t\t      buf_size, cd);\n+}\n+\n+/**\n+ * ice_sbq_rw_reg_lp - Fill Sideband Queue command, with lock parameter\n+ * @hw: pointer to the HW struct\n+ * @in: message info to be filled in descriptor\n+ * @lock: true to lock the sq_lock (the usual case); false if the sq_lock has\n+ *        already been locked at a higher level\n+ */\n+enum ice_status ice_sbq_rw_reg_lp(struct ice_hw *hw,\n+\t\t\t\t  struct ice_sbq_msg_input *in, bool lock)\n+{\n+\tstruct ice_sbq_cmd_desc desc = {0};\n+\tstruct ice_sbq_msg_req msg = {0};\n+\tenum ice_status status;\n+\tu16 msg_len;\n+\n+\tmsg_len = sizeof(msg);\n+\n+\tmsg.dest_dev = in->dest_dev;\n+\tmsg.opcode = in->opcode;\n+\tmsg.flags = ICE_SBQ_MSG_FLAGS;\n+\tmsg.sbe_fbe = ICE_SBQ_MSG_SBE_FBE;\n+\tmsg.msg_addr_low = CPU_TO_LE16(in->msg_addr_low);\n+\tmsg.msg_addr_high = CPU_TO_LE32(in->msg_addr_high);\n+\n+\tif (in->opcode)\n+\t\tmsg.data = CPU_TO_LE32(in->data);\n+\telse\n+\t\t/* data read comes back in completion, so shorten the struct by\n+\t\t * sizeof(msg.data)\n+\t\t */\n+\t\tmsg_len -= sizeof(msg.data);\n+\n+\tdesc.flags = CPU_TO_LE16(ICE_AQ_FLAG_RD);\n+\tdesc.opcode = CPU_TO_LE16(ice_sbq_opc_neigh_dev_req);\n+\tdesc.param0.cmd_len = CPU_TO_LE16(msg_len);\n+\tif (lock)\n+\t\tstatus = ice_sbq_send_cmd(hw, &desc, &msg, msg_len, NULL);\n+\telse\n+\t\tstatus = ice_sbq_send_cmd_nolock(hw, &desc, &msg, msg_len,\n+\t\t\t\t\t\t NULL);\n+\tif (!status && !in->opcode)\n+\t\tin->data = LE32_TO_CPU\n+\t\t\t(((struct ice_sbq_msg_cmpl *)&msg)->data);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_sbq_rw_reg - Fill Sideband Queue command\n+ * @hw: pointer to the HW struct\n+ * @in: message info to be filled in descriptor\n+ */\n+enum ice_status ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in)\n+{\n+\treturn ice_sbq_rw_reg_lp(hw, in, true);\n+}\n+\n+/**\n+ * ice_sbq_lock - Lock the sideband queue's sq_lock\n+ * @hw: pointer to the HW struct\n+ */\n+void ice_sbq_lock(struct ice_hw *hw)\n+{\n+\tice_acquire_lock(&ice_get_sbq(hw)->sq_lock);\n+}\n+\n+/**\n+ * ice_sbq_unlock - Unlock the sideband queue's sq_lock\n+ * @hw: pointer to the HW struct\n+ */\n+void ice_sbq_unlock(struct ice_hw *hw)\n+{\n+\tice_release_lock(&ice_get_sbq(hw)->sq_lock);\n+}\n+\n /* FW Admin Queue command wrappers */\n \n /**\ndiff --git a/drivers/net/ice/base/ice_common.h b/drivers/net/ice/base/ice_common.h\nindex 22ea89c..de7592b 100644\n--- a/drivers/net/ice/base/ice_common.h\n+++ b/drivers/net/ice/base/ice_common.h\n@@ -51,6 +51,10 @@ ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,\n \t\t      struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,\n \t\t      enum ice_adminq_opc opc, struct ice_sq_cd *cd);\n enum ice_status\n+ice_sq_send_cmd_nolock(struct ice_hw *hw, struct ice_ctl_q_info *cq,\n+\t\t       struct ice_aq_desc *desc, void *buf, u16 buf_size,\n+\t\t       struct ice_sq_cd *cd);\n+enum ice_status\n ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,\n \t\tstruct ice_aq_desc *desc, void *buf, u16 buf_size,\n \t\tstruct ice_sq_cd *cd);\n@@ -215,6 +219,11 @@ enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle);\n void ice_replay_post(struct ice_hw *hw);\n struct ice_q_ctx *\n ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle);\n+enum ice_status ice_sbq_rw_reg_lp(struct ice_hw *hw,\n+\t\t\t\t  struct ice_sbq_msg_input *in, bool lock);\n+void ice_sbq_lock(struct ice_hw *hw);\n+void ice_sbq_unlock(struct ice_hw *hw);\n+enum ice_status ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in);\n void\n ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,\n \t\t  u64 *prev_stat, u64 *cur_stat);\n@@ -226,6 +235,8 @@ ice_stat_update_repc(struct ice_hw *hw, u16 vsi_handle, bool prev_stat_loaded,\n \t\t     struct ice_eth_stats *cur_stats);\n enum ice_fw_modes ice_get_fw_mode(struct ice_hw *hw);\n void ice_print_rollback_msg(struct ice_hw *hw);\n+bool ice_is_generic_mac(struct ice_hw *hw);\n+bool ice_is_e810(struct ice_hw *hw);\n enum ice_status\n ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,\n \t\t     struct ice_aqc_txsched_elem_data *buf);\ndiff --git a/drivers/net/ice/base/ice_controlq.c b/drivers/net/ice/base/ice_controlq.c\nindex 93f7bc0..cdd067c 100644\n--- a/drivers/net/ice/base/ice_controlq.c\n+++ b/drivers/net/ice/base/ice_controlq.c\n@@ -55,6 +55,21 @@ static void ice_mailbox_init_regs(struct ice_hw *hw)\n }\n \n /**\n+ * ice_sb_init_regs - Initialize Sideband registers\n+ * @hw: pointer to the hardware structure\n+ *\n+ * This assumes the alloc_sq and alloc_rq functions have already been called\n+ */\n+static void ice_sb_init_regs(struct ice_hw *hw)\n+{\n+\tstruct ice_ctl_q_info *cq = &hw->sbq;\n+\n+\tice_debug(hw, ICE_DBG_TRACE, \"%s\\n\", __func__);\n+\n+\tICE_CQ_INIT_REGS(cq, PF_SB);\n+}\n+\n+/**\n  * ice_check_sq_alive\n  * @hw: pointer to the HW struct\n  * @cq: pointer to the specific Control queue\n@@ -584,6 +599,10 @@ static enum ice_status ice_init_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type)\n \t\tice_adminq_init_regs(hw);\n \t\tcq = &hw->adminq;\n \t\tbreak;\n+\tcase ICE_CTL_Q_SB:\n+\t\tice_sb_init_regs(hw);\n+\t\tcq = &hw->sbq;\n+\t\tbreak;\n \tcase ICE_CTL_Q_MAILBOX:\n \t\tice_mailbox_init_regs(hw);\n \t\tcq = &hw->mailboxq;\n@@ -621,6 +640,18 @@ static enum ice_status ice_init_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type)\n }\n \n /**\n+ * ice_is_sbq_supported - is the sideband queue supported\n+ * @hw: pointer to the hardware structure\n+ *\n+ * Returns true if the sideband control queue interface is\n+ * supported for the device, false otherwise\n+ */\n+static bool ice_is_sbq_supported(struct ice_hw *hw)\n+{\n+\treturn ice_is_generic_mac(hw);\n+}\n+\n+/**\n  * ice_shutdown_ctrlq - shutdown routine for any control queue\n  * @hw: pointer to the hardware structure\n  * @q_type: specific Control queue type\n@@ -639,6 +670,9 @@ static void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type)\n \t\tif (ice_check_sq_alive(hw, cq))\n \t\t\tice_aq_q_shutdown(hw, true);\n \t\tbreak;\n+\tcase ICE_CTL_Q_SB:\n+\t\tcq = &hw->sbq;\n+\t\tbreak;\n \tcase ICE_CTL_Q_MAILBOX:\n \t\tcq = &hw->mailboxq;\n \t\tbreak;\n@@ -663,6 +697,9 @@ void ice_shutdown_all_ctrlq(struct ice_hw *hw)\n \tice_debug(hw, ICE_DBG_TRACE, \"%s\\n\", __func__);\n \t/* Shutdown FW admin queue */\n \tice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN);\n+\t/* Shutdown PHY Sideband */\n+\tif (ice_is_sbq_supported(hw))\n+\t\tice_shutdown_ctrlq(hw, ICE_CTL_Q_SB);\n \t/* Shutdown PF-VF Mailbox */\n \tice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX);\n }\n@@ -704,6 +741,15 @@ enum ice_status ice_init_all_ctrlq(struct ice_hw *hw)\n \n \tif (status)\n \t\treturn status;\n+\t/* sideband control queue (SBQ) interface is not supported on some\n+\t * devices. Initialize if supported, else fallback to the admin queue\n+\t * interface\n+\t */\n+\tif (ice_is_sbq_supported(hw)) {\n+\t\tstatus = ice_init_ctrlq(hw, ICE_CTL_Q_SB);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n \t/* Init Mailbox queue */\n \treturn ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX);\n }\n@@ -739,6 +785,8 @@ static void ice_init_ctrlq_locks(struct ice_ctl_q_info *cq)\n enum ice_status ice_create_all_ctrlq(struct ice_hw *hw)\n {\n \tice_init_ctrlq_locks(&hw->adminq);\n+\tif (ice_is_sbq_supported(hw))\n+\t\tice_init_ctrlq_locks(&hw->sbq);\n \tice_init_ctrlq_locks(&hw->mailboxq);\n \n \treturn ice_init_all_ctrlq(hw);\n@@ -771,6 +819,8 @@ void ice_destroy_all_ctrlq(struct ice_hw *hw)\n \tice_shutdown_all_ctrlq(hw);\n \n \tice_destroy_ctrlq_locks(&hw->adminq);\n+\tif (ice_is_sbq_supported(hw))\n+\t\tice_destroy_ctrlq_locks(&hw->sbq);\n \tice_destroy_ctrlq_locks(&hw->mailboxq);\n }\n \n@@ -882,7 +932,7 @@ static bool ice_sq_done(struct ice_hw *hw, struct ice_ctl_q_info *cq)\n  * This is the main send command routine for the ATQ. It runs the queue,\n  * cleans the queue, etc.\n  */\n-static enum ice_status\n+enum ice_status\n ice_sq_send_cmd_nolock(struct ice_hw *hw, struct ice_ctl_q_info *cq,\n \t\t       struct ice_aq_desc *desc, void *buf, u16 buf_size,\n \t\t       struct ice_sq_cd *cd)\ndiff --git a/drivers/net/ice/base/ice_controlq.h b/drivers/net/ice/base/ice_controlq.h\nindex 0d54e71..840fb5e 100644\n--- a/drivers/net/ice/base/ice_controlq.h\n+++ b/drivers/net/ice/base/ice_controlq.h\n@@ -10,6 +10,7 @@\n /* Maximum buffer lengths for all control queue types */\n #define ICE_AQ_MAX_BUF_LEN 4096\n #define ICE_MBXQ_MAX_BUF_LEN 4096\n+#define ICE_SBQ_MAX_BUF_LEN 512\n \n #define ICE_CTL_Q_DESC(R, i) \\\n \t(&(((struct ice_aq_desc *)((R).desc_buf.va))[i]))\n@@ -30,6 +31,7 @@ enum ice_ctl_q {\n \tICE_CTL_Q_UNKNOWN = 0,\n \tICE_CTL_Q_ADMIN,\n \tICE_CTL_Q_MAILBOX,\n+\tICE_CTL_Q_SB,\n };\n \n /* Control Queue timeout settings - max delay 1s */\ndiff --git a/drivers/net/ice/base/ice_ptp_consts.h b/drivers/net/ice/base/ice_ptp_consts.h\nnew file mode 100644\nindex 0000000..2bd338c\n--- /dev/null\n+++ b/drivers/net/ice/base/ice_ptp_consts.h\n@@ -0,0 +1,86 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2001-2021 Intel Corporation\n+ */\n+\n+#ifndef _ICE_PTP_CONSTS_H_\n+#define _ICE_PTP_CONSTS_H_\n+\n+/* Constant definitions related to the hardware clock used for PTP 1588\n+ * features and functionality.\n+ */\n+/* Constants defined for the PTP 1588 clock hardware. */\n+\n+/*\n+ * struct ice_time_ref_info_e822\n+ *\n+ * E822 hardware can use different sources as the reference for the PTP\n+ * hardware clock. Each clock has different characteristics such as a slightly\n+ * different frequency, etc.\n+ *\n+ * This lookup table defines several constants that depend on the current time\n+ * reference. See the struct ice_time_ref_info_e822 for information about the\n+ * meaning of each constant.\n+ */\n+const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ] = {\n+\t/* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */\n+\t{\n+\t\t/* pll_freq */\n+\t\t823437500, /* 823.4375 MHz PLL */\n+\t\t/* nominal_incval */\n+\t\t0x136e44fabULL,\n+\t\t/* pps_delay */\n+\t\t11,\n+\t},\n+\n+\t/* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */\n+\t{\n+\t\t/* pll_freq */\n+\t\t783360000, /* 783.36 MHz */\n+\t\t/* nominal_incval */\n+\t\t0x146cc2177ULL,\n+\t\t/* pps_delay */\n+\t\t12,\n+\t},\n+\n+\t/* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */\n+\t{\n+\t\t/* pll_freq */\n+\t\t796875000, /* 796.875 MHz */\n+\t\t/* nominal_incval */\n+\t\t0x141414141ULL,\n+\t\t/* pps_delay */\n+\t\t12,\n+\t},\n+\n+\t/* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */\n+\t{\n+\t\t/* pll_freq */\n+\t\t816000000, /* 816 MHz */\n+\t\t/* nominal_incval */\n+\t\t0x139b9b9baULL,\n+\t\t/* pps_delay */\n+\t\t12,\n+\t},\n+\n+\t/* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */\n+\t{\n+\t\t/* pll_freq */\n+\t\t830078125, /* 830.78125 MHz */\n+\t\t/* nominal_incval */\n+\t\t0x134679aceULL,\n+\t\t/* pps_delay */\n+\t\t11,\n+\t},\n+\n+\t/* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */\n+\t{\n+\t\t/* pll_freq */\n+\t\t783360000, /* 783.36 MHz */\n+\t\t/* nominal_incval */\n+\t\t0x146cc2177ULL,\n+\t\t/* pps_delay */\n+\t\t12,\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\nnew file mode 100644\nindex 0000000..8aefcf9\n--- /dev/null\n+++ b/drivers/net/ice/base/ice_ptp_hw.c\n@@ -0,0 +1,2023 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2001-2021 Intel Corporation\n+ */\n+\n+#include \"ice_type.h\"\n+#include \"ice_common.h\"\n+#include \"ice_ptp_hw.h\"\n+#include \"ice_ptp_consts.h\"\n+\n+\n+/* Low level functions for interacting with and managing the device clock used\n+ * for the Precision Time Protocol.\n+ *\n+ * The ice hardware represents the current time using three registers:\n+ *\n+ *    GLTSYN_TIME_H     GLTSYN_TIME_L     GLTSYN_TIME_R\n+ *  +---------------+ +---------------+ +---------------+\n+ *  |    32 bits    | |    32 bits    | |    32 bits    |\n+ *  +---------------+ +---------------+ +---------------+\n+ *\n+ * The registers are incremented every clock tick using a 40bit increment\n+ * value defined over two registers:\n+ *\n+ *                     GLTSYN_INCVAL_H   GLTSYN_INCVAL_L\n+ *                    +---------------+ +---------------+\n+ *                    |    8 bit s    | |    32 bits    |\n+ *                    +---------------+ +---------------+\n+ *\n+ * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L\n+ * registers every clock source tick. Depending on the specific device\n+ * configuration, the clock source frequency could be one of a number of\n+ * values.\n+ *\n+ * For E810 devices, the increment frequency is 812.5 MHz\n+ *\n+ * For E822 devices the clock can be derived from different sources, and the\n+ * increment has an effective frequency of one of the following:\n+ * - 823.4375 MHz\n+ * - 783.36 MHz\n+ * - 796.875 MHz\n+ * - 816 MHz\n+ * - 830.078125 MHz\n+ * - 783.36 MHz\n+ *\n+ * The hardware captures timestamps in the PHY for incoming packets, and for\n+ * outgoing packets on request. To support this, the PHY maintains a timer\n+ * that matches the lower 64 bits of the global source timer.\n+ *\n+ * In order to ensure that the PHY timers and the source timer are equivalent,\n+ * shadow registers are used to prepare the desired initial values. A special\n+ * sync command is issued to trigger copying from the shadow registers into\n+ * the appropriate source and PHY registers simultaneously.\n+ *\n+ * The driver supports devices which have different PHYs with subtly different\n+ * mechanisms to program and control the timers. We divide the devices into\n+ * families named after the first major device, E810 and similar devices, and\n+ * E822 and similar devices.\n+ *\n+ * - E822 based devices have additional support for fine grained Vernier\n+ *   calibration which requires significant setup\n+ * - The layout of timestamp data in the PHY register blocks is different\n+ * - The way timer synchronization commands are issued is different.\n+ *\n+ * To support this, very low level functions have an e810 or e822 suffix\n+ * indicating what type of device they work on. Higher level abstractions for\n+ * tasks that can be done on both devices do not have the suffix and will\n+ * correctly look up the appropriate low level function when running.\n+ *\n+ * Functions which only make sense on a single device family may not have\n+ * a suitable generic implementation\n+ */\n+\n+/**\n+ * ice_get_ptp_src_clock_index - determine source clock index\n+ * @hw: pointer to HW struct\n+ *\n+ * Determine the source clock index currently in use, based on device\n+ * capabilities reported during initialization.\n+ */\n+u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)\n+{\n+\treturn hw->func_caps.ts_func_info.tmr_index_assoc;\n+}\n+\n+/**\n+ * ice_ptp_read_src_incval - Read source timer increment value\n+ * @hw: pointer to HW struct\n+ *\n+ * Read the increment value of the source timer and return it.\n+ */\n+u64 ice_ptp_read_src_incval(struct ice_hw *hw)\n+{\n+\tu32 lo, hi;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = ice_get_ptp_src_clock_index(hw);\n+\n+\tlo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));\n+\thi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));\n+\n+\treturn ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;\n+}\n+\n+/**\n+ * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands\n+ * @hw: pointer to HW struct\n+ *\n+ * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the\n+ * write immediately. This triggers the hardware to begin executing all of the\n+ * source and PHY timer commands synchronously.\n+ */\n+static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)\n+{\n+\twr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);\n+\tice_flush(hw);\n+}\n+\n+/* E822 family functions\n+ *\n+ * The following functions operate on the E822 family of devices.\n+ */\n+\n+/**\n+ * ice_fill_phy_msg_e822 - Fill message data for a PHY register access\n+ * @msg: the PHY message buffer to fill in\n+ * @port: the port to access\n+ * @offset: the register offset\n+ */\n+static void\n+ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)\n+{\n+\tint phy_port, phy, quadtype;\n+\n+\tphy_port = port % ICE_PORTS_PER_PHY;\n+\tphy = port / ICE_PORTS_PER_PHY;\n+\tquadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE;\n+\n+\tif (quadtype == 0) {\n+\t\tmsg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);\n+\t\tmsg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port);\n+\t} else {\n+\t\tmsg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port);\n+\t\tmsg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port);\n+\t}\n+\n+\tif (phy == 0)\n+\t\tmsg->dest_dev = rmn_0;\n+\telse if (phy == 1)\n+\t\tmsg->dest_dev = rmn_1;\n+\telse\n+\t\tmsg->dest_dev = rmn_2;\n+}\n+\n+/**\n+ * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register\n+ * @low_addr: the low address to check\n+ * @high_addr: on return, contains the high address of the 64bit register\n+ *\n+ * Checks if the provided low address is one of the known 64bit PHY values\n+ * represented as two 32bit registers. If it is, return the appropriate high\n+ * register offset to use.\n+ */\n+static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)\n+{\n+\tswitch (low_addr) {\n+\tcase P_REG_PAR_PCS_TX_OFFSET_L:\n+\t\t*high_addr = P_REG_PAR_PCS_TX_OFFSET_U;\n+\t\treturn true;\n+\tcase P_REG_PAR_PCS_RX_OFFSET_L:\n+\t\t*high_addr = P_REG_PAR_PCS_RX_OFFSET_U;\n+\t\treturn true;\n+\tcase P_REG_PAR_TX_TIME_L:\n+\t\t*high_addr = P_REG_PAR_TX_TIME_U;\n+\t\treturn true;\n+\tcase P_REG_PAR_RX_TIME_L:\n+\t\t*high_addr = P_REG_PAR_RX_TIME_U;\n+\t\treturn true;\n+\tcase P_REG_TOTAL_TX_OFFSET_L:\n+\t\t*high_addr = P_REG_TOTAL_TX_OFFSET_U;\n+\t\treturn true;\n+\tcase P_REG_TOTAL_RX_OFFSET_L:\n+\t\t*high_addr = P_REG_TOTAL_RX_OFFSET_U;\n+\t\treturn true;\n+\tcase P_REG_UIX66_10G_40G_L:\n+\t\t*high_addr = P_REG_UIX66_10G_40G_U;\n+\t\treturn true;\n+\tcase P_REG_UIX66_25G_100G_L:\n+\t\t*high_addr = P_REG_UIX66_25G_100G_U;\n+\t\treturn true;\n+\tcase P_REG_TX_CAPTURE_L:\n+\t\t*high_addr = P_REG_TX_CAPTURE_U;\n+\t\treturn true;\n+\tcase P_REG_RX_CAPTURE_L:\n+\t\t*high_addr = P_REG_RX_CAPTURE_U;\n+\t\treturn true;\n+\tcase P_REG_TX_TIMER_INC_PRE_L:\n+\t\t*high_addr = P_REG_TX_TIMER_INC_PRE_U;\n+\t\treturn true;\n+\tcase P_REG_RX_TIMER_INC_PRE_L:\n+\t\t*high_addr = P_REG_RX_TIMER_INC_PRE_U;\n+\t\treturn true;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+}\n+\n+/**\n+ * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register\n+ * @low_addr: the low address to check\n+ * @high_addr: on return, contains the high address of the 40bit value\n+ *\n+ * Checks if the provided low address is one of the known 40bit PHY values\n+ * split into two registers with the lower 8 bits in the low register and the\n+ * upper 32 bits in the high register. If it is, return the appropriate high\n+ * register offset to use.\n+ */\n+static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)\n+{\n+\tswitch (low_addr) {\n+\tcase P_REG_TIMETUS_L:\n+\t\t*high_addr = P_REG_TIMETUS_U;\n+\t\treturn true;\n+\tcase P_REG_PAR_RX_TUS_L:\n+\t\t*high_addr = P_REG_PAR_RX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_PAR_TX_TUS_L:\n+\t\t*high_addr = P_REG_PAR_TX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_PCS_RX_TUS_L:\n+\t\t*high_addr = P_REG_PCS_RX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_PCS_TX_TUS_L:\n+\t\t*high_addr = P_REG_PCS_TX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_DESK_PAR_RX_TUS_L:\n+\t\t*high_addr = P_REG_DESK_PAR_RX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_DESK_PAR_TX_TUS_L:\n+\t\t*high_addr = P_REG_DESK_PAR_TX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_DESK_PCS_RX_TUS_L:\n+\t\t*high_addr = P_REG_DESK_PCS_RX_TUS_U;\n+\t\treturn true;\n+\tcase P_REG_DESK_PCS_TX_TUS_L:\n+\t\t*high_addr = P_REG_DESK_PCS_TX_TUS_U;\n+\t\treturn true;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+}\n+\n+/**\n+ * ice_read_phy_reg_e822_lp - Read a PHY register\n+ * @hw: pointer to the HW struct\n+ * @port: PHY port to read from\n+ * @offset: PHY register offset to read\n+ * @val: on return, the contents read from the PHY\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Read a PHY register for the given port over the device sideband queue.\n+ */\n+static enum ice_status\n+ice_read_phy_reg_e822_lp(struct ice_hw *hw, u8 port, u16 offset, u32 *val,\n+\t\t\t bool lock_sbq)\n+{\n+\tstruct ice_sbq_msg_input msg = {0};\n+\tenum ice_status status;\n+\n+\tice_fill_phy_msg_e822(&msg, port, offset);\n+\tmsg.opcode = ice_sbq_msg_rd;\n+\n+\tstatus = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to send message to phy, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t*val = msg.data;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+enum ice_status\n+ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)\n+{\n+\treturn ice_read_phy_reg_e822_lp(hw, port, offset, val, true);\n+}\n+\n+/**\n+ * ice_read_40b_phy_reg_e822 - Read a 40bit value from PHY registers\n+ * @hw: pointer to the HW struct\n+ * @port: PHY port to read from\n+ * @low_addr: offset of the lower register to read from\n+ * @val: on return, the contents of the 40bit value from the PHY registers\n+ *\n+ * Reads the two registers associated with a 40bit value and returns it in the\n+ * val pointer. The offset always specifies the lower register offset to use.\n+ * The high offset is looked up. This function only operates on registers\n+ * known to be split into a lower 8 bit chunk and an upper 32 bit chunk.\n+ */\n+static enum ice_status\n+ice_read_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)\n+{\n+\tenum ice_status status;\n+\tu32 low, high;\n+\tu16 high_addr;\n+\n+\t/* Only operate on registers known to be split into two 32bit\n+\t * registers.\n+\t */\n+\tif (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Invalid 64b register addr 0x%08x\\n\",\n+\t\t\t  low_addr);\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, low_addr, &low);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read from low register 0x%08x\\n, status %d\",\n+\t\t\t  low_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, high_addr, &high);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read from high register 0x%08x\\n, status %d\",\n+\t\t\t  high_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\t*val = (u64)high << P_REG_40B_HIGH_S | (low & P_REG_40B_LOW_M);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers\n+ * @hw: pointer to the HW struct\n+ * @port: PHY port to read from\n+ * @low_addr: offset of the lower register to read from\n+ * @val: on return, the contents of the 64bit value from the PHY registers\n+ *\n+ * Reads the two registers associated with a 64bit value and returns it in the\n+ * val pointer. The offset always specifies the lower register offset to use.\n+ * The high offset is looked up. This function only operates on registers\n+ * known to be two parts of a 64bit value.\n+ */\n+static enum ice_status\n+ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)\n+{\n+\tenum ice_status status;\n+\tu32 low, high;\n+\tu16 high_addr;\n+\n+\t/* Only operate on registers known to be split into two 32bit\n+\t * registers.\n+\t */\n+\tif (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Invalid 64b register addr 0x%08x\\n\",\n+\t\t\t  low_addr);\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, low_addr, &low);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read from low register 0x%08x\\n, status %d\",\n+\t\t\t  low_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, high_addr, &high);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read from high register 0x%08x\\n, status %d\",\n+\t\t\t  high_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\t*val = (u64)high << 32 | low;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_write_phy_reg_e822_lp - Write a PHY register\n+ * @hw: pointer to the HW struct\n+ * @port: PHY port to write to\n+ * @offset: PHY register offset to write\n+ * @val: The value to write to the register\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Write a PHY register for the given port over the device sideband queue.\n+ */\n+static enum ice_status\n+ice_write_phy_reg_e822_lp(struct ice_hw *hw, u8 port, u16 offset, u32 val,\n+\t\t\t  bool lock_sbq)\n+{\n+\tstruct ice_sbq_msg_input msg = {0};\n+\tenum ice_status status;\n+\n+\tice_fill_phy_msg_e822(&msg, port, offset);\n+\tmsg.opcode = ice_sbq_msg_wr;\n+\tmsg.data = val;\n+\n+\tstatus = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to send message to phy, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+enum ice_status\n+ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)\n+{\n+\treturn ice_write_phy_reg_e822_lp(hw, port, offset, val, true);\n+}\n+\n+/**\n+ * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY\n+ * @hw: pointer to the HW struct\n+ * @port: port to write to\n+ * @low_addr: offset of the low register\n+ * @val: 40b value to write\n+ *\n+ * Write the provided 40b value to the two associated registers by splitting\n+ * it up into two chunks, the lower 8 bits and the upper 32 bits.\n+ */\n+static enum ice_status\n+ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)\n+{\n+\tenum ice_status status;\n+\tu32 low, high;\n+\tu16 high_addr;\n+\n+\t/* Only operate on registers known to be split into a lower 8 bit\n+\t * register and an upper 32 bit register.\n+\t */\n+\tif (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Invalid 40b register addr 0x%08x\\n\",\n+\t\t\t  low_addr);\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\tlow = (u32)(val & P_REG_40B_LOW_M);\n+\thigh = (u32)(val >> P_REG_40B_HIGH_S);\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, low_addr, low);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write to low register 0x%08x\\n, status %d\",\n+\t\t\t  low_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, high_addr, high);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write to high register 0x%08x\\n, status %d\",\n+\t\t\t  high_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers\n+ * @hw: pointer to the HW struct\n+ * @port: PHY port to read from\n+ * @low_addr: offset of the lower register to read from\n+ * @val: the contents of the 64bit value to write to PHY\n+ *\n+ * Write the 64bit value to the two associated 32bit PHY registers. The offset\n+ * is always specified as the lower register, and the high address is looked\n+ * up. This function only operates on registers known to be two parts of\n+ * a 64bit value.\n+ */\n+static enum ice_status\n+ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)\n+{\n+\tenum ice_status status;\n+\tu32 low, high;\n+\tu16 high_addr;\n+\n+\t/* Only operate on registers known to be split into two 32bit\n+\t * registers.\n+\t */\n+\tif (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Invalid 64b register addr 0x%08x\\n\",\n+\t\t\t  low_addr);\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\tlow = ICE_LO_DWORD(val);\n+\thigh = ICE_HI_DWORD(val);\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, low_addr, low);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write to low register 0x%08x\\n, status %d\",\n+\t\t\t  low_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e822(hw, port, high_addr, high);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write to high register 0x%08x\\n, status %d\",\n+\t\t\t  high_addr, status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_fill_quad_msg_e822 - Fill message data for quad register access\n+ * @msg: the PHY message buffer to fill in\n+ * @quad: the quad to access\n+ * @offset: the register offset\n+ *\n+ * Fill a message buffer for accessing a register in a quad shared between\n+ * multiple PHYs.\n+ */\n+static void\n+ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)\n+{\n+\tu32 addr;\n+\n+\tmsg->dest_dev = rmn_0;\n+\n+\tif ((quad % ICE_NUM_QUAD_TYPE) == 0)\n+\t\taddr = Q_0_BASE + offset;\n+\telse\n+\t\taddr = Q_1_BASE + offset;\n+\n+\tmsg->msg_addr_low = ICE_LO_WORD(addr);\n+\tmsg->msg_addr_high = ICE_HI_WORD(addr);\n+}\n+\n+/**\n+ * ice_read_quad_reg_e822_lp - Read a PHY quad register\n+ * @hw: pointer to the HW struct\n+ * @quad: quad to read from\n+ * @offset: quad register offset to read\n+ * @val: on return, the contents read from the quad\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Read a quad register over the device sideband queue. Quad registers are\n+ * shared between multiple PHYs.\n+ */\n+static enum ice_status\n+ice_read_quad_reg_e822_lp(struct ice_hw *hw, u8 quad, u16 offset, u32 *val,\n+\t\t\t  bool lock_sbq)\n+{\n+\tstruct ice_sbq_msg_input msg = {0};\n+\tenum ice_status status;\n+\n+\tif (quad >= ICE_MAX_QUAD)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tice_fill_quad_msg_e822(&msg, quad, offset);\n+\tmsg.opcode = ice_sbq_msg_rd;\n+\n+\tstatus = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to send message to phy, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t*val = msg.data;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+enum ice_status\n+ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)\n+{\n+\treturn ice_read_quad_reg_e822_lp(hw, quad, offset, val, true);\n+}\n+\n+/**\n+ * ice_write_quad_reg_e822_lp - Write a PHY quad register\n+ * @hw: pointer to the HW struct\n+ * @quad: quad to write to\n+ * @offset: quad register offset to write\n+ * @val: The value to write to the register\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Write a quad register over the device sideband queue. Quad registers are\n+ * shared between multiple PHYs.\n+ */\n+static enum ice_status\n+ice_write_quad_reg_e822_lp(struct ice_hw *hw, u8 quad, u16 offset, u32 val,\n+\t\t\t   bool lock_sbq)\n+{\n+\tstruct ice_sbq_msg_input msg = {0};\n+\tenum ice_status status;\n+\n+\tif (quad >= ICE_MAX_QUAD)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tice_fill_quad_msg_e822(&msg, quad, offset);\n+\tmsg.opcode = ice_sbq_msg_wr;\n+\tmsg.data = val;\n+\n+\tstatus = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to send message to phy, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+enum ice_status\n+ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)\n+{\n+\treturn ice_write_quad_reg_e822_lp(hw, quad, offset, val, true);\n+}\n+\n+/**\n+ * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block\n+ * @hw: pointer to the HW struct\n+ * @quad: the quad to read from\n+ * @idx: the timestamp index to read\n+ * @tstamp: on return, the 40bit timestamp value\n+ *\n+ * Read a 40bit timestamp value out of the two associated registers in the\n+ * quad memory block that is shared between the internal PHYs of the E822\n+ * family of devices.\n+ */\n+static enum ice_status\n+ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)\n+{\n+\tenum ice_status status;\n+\tu16 lo_addr, hi_addr;\n+\tu32 lo, hi;\n+\n+\tlo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);\n+\thi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);\n+\n+\tstatus = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read low PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read high PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* For E822 based internal PHYs, the timestamp is reported with the\n+\t * lower 8 bits in the low register, and the upper 32 bits in the high\n+\t * register.\n+\t */\n+\t*tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block\n+ * @hw: pointer to the HW struct\n+ * @quad: the quad to read from\n+ * @idx: the timestamp index to reset\n+ *\n+ * Clear a timestamp, resetting its valid bit, from the PHY quad block that is\n+ * shared between the internal PHYs on the E822 devices.\n+ */\n+static enum ice_status\n+ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)\n+{\n+\tenum ice_status status;\n+\tu16 lo_addr, hi_addr;\n+\n+\tlo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);\n+\thi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);\n+\n+\tstatus = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to clear low PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to clear high PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time\n+ * @hw: pointer to the HW struct\n+ * @time: Time to initialize the PHY port clocks to\n+ *\n+ * Program the PHY port registers with a new initial time value. The port\n+ * clock will be initialized once the driver issues an INIT_TIME sync\n+ * command. The time value is the upper 32 bits of the PHY timer, usually in\n+ * units of nominal nanoseconds.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)\n+{\n+\tenum ice_status status;\n+\tu64 phy_time;\n+\tu8 port;\n+\n+\t/* The time represents the upper 32 bits of the PHY timer, so we need\n+\t * to shift to account for this when programming.\n+\t */\n+\tphy_time = (u64)time << 32;\n+\n+\tfor (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {\n+\n+\t\t/* Tx case */\n+\t\tstatus = ice_write_64b_phy_reg_e822(hw, port,\n+\t\t\t\t\t\t    P_REG_TX_TIMER_INC_PRE_L,\n+\t\t\t\t\t\t    phy_time);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\n+\t\t/* Rx case */\n+\t\tstatus = ice_write_64b_phy_reg_e822(hw, port,\n+\t\t\t\t\t\t    P_REG_RX_TIMER_INC_PRE_L,\n+\t\t\t\t\t\t    phy_time);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+\n+exit_err:\n+\tice_debug(hw, ICE_DBG_PTP, \"Failed to write init time for port %u, status %d\\n\",\n+\t\t  port, status);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust\n+ * @hw: pointer to HW struct\n+ * @port: Port number to be programmed\n+ * @time: time in cycles to adjust the port Tx and Rx clocks\n+ * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the\n+ *            sq_lock has already been locked at a higher level\n+ *\n+ * Program the port for an atomic adjustment by writing the Tx and Rx timer\n+ * registers. The atomic adjustment won't be completed until the driver issues\n+ * an ADJ_TIME command.\n+ *\n+ * Note that time is not in units of nanoseconds. It is in clock time\n+ * including the lower sub-nanosecond portion of the port timer.\n+ *\n+ * Negative adjustments are supported using 2s complement arithmetic.\n+ */\n+enum ice_status\n+ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time,\n+\t\t\t   bool lock_sbq)\n+{\n+\tenum ice_status status;\n+\tu32 l_time, u_time;\n+\n+\tl_time = ICE_LO_DWORD(time);\n+\tu_time = ICE_HI_DWORD(time);\n+\n+\t/* Tx case */\n+\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TIMER_INC_PRE_L,\n+\t\t\t\t\t   l_time, lock_sbq);\n+\tif (status)\n+\t\tgoto exit_err;\n+\n+\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TIMER_INC_PRE_U,\n+\t\t\t\t\t   u_time, lock_sbq);\n+\tif (status)\n+\t\tgoto exit_err;\n+\n+\t/* Rx case */\n+\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TIMER_INC_PRE_L,\n+\t\t\t\t\t   l_time, lock_sbq);\n+\tif (status)\n+\t\tgoto exit_err;\n+\n+\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TIMER_INC_PRE_U,\n+\t\t\t\t\t   u_time, lock_sbq);\n+\tif (status)\n+\t\tgoto exit_err;\n+\n+\treturn ICE_SUCCESS;\n+\n+exit_err:\n+\tice_debug(hw, ICE_DBG_PTP, \"Failed to write time adjust for port %u, status %d\\n\",\n+\t\t  port, status);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment\n+ * @hw: pointer to HW struct\n+ * @adj: adjustment in nanoseconds\n+ * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the\n+ *            sq_lock has already been locked at a higher level\n+ *\n+ * Prepare the PHY ports for an atomic time adjustment by programming the PHY\n+ * Tx and Rx port registers. The actual adjustment is completed by issuing an\n+ * ADJ_TIME or ADJ_TIME_AT_TIME sync command.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj, bool lock_sbq)\n+{\n+\ts64 cycles;\n+\tu8 port;\n+\n+\t/* The port clock supports adjustment of the sub-nanosecond portion of\n+\t * the clock. We shift the provided adjustment in nanoseconds to\n+\t * calculate the appropriate adjustment to program into the PHY ports.\n+\t */\n+\tif (adj > 0)\n+\t\tcycles = (s64)adj << 32;\n+\telse\n+\t\tcycles = -(((s64)-adj) << 32);\n+\n+\tfor (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {\n+\t\tenum ice_status status;\n+\n+\t\tstatus = ice_ptp_prep_port_adj_e822(hw, port, cycles,\n+\t\t\t\t\t\t    lock_sbq);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment\n+ * @hw: pointer to HW struct\n+ * @incval: new increment value to prepare\n+ *\n+ * Prepare each of the PHY ports for a new increment value by programming the\n+ * port's TIMETUS registers. The new increment value will be updated after\n+ * issuing an INIT_INCVAL command.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)\n+{\n+\tenum ice_status status;\n+\tu8 port;\n+\n+\tfor (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {\n+\t\tstatus = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,\n+\t\t\t\t\t\t    incval);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+\n+exit_err:\n+\tice_debug(hw, ICE_DBG_PTP, \"Failed to write incval for port %u, status %d\\n\",\n+\t\t  port, status);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_ptp_read_phy_incval_e822 - Read a PHY port's current incval\n+ * @hw: pointer to the HW struct\n+ * @port: the port to read\n+ * @incval: on return, the time_clk_cyc incval for this port\n+ *\n+ * Read the time_clk_cyc increment value for a given PHY port.\n+ */\n+enum ice_status\n+ice_ptp_read_phy_incval_e822(struct ice_hw *hw, u8 port, u64 *incval)\n+{\n+\tenum ice_status status;\n+\n+\tstatus = ice_read_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read TIMETUS_L, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tice_debug(hw, ICE_DBG_PTP, \"read INCVAL = 0x%016llx\\n\",\n+\t\t  (unsigned long long)*incval);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_adj_target_e822 - Prepare PHY for adjust at target time\n+ * @hw: pointer to HW struct\n+ * @target_time: target time to program\n+ *\n+ * Program the PHY port Tx and Rx TIMER_CNT_ADJ registers used for the\n+ * ADJ_TIME_AT_TIME command. This should be used in conjunction with\n+ * ice_ptp_prep_phy_adj_e822 to program an atomic adjustment that is\n+ * delayed until a specified target time.\n+ *\n+ * Note that a target time adjustment is not currently supported on E810\n+ * devices.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_adj_target_e822(struct ice_hw *hw, u32 target_time)\n+{\n+\tenum ice_status status;\n+\tu8 port;\n+\n+\tfor (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {\n+\n+\t\t/* Tx case */\n+\t\t/* No sub-nanoseconds data */\n+\t\tstatus = ice_write_phy_reg_e822_lp(hw, port,\n+\t\t\t\t\t\t   P_REG_TX_TIMER_CNT_ADJ_L,\n+\t\t\t\t\t\t   0, true);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\n+\t\tstatus = ice_write_phy_reg_e822_lp(hw, port,\n+\t\t\t\t\t\t   P_REG_TX_TIMER_CNT_ADJ_U,\n+\t\t\t\t\t\t   target_time, true);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\n+\t\t/* Rx case */\n+\t\t/* No sub-nanoseconds data */\n+\t\tstatus = ice_write_phy_reg_e822_lp(hw, port,\n+\t\t\t\t\t\t   P_REG_RX_TIMER_CNT_ADJ_L,\n+\t\t\t\t\t\t   0, true);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\n+\t\tstatus = ice_write_phy_reg_e822_lp(hw, port,\n+\t\t\t\t\t\t   P_REG_RX_TIMER_CNT_ADJ_U,\n+\t\t\t\t\t\t   target_time, true);\n+\t\tif (status)\n+\t\t\tgoto exit_err;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+\n+exit_err:\n+\tice_debug(hw, ICE_DBG_PTP, \"Failed to write target time for port %u, status %d\\n\",\n+\t\t  port, status);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_ptp_read_port_capture - Read a port's local time capture\n+ * @hw: pointer to HW struct\n+ * @port: Port number to read\n+ * @tx_ts: on return, the Tx port time capture\n+ * @rx_ts: on return, the Rx port time capture\n+ *\n+ * Read the port's Tx and Rx local time capture values.\n+ *\n+ * Note this has no equivalent for the E810 devices.\n+ */\n+enum ice_status\n+ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)\n+{\n+\tenum ice_status status;\n+\n+\t/* Tx case */\n+\tstatus = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read REG_TX_CAPTURE, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tice_debug(hw, ICE_DBG_PTP, \"tx_init = 0x%016llx\\n\",\n+\t\t  (unsigned long long)*tx_ts);\n+\n+\t/* Rx case */\n+\tstatus = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read RX_CAPTURE, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tice_debug(hw, ICE_DBG_PTP, \"rx_init = 0x%016llx\\n\",\n+\t\t  (unsigned long long)*rx_ts);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command\n+ * @hw: pointer to HW struct\n+ * @port: Port to which cmd has to be sent\n+ * @cmd: Command to be sent to the port\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Prepare the requested port for an upcoming timer sync command.\n+ *\n+ * Note there is no equivalent of this operation on E810, as that device\n+ * always handles all external PHYs internally.\n+ */\n+enum ice_status\n+ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd,\n+\t\t     bool lock_sbq)\n+{\n+\tenum ice_status status;\n+\tu32 cmd_val, val;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = ice_get_ptp_src_clock_index(hw);\n+\tcmd_val = tmr_idx << SEL_PHY_SRC;\n+\tswitch (cmd) {\n+\tcase INIT_TIME:\n+\t\tcmd_val |= PHY_CMD_INIT_TIME;\n+\t\tbreak;\n+\tcase INIT_INCVAL:\n+\t\tcmd_val |= PHY_CMD_INIT_INCVAL;\n+\t\tbreak;\n+\tcase ADJ_TIME:\n+\t\tcmd_val |= PHY_CMD_ADJ_TIME;\n+\t\tbreak;\n+\tcase ADJ_TIME_AT_TIME:\n+\t\tcmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;\n+\t\tbreak;\n+\tcase READ_TIME:\n+\t\tcmd_val |= PHY_CMD_READ_TIME;\n+\t\tbreak;\n+\tdefault:\n+\t\tice_warn(hw, \"Unknown timer command %u\\n\", cmd);\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\t/* Tx case */\n+\t/* Read, modify, write */\n+\tstatus = ice_read_phy_reg_e822_lp(hw, port, P_REG_TX_TMR_CMD, &val,\n+\t\t\t\t\t  lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read TX_TMR_CMD, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* Modify necessary bits only and perform write */\n+\tval &= ~TS_CMD_MASK;\n+\tval |= cmd_val;\n+\n+\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TMR_CMD, val,\n+\t\t\t\t\t   lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write back TX_TMR_CMD, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* Rx case */\n+\t/* Read, modify, write */\n+\tstatus = ice_read_phy_reg_e822_lp(hw, port, P_REG_RX_TMR_CMD, &val,\n+\t\t\t\t\t  lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read RX_TMR_CMD, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* Modify necessary bits only and perform write */\n+\tval &= ~TS_CMD_MASK;\n+\tval |= cmd_val;\n+\n+\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TMR_CMD, val,\n+\t\t\t\t\t   lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write back RX_TMR_CMD, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command\n+ * @hw: pointer to the HW struct\n+ * @cmd: timer command to prepare\n+ * @lock_sbq: true if the sideband queue lock must  be acquired\n+ *\n+ * Prepare all ports connected to this device for an upcoming timer sync\n+ * command.\n+ */\n+static enum ice_status\n+ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,\n+\t\t      bool lock_sbq)\n+{\n+\tu8 port;\n+\n+\tfor (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {\n+\t\tenum ice_status status;\n+\n+\t\tstatus = ice_ptp_one_port_cmd(hw, port, cmd, lock_sbq);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/* E822 Vernier calibration functions\n+ *\n+ * The following functions are used as part of the vernier calibration of\n+ * a port. This calibration increases the precision of the timestamps on the\n+ * port.\n+ */\n+\n+/**\n+ * ice_ptp_set_vernier_wl - Set the window length for vernier calibration\n+ * @hw: pointer to the HW struct\n+ *\n+ * Set the window length used for the vernier port calibration process.\n+ */\n+enum ice_status ice_ptp_set_vernier_wl(struct ice_hw *hw)\n+{\n+\tu8 port;\n+\n+\tfor (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {\n+\t\tenum ice_status status;\n+\n+\t\tstatus = ice_write_phy_reg_e822_lp(hw, port, P_REG_WL,\n+\t\t\t\t\t\t   PTP_VERNIER_WL, true);\n+\t\tif (status) {\n+\t\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to set vernier window length for port %u, status %d\\n\",\n+\t\t\t\t  port, status);\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode\n+ * @hw: pointer to HW struct\n+ * @port: the port to read from\n+ * @link_out: if non-NULL, holds link speed on success\n+ * @fec_out: if non-NULL, holds FEC algorithm on success\n+ *\n+ * Read the serdes data for the PHY port and extract the link speed and FEC\n+ * algorithm.\n+ */\n+enum ice_status\n+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+{\n+\tenum ice_ptp_link_spd link;\n+\tenum ice_ptp_fec_mode fec;\n+\tenum ice_status status;\n+\tu32 serdes;\n+\n+\tstatus = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read serdes info\\n\");\n+\t\treturn status;\n+\t}\n+\n+\t/* Determine the FEC algorithm */\n+\tfec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes);\n+\n+\tserdes &= P_REG_LINK_SPEED_SERDES_M;\n+\n+\t/* Determine the link speed */\n+\tif (fec == ICE_PTP_FEC_MODE_RS_FEC) {\n+\t\tswitch (serdes) {\n+\t\tcase ICE_PTP_SERDES_25G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_25G_RS;\n+\t\t\tbreak;\n+\t\tcase ICE_PTP_SERDES_50G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_50G_RS;\n+\t\t\tbreak;\n+\t\tcase ICE_PTP_SERDES_100G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_100G_RS;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\t\t}\n+\t} else {\n+\t\tswitch (serdes) {\n+\t\tcase ICE_PTP_SERDES_1G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_1G;\n+\t\t\tbreak;\n+\t\tcase ICE_PTP_SERDES_10G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_10G;\n+\t\t\tbreak;\n+\t\tcase ICE_PTP_SERDES_25G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_25G;\n+\t\t\tbreak;\n+\t\tcase ICE_PTP_SERDES_40G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_40G;\n+\t\t\tbreak;\n+\t\tcase ICE_PTP_SERDES_50G:\n+\t\t\tlink = ICE_PTP_LNK_SPD_50G;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn ICE_ERR_OUT_OF_RANGE;\n+\t\t}\n+\t}\n+\n+\tif (link_out)\n+\t\t*link_out = link;\n+\tif (fec_out)\n+\t\t*fec_out = fec;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp\n+ * @hw: pointer to HW struct\n+ * @port: to configure the quad for\n+ */\n+void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)\n+{\n+\tenum ice_ptp_link_spd link_spd;\n+\tenum ice_status status;\n+\tu32 val;\n+\tu8 quad;\n+\n+\tstatus = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to get PHY link speed, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn;\n+\t}\n+\n+\tquad = port / ICE_PORTS_PER_QUAD;\n+\n+\tstatus = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read TX_MEM_GLB_CFG, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn;\n+\t}\n+\n+\tif (link_spd >= ICE_PTP_LNK_SPD_40G)\n+\t\tval &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;\n+\telse\n+\t\tval |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;\n+\n+\tstatus = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write back TX_MEM_GBL_CFG, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn;\n+\t}\n+}\n+\n+/* E810 functions\n+ *\n+ * The following functions operate on the E810 series devices which use\n+ * a separate external PHY.\n+ */\n+\n+/**\n+ * ice_read_phy_reg_e810_lp - Read register from external PHY on E810\n+ * @hw: pointer to the HW struct\n+ * @addr: the address to read from\n+ * @val: On return, the value read from the PHY\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Read a register from the external PHY on the E810 device.\n+ */\n+static enum ice_status\n+ice_read_phy_reg_e810_lp(struct ice_hw *hw, u32 addr, u32 *val, bool lock_sbq)\n+{\n+\tstruct ice_sbq_msg_input msg = {0};\n+\tenum ice_status status;\n+\n+\tmsg.msg_addr_low = ICE_LO_WORD(addr);\n+\tmsg.msg_addr_high = ICE_HI_WORD(addr);\n+\tmsg.opcode = ice_sbq_msg_rd;\n+\tmsg.dest_dev = rmn_0;\n+\n+\tstatus = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to send message to phy, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t*val = msg.data;\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+static enum ice_status\n+ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)\n+{\n+\treturn ice_read_phy_reg_e810_lp(hw, addr, val, true);\n+}\n+\n+/**\n+ * ice_write_phy_reg_e810_lp - Write register on external PHY on E810\n+ * @hw: pointer to the HW struct\n+ * @addr: the address to writem to\n+ * @val: the value to write to the PHY\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Write a value to a register of the external PHY on the E810 device.\n+ */\n+static enum ice_status\n+ice_write_phy_reg_e810_lp(struct ice_hw *hw, u32 addr, u32 val, bool lock_sbq)\n+{\n+\tstruct ice_sbq_msg_input msg = {0};\n+\tenum ice_status status;\n+\n+\tmsg.msg_addr_low = ICE_LO_WORD(addr);\n+\tmsg.msg_addr_high = ICE_HI_WORD(addr);\n+\tmsg.opcode = ice_sbq_msg_wr;\n+\tmsg.dest_dev = rmn_0;\n+\tmsg.data = val;\n+\n+\tstatus = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to send message to phy, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+static enum ice_status\n+ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)\n+{\n+\treturn ice_write_phy_reg_e810_lp(hw, addr, val, true);\n+}\n+\n+/**\n+ * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY\n+ * @hw: pointer to the HW struct\n+ * @lport: the lport to read from\n+ * @idx: the timestamp index to read\n+ * @tstamp: on return, the 40bit timestamp value\n+ *\n+ * Read a 40bit timestamp value out of the timestamp block of the external PHY\n+ * on the E810 device.\n+ */\n+static enum ice_status\n+ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)\n+{\n+\tenum ice_status status;\n+\tu32 lo_addr, hi_addr, lo, hi;\n+\n+\tlo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);\n+\thi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);\n+\n+\tstatus = ice_read_phy_reg_e810(hw, lo_addr, &lo);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read low PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_read_phy_reg_e810(hw, hi_addr, &hi);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read high PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* For E810 devices, the timestamp is reported with the lower 32 bits\n+\t * in the low register, and the upper 8 bits in the high register.\n+\t */\n+\t*tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY\n+ * @hw: pointer to the HW struct\n+ * @lport: the lport to read from\n+ * @idx: the timestamp index to reset\n+ *\n+ * Clear a timestamp, resetting its valid bit, from the timestamp block of the\n+ * external PHY on the E810 device.\n+ */\n+static enum ice_status\n+ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)\n+{\n+\tenum ice_status status;\n+\tu32 lo_addr, hi_addr;\n+\n+\tlo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);\n+\thi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);\n+\n+\tstatus = ice_write_phy_reg_e810(hw, lo_addr, 0);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to clear low PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e810(hw, hi_addr, 0);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to clear high PTP timestamp register, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY\n+ * @hw: pointer to HW struct\n+ *\n+ * Enable the timesync PTP functionality for the external PHY connected to\n+ * this function.\n+ *\n+ * Note there is no equivalent function needed on E822 based devices.\n+ */\n+enum ice_status ice_ptp_init_phy_e810(struct ice_hw *hw)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),\n+\t\t\t\t\tGLTSYN_ENA_TSYN_ENA_M);\n+\tif (status)\n+\t\tice_debug(hw, ICE_DBG_PTP, \"PTP failed in ena_phy_time_syn %d\\n\",\n+\t\t\t  status);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time\n+ * @hw: Board private structure\n+ * @time: Time to initialize the PHY port clock to\n+ *\n+ * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the\n+ * initial clock time. The time will not actually be programmed until the\n+ * driver issues an INIT_TIME command.\n+ *\n+ * The time value is the upper 32 bits of the PHY timer, usually in units of\n+ * nominal nanoseconds.\n+ */\n+static enum ice_status ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write SHTIME_0, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write SHTIME_L, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment\n+ * @hw: pointer to HW struct\n+ * @adj: adjustment value to program\n+ * @lock_sbq: true if the sideband queue luck must be acquired\n+ *\n+ * Prepare the PHY port for an atomic adjustment by programming the PHY\n+ * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment\n+ * is completed by issuing an ADJ_TIME sync command.\n+ *\n+ * The adjustment value only contains the portion used for the upper 32bits of\n+ * the PHY timer, usually in units of nominal nanoseconds. Negative\n+ * adjustments are supported using 2s complement arithmetic.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj, bool lock_sbq)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\n+\t/* Adjustments are represented as signed 2's complement values in\n+\t * nanoseconds. Sub-nanosecond adjustment is not supported.\n+\t */\n+\tstatus = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_SHADJ_L(tmr_idx),\n+\t\t\t\t\t   0, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write adj to PHY SHADJ_L, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_SHADJ_H(tmr_idx),\n+\t\t\t\t\t   adj, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write adj to PHY SHADJ_H, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change\n+ * @hw: pointer to HW struct\n+ * @incval: The new 40bit increment value to prepare\n+ *\n+ * Prepare the PHY port for a new increment value by programming the PHY\n+ * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is\n+ * completed by issuing an INIT_INCVAL command.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)\n+{\n+\tenum ice_status status;\n+\tu32 high, low;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\tlow = ICE_LO_DWORD(incval);\n+\thigh = ICE_HI_DWORD(incval);\n+\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write incval to PHY SHADJ_L, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write incval PHY SHADJ_H, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_prep_phy_adj_target_e810 - Prepare PHY port with adjust target\n+ * @hw: Board private structure\n+ * @target_time: Time to trigger the clock adjustment at\n+ *\n+ * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation for\n+ * a target time adjust, which will trigger an adjustment of the clock in the\n+ * future. The actual adjustment will occur the next time the PHY port timer\n+ * crosses over the provided value after the driver issues an ADJ_TIME_AT_TIME\n+ * command.\n+ *\n+ * The time value is the upper 32 bits of the PHY timer, usually in units of\n+ * nominal nanoseconds.\n+ */\n+static enum ice_status\n+ice_ptp_prep_phy_adj_target_e810(struct ice_hw *hw, u32 target_time)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write target time to SHTIME_0, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx),\n+\t\t\t\t\ttarget_time);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write target time to SHTIME_L, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command\n+ * @hw: pointer to HW struct\n+ * @cmd: Command to be sent to the port\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Prepare the external PHYs connected to this device for a timer sync\n+ * command.\n+ */\n+static enum ice_status\n+ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,\n+\t\t      bool lock_sbq)\n+{\n+\tenum ice_status status;\n+\tu32 cmd_val, val;\n+\n+\tswitch (cmd) {\n+\tcase INIT_TIME:\n+\t\tcmd_val = GLTSYN_CMD_INIT_TIME;\n+\t\tbreak;\n+\tcase INIT_INCVAL:\n+\t\tcmd_val = GLTSYN_CMD_INIT_INCVAL;\n+\t\tbreak;\n+\tcase ADJ_TIME:\n+\t\tcmd_val = GLTSYN_CMD_ADJ_TIME;\n+\t\tbreak;\n+\tcase ADJ_TIME_AT_TIME:\n+\t\tcmd_val = GLTSYN_CMD_ADJ_INIT_TIME;\n+\t\tbreak;\n+\tcase READ_TIME:\n+\t\tcmd_val = GLTSYN_CMD_READ_TIME;\n+\t\tbreak;\n+\tdefault:\n+\t\tice_warn(hw, \"Unknown timer command %u\\n\", cmd);\n+\t\treturn ICE_ERR_PARAM;\n+\t}\n+\n+\t/* Read, modify, write */\n+\tstatus = ice_read_phy_reg_e810_lp(hw, ETH_GLTSYN_CMD, &val, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to read GLTSYN_CMD, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\t/* Modify necessary bits only and perform write */\n+\tval &= ~TS_CMD_MASK_E810;\n+\tval |= cmd_val;\n+\n+\tstatus = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_CMD, val, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to write back GLTSYN_CMD, status %d\\n\",\n+\t\t\t  status);\n+\t\treturn status;\n+\t}\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/* Device agnostic functions\n+ *\n+ * The following functions implement shared behavior common to both E822 and\n+ * E810 devices, possibly calling a device specific implementation where\n+ * necessary.\n+ */\n+\n+/**\n+ * ice_ptp_lock - Acquire PTP global semaphore register lock\n+ * @hw: pointer to the HW struct\n+ *\n+ * Acquire the global PTP hardware semaphore lock. Returns true if the lock\n+ * was acquired, false otherwise.\n+ *\n+ * The PFTSYN_SEM register sets the busy bit on read, returning the previous\n+ * value. If software sees the busy bit cleared, this means that this function\n+ * acquired the lock (and the busy bit is now set). If software sees the busy\n+ * bit set, it means that another function acquired the lock.\n+ *\n+ * Software must clear the busy bit with a write to release the lock for other\n+ * functions when done.\n+ */\n+bool ice_ptp_lock(struct ice_hw *hw)\n+{\n+\tu32 hw_lock;\n+\tint i;\n+\n+#define MAX_TRIES 5\n+\n+\tfor (i = 0; i < MAX_TRIES; i++) {\n+\t\thw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));\n+\t\thw_lock = hw_lock & PFTSYN_SEM_BUSY_M;\n+\t\tif (hw_lock) {\n+\t\t\t/* Somebody is holding the lock */\n+\t\t\tice_msec_delay(10, true);\n+\t\t\tcontinue;\n+\t\t} else {\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn !hw_lock;\n+}\n+\n+/**\n+ * ice_ptp_unlock - Release PTP global semaphore register lock\n+ * @hw: pointer to the HW struct\n+ *\n+ * Release the global PTP hardware semaphore lock. This is done by writing to\n+ * the PFTSYN_SEM register.\n+ */\n+void ice_ptp_unlock(struct ice_hw *hw)\n+{\n+\twr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);\n+}\n+\n+/**\n+ * ice_ptp_src_cmd - Prepare source timer for a timer command\n+ * @hw: pointer to HW structure\n+ * @cmd: Timer command\n+ *\n+ * Prepare the source timer for an upcoming timer sync command.\n+ */\n+void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)\n+{\n+\tu32 cmd_val;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = ice_get_ptp_src_clock_index(hw);\n+\tcmd_val = tmr_idx << SEL_CPK_SRC;\n+\n+\tswitch (cmd) {\n+\tcase INIT_TIME:\n+\t\tcmd_val |= GLTSYN_CMD_INIT_TIME;\n+\t\tbreak;\n+\tcase INIT_INCVAL:\n+\t\tcmd_val |= GLTSYN_CMD_INIT_INCVAL;\n+\t\tbreak;\n+\tcase ADJ_TIME:\n+\t\tcmd_val |= GLTSYN_CMD_ADJ_TIME;\n+\t\tbreak;\n+\tcase ADJ_TIME_AT_TIME:\n+\t\tcmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;\n+\t\tbreak;\n+\tcase READ_TIME:\n+\t\tcmd_val |= GLTSYN_CMD_READ_TIME;\n+\t\tbreak;\n+\tdefault:\n+\t\tice_warn(hw, \"Unknown timer command %u\\n\", cmd);\n+\t\treturn;\n+\t}\n+\n+\twr32(hw, GLTSYN_CMD, cmd_val);\n+}\n+\n+/**\n+ * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command\n+ * @hw: pointer to HW struct\n+ * @cmd: the command to issue\n+ * @lock_sbq: true if the sideband queue lock must be acquired\n+ *\n+ * Prepare the source timer and PHY timers and then trigger the requested\n+ * command. This causes the shadow registers previously written in preparation\n+ * for the command to be synchronously applied to both the source and PHY\n+ * timers.\n+ */\n+static enum ice_status\n+ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd, bool lock_sbq)\n+{\n+\tenum ice_status status;\n+\n+\t/* First, prepare the source timer */\n+\tice_ptp_src_cmd(hw, cmd);\n+\n+\t/* Next, prepare the ports */\n+\tif (ice_is_e810(hw))\n+\t\tstatus = ice_ptp_port_cmd_e810(hw, cmd, lock_sbq);\n+\telse\n+\t\tstatus = ice_ptp_port_cmd_e822(hw, cmd, lock_sbq);\n+\tif (status) {\n+\t\tice_debug(hw, ICE_DBG_PTP, \"Failed to prepare PHY ports for timer command %u, status %d\\n\",\n+\t\t\t  cmd, status);\n+\t\treturn status;\n+\t}\n+\n+\t/* Write the sync command register to drive both source and PHY timer\n+\t * commands synchronously\n+\t */\n+\tice_ptp_exec_tmr_cmd(hw);\n+\n+\treturn ICE_SUCCESS;\n+}\n+\n+/**\n+ * ice_ptp_init_time - Initialize device time to provided value\n+ * @hw: pointer to HW struct\n+ * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)\n+ *\n+ * Initialize the device to the specified time provided. This requires a three\n+ * step process:\n+ *\n+ * 1) write the new init time to the source timer shadow registers\n+ * 2) write the new init time to the phy timer shadow registers\n+ * 3) issue an init_time timer command to synchronously switch both the source\n+ *    and port timers to the new init time value at the next clock cycle.\n+ */\n+enum ice_status ice_ptp_init_time(struct ice_hw *hw, u64 time)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\n+\t/* Source timers */\n+\twr32(hw, GLTSYN_SHTIME_L(tmr_idx), ICE_LO_DWORD(time));\n+\twr32(hw, GLTSYN_SHTIME_H(tmr_idx), ICE_HI_DWORD(time));\n+\twr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);\n+\n+\t/* PHY Clks */\n+\t/* Fill Rx and Tx ports and send msg to PHY */\n+\tif (ice_is_e810(hw))\n+\t\tstatus = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);\n+\telse\n+\t\tstatus = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ice_ptp_tmr_cmd(hw, INIT_TIME, true);\n+}\n+\n+/**\n+ * ice_ptp_write_incval - Program PHC with new increment value\n+ * @hw: pointer to HW struct\n+ * @incval: Source timer increment value per clock cycle\n+ *\n+ * Program the PHC with a new increment value. This requires a three-step\n+ * process:\n+ *\n+ * 1) Write the increment value to the source timer shadow registers\n+ * 2) Write the increment value to the PHY timer shadow registers\n+ * 3) Issue an INIT_INCVAL timer command to synchronously switch both the\n+ *    source and port timers to the new increment value at the next clock\n+ *    cycle.\n+ */\n+enum ice_status ice_ptp_write_incval(struct ice_hw *hw, u64 incval)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\n+\t/* Shadow Adjust */\n+\twr32(hw, GLTSYN_SHADJ_L(tmr_idx), ICE_LO_DWORD(incval));\n+\twr32(hw, GLTSYN_SHADJ_H(tmr_idx), ICE_HI_DWORD(incval));\n+\n+\tif (ice_is_e810(hw))\n+\t\tstatus = ice_ptp_prep_phy_incval_e810(hw, incval);\n+\telse\n+\t\tstatus = ice_ptp_prep_phy_incval_e822(hw, incval);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ice_ptp_tmr_cmd(hw, INIT_INCVAL, true);\n+}\n+\n+/**\n+ * ice_ptp_write_incval_locked - Program new incval while holding semaphore\n+ * @hw: pointer to HW struct\n+ * @incval: Source timer increment value per clock cycle\n+ *\n+ * Program a new PHC incval while holding the PTP semaphore.\n+ */\n+enum ice_status ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)\n+{\n+\tenum ice_status status;\n+\n+\tif (!ice_ptp_lock(hw))\n+\t\treturn ICE_ERR_NOT_READY;\n+\n+\tstatus = ice_ptp_write_incval(hw, incval);\n+\n+\tice_ptp_unlock(hw);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_ptp_adj_clock - Adjust PHC clock time atomically\n+ * @hw: pointer to HW struct\n+ * @adj: Adjustment in nanoseconds\n+ * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the\n+ *            sq_lock has already been locked at a higher level\n+ *\n+ * Perform an atomic adjustment of the PHC time by the specified number of\n+ * nanoseconds. This requires a three-step process:\n+ *\n+ * 1) Write the adjustment to the source timer shadow registers\n+ * 2) Write the adjustment to the PHY timer shadow registers\n+ * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to\n+ *    both the source and port timers at the next clock cycle.\n+ */\n+enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq)\n+{\n+\tenum ice_status status;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\n+\t/* Write the desired clock adjustment into the GLTSYN_SHADJ register.\n+\t * For an ADJ_TIME command, this set of registers represents the value\n+\t * to add to the clock time. It supports subtraction by interpreting\n+\t * the value as a 2's complement integer.\n+\t */\n+\twr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);\n+\twr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);\n+\n+\tif (ice_is_e810(hw))\n+\t\tstatus = ice_ptp_prep_phy_adj_e810(hw, adj, lock_sbq);\n+\telse\n+\t\tstatus = ice_ptp_prep_phy_adj_e822(hw, adj, lock_sbq);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ice_ptp_tmr_cmd(hw, ADJ_TIME, lock_sbq);\n+}\n+\n+/**\n+ * ice_ptp_adj_clock_at_time - Adjust PHC atomically at specified time\n+ * @hw: pointer to HW struct\n+ * @at_time: Time in nanoseconds at which to perform the adjustment\n+ * @adj: Adjustment in nanoseconds\n+ *\n+ * Perform an atomic adjustment to the PHC clock at the specified time. This\n+ * requires a five-step process:\n+ *\n+ * 1) Write the adjustment to the source timer shadow adjust registers\n+ * 2) Write the target time to the source timer shadow time registers\n+ * 3) Write the adjustment to the PHY timers shadow adjust registers\n+ * 4) Write the target time to the PHY timers shadow adjust registers\n+ * 5) Issue an ADJ_TIME_AT_TIME command to initiate the atomic adjustment.\n+ */\n+enum ice_status\n+ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj)\n+{\n+\tenum ice_status status;\n+\tu32 time_lo, time_hi;\n+\tu8 tmr_idx;\n+\n+\ttmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;\n+\ttime_lo = ICE_LO_DWORD(at_time);\n+\ttime_hi = ICE_HI_DWORD(at_time);\n+\n+\t/* Write the desired clock adjustment into the GLTSYN_SHADJ register.\n+\t * For an ADJ_TIME_AT_TIME command, this set of registers represents\n+\t * the value to add to the clock time. It supports subtraction by\n+\t * interpreting the value as a 2's complement integer.\n+\t */\n+\twr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);\n+\twr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);\n+\n+\t/* Write the target time to trigger the adjustment for source clock */\n+\twr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);\n+\twr32(hw, GLTSYN_SHTIME_L(tmr_idx), time_lo);\n+\twr32(hw, GLTSYN_SHTIME_H(tmr_idx), time_hi);\n+\n+\t/* Prepare PHY port adjustments */\n+\tif (ice_is_e810(hw))\n+\t\tstatus = ice_ptp_prep_phy_adj_e810(hw, adj, true);\n+\telse\n+\t\tstatus = ice_ptp_prep_phy_adj_e822(hw, adj, true);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* Set target time for each PHY port */\n+\tif (ice_is_e810(hw))\n+\t\tstatus = ice_ptp_prep_phy_adj_target_e810(hw, time_lo);\n+\telse\n+\t\tstatus = ice_ptp_prep_phy_adj_target_e822(hw, time_lo);\n+\tif (status)\n+\t\treturn status;\n+\n+\treturn ice_ptp_tmr_cmd(hw, ADJ_TIME_AT_TIME, true);\n+}\n+\n+/**\n+ * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block\n+ * @hw: pointer to the HW struct\n+ * @block: the block to read from\n+ * @idx: the timestamp index to read\n+ * @tstamp: on return, the 40bit timestamp value\n+ *\n+ * Read a 40bit timestamp value out of the timestamp block. For E822 devices,\n+ * the block is the quad to read from. For E810 devices, the block is the\n+ * logical port to read from.\n+ */\n+enum ice_status\n+ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)\n+{\n+\tif (ice_is_e810(hw))\n+\t\treturn ice_read_phy_tstamp_e810(hw, block, idx, tstamp);\n+\telse\n+\t\treturn ice_read_phy_tstamp_e822(hw, block, idx, tstamp);\n+}\n+\n+/**\n+ * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block\n+ * @hw: pointer to the HW struct\n+ * @block: the block to read from\n+ * @idx: the timestamp index to reset\n+ *\n+ * Clear a timestamp, resetting its valid bit, from the timestamp block. For\n+ * E822 devices, the block is the quad to clear from. For E810 devices, the\n+ * block is the logical port to clear from.\n+ */\n+enum ice_status\n+ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)\n+{\n+\tif (ice_is_e810(hw))\n+\t\treturn ice_clear_phy_tstamp_e810(hw, block, idx);\n+\telse\n+\t\treturn ice_clear_phy_tstamp_e822(hw, block, idx);\n+}\ndiff --git a/drivers/net/ice/base/ice_ptp_hw.h b/drivers/net/ice/base/ice_ptp_hw.h\nnew file mode 100644\nindex 0000000..8cbe817\n--- /dev/null\n+++ b/drivers/net/ice/base/ice_ptp_hw.h\n@@ -0,0 +1,376 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2001-2021 Intel Corporation\n+ */\n+\n+#ifndef _ICE_PTP_HW_H_\n+#define _ICE_PTP_HW_H_\n+\n+enum ice_ptp_tmr_cmd {\n+\tINIT_TIME,\n+\tINIT_INCVAL,\n+\tADJ_TIME,\n+\tADJ_TIME_AT_TIME,\n+\tREAD_TIME\n+};\n+\n+enum ice_ptp_serdes {\n+\tICE_PTP_SERDES_1G,\n+\tICE_PTP_SERDES_10G,\n+\tICE_PTP_SERDES_25G,\n+\tICE_PTP_SERDES_40G,\n+\tICE_PTP_SERDES_50G,\n+\tICE_PTP_SERDES_100G\n+};\n+\n+enum ice_ptp_link_spd {\n+\tICE_PTP_LNK_SPD_1G,\n+\tICE_PTP_LNK_SPD_10G,\n+\tICE_PTP_LNK_SPD_25G,\n+\tICE_PTP_LNK_SPD_25G_RS,\n+\tICE_PTP_LNK_SPD_40G,\n+\tICE_PTP_LNK_SPD_50G,\n+\tICE_PTP_LNK_SPD_50G_RS,\n+\tICE_PTP_LNK_SPD_100G_RS,\n+\tNUM_ICE_PTP_LNK_SPD /* Must be last */\n+};\n+\n+enum ice_ptp_fec_mode {\n+\tICE_PTP_FEC_MODE_NONE,\n+\tICE_PTP_FEC_MODE_CLAUSE74,\n+\tICE_PTP_FEC_MODE_RS_FEC\n+};\n+\n+/**\n+ * struct ice_time_ref_info_e822\n+ * @pll_freq: Frequency of PLL that drives timer ticks in Hz\n+ * @nominal_incval: increment to generate nanoseconds in GLTSYN_TIME_L\n+ * @pps_delay: propagation delay of the PPS output signal\n+ *\n+ * Characteristic information for the various TIME_REF sources possible in the\n+ * E822 devices\n+ */\n+struct ice_time_ref_info_e822 {\n+\tu64 pll_freq;\n+\tu64 nominal_incval;\n+\tu8 pps_delay;\n+};\n+\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+/* 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+#define ICE_PTP_NOMINAL_INCVAL_E810 0x13b13b13bULL\n+\n+/* Device agnostic functions */\n+u8 ice_get_ptp_src_clock_index(struct ice_hw *hw);\n+u64 ice_ptp_read_src_incval(struct ice_hw *hw);\n+bool ice_ptp_lock(struct ice_hw *hw);\n+void ice_ptp_unlock(struct ice_hw *hw);\n+void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd);\n+enum ice_status ice_ptp_init_time(struct ice_hw *hw, u64 time);\n+enum ice_status ice_ptp_write_incval(struct ice_hw *hw, u64 incval);\n+enum ice_status ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval);\n+enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq);\n+enum ice_status\n+ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj);\n+enum ice_status\n+ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp);\n+enum ice_status\n+ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx);\n+\n+/* E822 family functions */\n+enum ice_status\n+ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val);\n+enum ice_status\n+ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val);\n+enum ice_status\n+ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val);\n+enum ice_status\n+ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val);\n+enum ice_status\n+ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time,\n+\t\t\t   bool lock_sbq);\n+enum ice_status\n+ice_ptp_read_phy_incval_e822(struct ice_hw *hw, u8 port, u64 *incval);\n+enum ice_status\n+ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts);\n+enum ice_status\n+ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd,\n+\t\t     bool lock_sbq);\n+\n+static inline u64 ice_e822_pll_freq(enum ice_time_ref_freq time_ref)\n+{\n+\treturn e822_time_ref[time_ref].pll_freq;\n+}\n+\n+static inline u64 ice_e822_nominal_incval(enum ice_time_ref_freq time_ref)\n+{\n+\treturn e822_time_ref[time_ref].nominal_incval;\n+}\n+\n+static inline u64 ice_e822_pps_delay(enum ice_time_ref_freq time_ref)\n+{\n+\treturn e822_time_ref[time_ref].pps_delay;\n+}\n+\n+/* E822 Vernier calibration functions */\n+enum ice_status ice_ptp_set_vernier_wl(struct ice_hw *hw);\n+enum ice_status\n+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+\n+/* E810 family functions */\n+enum ice_status ice_ptp_init_phy_e810(struct ice_hw *hw);\n+\n+#define PFTSYN_SEM_BYTES\t4\n+\n+#define ICE_PTP_CLOCK_INDEX_0\t0x00\n+#define ICE_PTP_CLOCK_INDEX_1\t0x01\n+\n+/* PHY timer commands */\n+#define SEL_CPK_SRC\t8\n+#define SEL_PHY_SRC\t3\n+\n+/* Time Sync command Definitions */\n+#define GLTSYN_CMD_INIT_TIME\t\tBIT(0)\n+#define GLTSYN_CMD_INIT_INCVAL\t\tBIT(1)\n+#define GLTSYN_CMD_INIT_TIME_INCVAL\t(BIT(0) | BIT(1))\n+#define GLTSYN_CMD_ADJ_TIME\t\tBIT(2)\n+#define GLTSYN_CMD_ADJ_INIT_TIME\t(BIT(2) | BIT(3))\n+#define GLTSYN_CMD_READ_TIME\t\tBIT(7)\n+\n+/* PHY port Time Sync command definitions */\n+#define PHY_CMD_INIT_TIME\t\tBIT(0)\n+#define PHY_CMD_INIT_INCVAL\t\tBIT(1)\n+#define PHY_CMD_ADJ_TIME\t\t(BIT(0) | BIT(1))\n+#define PHY_CMD_ADJ_TIME_AT_TIME\t(BIT(0) | BIT(2))\n+#define PHY_CMD_READ_TIME\t\t(BIT(0) | BIT(1) | BIT(2))\n+\n+#define TS_CMD_MASK_E810\t\t0xFF\n+#define TS_CMD_MASK\t\t\t0xF\n+#define SYNC_EXEC_CMD\t\t\t0x3\n+\n+/* Macros to derive port low and high addresses on both quads */\n+#define P_Q0_L(a, p) ((((a) + (0x2000 * (p)))) & 0xFFFF)\n+#define P_Q0_H(a, p) ((((a) + (0x2000 * (p)))) >> 16)\n+#define P_Q1_L(a, p) ((((a) - (0x2000 * ((p) - ICE_PORTS_PER_QUAD)))) & 0xFFFF)\n+#define P_Q1_H(a, p) ((((a) - (0x2000 * ((p) - ICE_PORTS_PER_QUAD)))) >> 16)\n+\n+/* PHY QUAD register base addresses */\n+#define Q_0_BASE\t\t\t0x94000\n+#define Q_1_BASE\t\t\t0x114000\n+\n+/* Timestamp memory reset registers */\n+#define Q_REG_TS_CTRL\t\t\t0x618\n+#define Q_REG_TS_CTRL_S\t\t\t0\n+#define Q_REG_TS_CTRL_M\t\t\tBIT(0)\n+\n+/* Timestamp availability status registers */\n+#define Q_REG_TX_MEMORY_STATUS_L\t0xCF0\n+#define Q_REG_TX_MEMORY_STATUS_U\t0xCF4\n+\n+/* Tx FIFO status registers */\n+#define Q_REG_FIFO23_STATUS\t\t0xCF8\n+#define Q_REG_FIFO01_STATUS\t\t0xCFC\n+#define Q_REG_FIFO02_S\t\t\t0\n+#define Q_REG_FIFO02_M\t\t\tMAKEMASK(0x3FF, 0)\n+#define Q_REG_FIFO13_S\t\t\t10\n+#define Q_REG_FIFO13_M\t\t\tMAKEMASK(0x3FF, 10)\n+\n+/* Interrupt control Config registers */\n+#define Q_REG_TX_MEM_GBL_CFG\t\t0xC08\n+#define Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_S\t0\n+#define Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M\tBIT(0)\n+#define Q_REG_TX_MEM_GBL_CFG_TX_TYPE_S\t1\n+#define Q_REG_TX_MEM_GBL_CFG_TX_TYPE_M\tMAKEMASK(0xFF, 1)\n+#define Q_REG_TX_MEM_GBL_CFG_INTR_THR_S\t9\n+#define Q_REG_TX_MEM_GBL_CFG_INTR_THR_M MAKEMASK(0x3F, 9)\n+#define Q_REG_TX_MEM_GBL_CFG_INTR_ENA_S\t15\n+#define Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M\tBIT(15)\n+\n+/* Tx Timestamp data registers */\n+#define Q_REG_TX_MEMORY_BANK_START\t0xA00\n+\n+/* PHY port register base addresses */\n+#define P_0_BASE\t\t\t0x80000\n+#define P_4_BASE\t\t\t0x106000\n+\n+/* Timestamp init registers */\n+#define P_REG_RX_TIMER_INC_PRE_L\t0x46C\n+#define P_REG_RX_TIMER_INC_PRE_U\t0x470\n+#define P_REG_TX_TIMER_INC_PRE_L\t0x44C\n+#define P_REG_TX_TIMER_INC_PRE_U\t0x450\n+\n+/* Timestamp match and adjust target registers */\n+#define P_REG_RX_TIMER_CNT_ADJ_L\t0x474\n+#define P_REG_RX_TIMER_CNT_ADJ_U\t0x478\n+#define P_REG_TX_TIMER_CNT_ADJ_L\t0x454\n+#define P_REG_TX_TIMER_CNT_ADJ_U\t0x458\n+\n+/* Timestamp capture registers */\n+#define P_REG_RX_CAPTURE_L\t\t0x4D8\n+#define P_REG_RX_CAPTURE_U\t\t0x4DC\n+#define P_REG_TX_CAPTURE_L\t\t0x4B4\n+#define P_REG_TX_CAPTURE_U\t\t0x4B8\n+\n+/* Timestamp PHY incval registers */\n+#define P_REG_TIMETUS_L\t\t\t0x410\n+#define P_REG_TIMETUS_U\t\t\t0x414\n+\n+#define P_REG_40B_LOW_M\t\t\t0xFF\n+#define P_REG_40B_HIGH_S\t\t8\n+\n+/* PHY window length registers */\n+#define P_REG_WL\t\t\t0x40C\n+\n+#define PTP_VERNIER_WL\t\t\t0x111ed\n+\n+/* PHY start registers */\n+#define P_REG_PS\t\t\t0x408\n+#define P_REG_PS_START_S\t\t0\n+#define P_REG_PS_START_M\t\tBIT(0)\n+#define P_REG_PS_BYPASS_MODE_S\t\t1\n+#define P_REG_PS_BYPASS_MODE_M\t\tBIT(1)\n+#define P_REG_PS_ENA_CLK_S\t\t2\n+#define P_REG_PS_ENA_CLK_M\t\tBIT(2)\n+#define P_REG_PS_LOAD_OFFSET_S\t\t3\n+#define P_REG_PS_LOAD_OFFSET_M\t\tBIT(3)\n+#define P_REG_PS_SFT_RESET_S\t\t11\n+#define P_REG_PS_SFT_RESET_M\t\tBIT(11)\n+\n+/* PHY offset valid registers */\n+#define P_REG_TX_OV_STATUS\t\t0x4D4\n+#define P_REG_TX_OV_STATUS_OV_S\t\t0\n+#define P_REG_TX_OV_STATUS_OV_M\t\tBIT(0)\n+#define P_REG_RX_OV_STATUS\t\t0x4F8\n+#define P_REG_RX_OV_STATUS_OV_S\t\t0\n+#define P_REG_RX_OV_STATUS_OV_M\t\tBIT(0)\n+\n+/* PHY offset ready registers */\n+#define P_REG_TX_OR\t\t\t0x45C\n+#define P_REG_RX_OR\t\t\t0x47C\n+\n+/* PHY total offset registers */\n+#define P_REG_TOTAL_RX_OFFSET_L\t\t0x460\n+#define P_REG_TOTAL_RX_OFFSET_U\t\t0x464\n+#define P_REG_TOTAL_TX_OFFSET_L\t\t0x440\n+#define P_REG_TOTAL_TX_OFFSET_U\t\t0x444\n+\n+/* Timestamp PAR/PCS registers */\n+#define P_REG_UIX66_10G_40G_L\t\t0x480\n+#define P_REG_UIX66_10G_40G_U\t\t0x484\n+#define P_REG_UIX66_25G_100G_L\t\t0x488\n+#define P_REG_UIX66_25G_100G_U\t\t0x48C\n+#define P_REG_DESK_PAR_RX_TUS_L\t\t0x490\n+#define P_REG_DESK_PAR_RX_TUS_U\t\t0x494\n+#define P_REG_DESK_PAR_TX_TUS_L\t\t0x498\n+#define P_REG_DESK_PAR_TX_TUS_U\t\t0x49C\n+#define P_REG_DESK_PCS_RX_TUS_L\t\t0x4A0\n+#define P_REG_DESK_PCS_RX_TUS_U\t\t0x4A4\n+#define P_REG_DESK_PCS_TX_TUS_L\t\t0x4A8\n+#define P_REG_DESK_PCS_TX_TUS_U\t\t0x4AC\n+#define P_REG_PAR_RX_TUS_L\t\t0x420\n+#define P_REG_PAR_RX_TUS_U\t\t0x424\n+#define P_REG_PAR_TX_TUS_L\t\t0x428\n+#define P_REG_PAR_TX_TUS_U\t\t0x42C\n+#define P_REG_PCS_RX_TUS_L\t\t0x430\n+#define P_REG_PCS_RX_TUS_U\t\t0x434\n+#define P_REG_PCS_TX_TUS_L\t\t0x438\n+#define P_REG_PCS_TX_TUS_U\t\t0x43C\n+#define P_REG_PAR_RX_TIME_L\t\t0x4F0\n+#define P_REG_PAR_RX_TIME_U\t\t0x4F4\n+#define P_REG_PAR_TX_TIME_L\t\t0x4CC\n+#define P_REG_PAR_TX_TIME_U\t\t0x4D0\n+#define P_REG_PAR_PCS_RX_OFFSET_L\t0x4E8\n+#define P_REG_PAR_PCS_RX_OFFSET_U\t0x4EC\n+#define P_REG_PAR_PCS_TX_OFFSET_L\t0x4C4\n+#define P_REG_PAR_PCS_TX_OFFSET_U\t0x4C8\n+#define P_REG_LINK_SPEED\t\t0x4FC\n+#define P_REG_LINK_SPEED_SERDES_S\t0\n+#define P_REG_LINK_SPEED_SERDES_M\tMAKEMASK(0x7, 0)\n+#define P_REG_LINK_SPEED_FEC_MODE_S\t3\n+#define P_REG_LINK_SPEED_FEC_MODE_M\tMAKEMASK(0x3, 3)\n+#define P_REG_LINK_SPEED_FEC_MODE(reg)\t\t\t\\\n+\t(((reg) & P_REG_LINK_SPEED_FEC_MODE_M) >>\t\\\n+\t P_REG_LINK_SPEED_FEC_MODE_S)\n+\n+/* PHY timestamp related registers */\n+#define P_REG_PMD_ALIGNMENT\t\t0x0FC\n+#define P_REG_RX_80_TO_160_CNT\t\t0x6FC\n+#define P_REG_RX_80_TO_160_CNT_RXCYC_S\t0\n+#define P_REG_RX_80_TO_160_CNT_RXCYC_M\tBIT(0)\n+#define P_REG_RX_40_TO_160_CNT\t\t0x8FC\n+#define P_REG_RX_40_TO_160_CNT_RXCYC_S\t0\n+#define P_REG_RX_40_TO_160_CNT_RXCYC_M\tMAKEMASK(0x3, 0)\n+\n+/* Rx FIFO status registers */\n+#define P_REG_RX_OV_FS\t\t\t0x4F8\n+#define P_REG_RX_OV_FS_FIFO_STATUS_S\t2\n+#define P_REG_RX_OV_FS_FIFO_STATUS_M\tMAKEMASK(0x3FF, 2)\n+\n+/* Timestamp command registers */\n+#define P_REG_TX_TMR_CMD\t\t0x448\n+#define P_REG_RX_TMR_CMD\t\t0x468\n+\n+/* E810 timesync enable register */\n+#define ETH_GLTSYN_ENA(_i)\t\t(0x03000348 + ((_i) * 4))\n+\n+/* E810 shadow init time registers */\n+#define ETH_GLTSYN_SHTIME_0(i)\t\t(0x03000368 + ((i) * 32))\n+#define ETH_GLTSYN_SHTIME_L(i)\t\t(0x0300036C + ((i) * 32))\n+\n+/* E810 shadow time adjust registers */\n+#define ETH_GLTSYN_SHADJ_L(_i)\t\t(0x03000378 + ((_i) * 32))\n+#define ETH_GLTSYN_SHADJ_H(_i)\t\t(0x0300037C + ((_i) * 32))\n+\n+/* E810 timer command register */\n+#define ETH_GLTSYN_CMD\t\t\t0x03000344\n+\n+/* Source timer incval macros */\n+#define INCVAL_HIGH_M\t\t\t0xFF\n+\n+/* Timestamp block macros */\n+#define TS_LOW_M\t\t\t0xFFFFFFFF\n+#define TS_HIGH_M\t\t\t0xFF\n+#define TS_HIGH_S\t\t\t32\n+\n+#define TS_PHY_LOW_M\t\t\t0xFF\n+#define TS_PHY_HIGH_M\t\t\t0xFFFFFFFF\n+#define TS_PHY_HIGH_S\t\t\t8\n+\n+#define BYTES_PER_IDX_ADDR_L_U\t\t8\n+#define BYTES_PER_IDX_ADDR_L\t\t4\n+\n+/* Internal PHY timestamp address */\n+#define TS_L(a, idx) ((a) + ((idx) * BYTES_PER_IDX_ADDR_L_U))\n+#define TS_H(a, idx) ((a) + ((idx) * BYTES_PER_IDX_ADDR_L_U +\t\t\\\n+\t\t\t     BYTES_PER_IDX_ADDR_L))\n+\n+/* External PHY timestamp address */\n+#define TS_EXT(a, port, idx) ((a) + (0x1000 * (port)) +\t\t\t\\\n+\t\t\t\t ((idx) * BYTES_PER_IDX_ADDR_L_U))\n+\n+#define LOW_TX_MEMORY_BANK_START\t0x03090000\n+#define HIGH_TX_MEMORY_BANK_START\t0x03090004\n+\n+/* E810T PCA9575 IO controller registers */\n+#define ICE_PCA9575_P0_IN\t0x0\n+#define ICE_PCA9575_P1_IN\t0x1\n+#define ICE_PCA9575_P0_CFG\t0x8\n+#define ICE_PCA9575_P1_CFG\t0x9\n+#define ICE_PCA9575_P0_OUT\t0xA\n+#define ICE_PCA9575_P1_OUT\t0xB\n+\n+/* E810T PCA9575 IO controller pin control */\n+#define ICE_E810T_P0_GNSS_PRSNT_N\tBIT(4)\n+#define ICE_E810T_P1_SMA1_DIR_EN\tBIT(4)\n+#define ICE_E810T_P1_SMA1_TX_EN\t\tBIT(5)\n+#define ICE_E810T_P1_SMA2_UFL2_RX_DIS\tBIT(3)\n+#define ICE_E810T_P1_SMA2_DIR_EN\tBIT(6)\n+#define ICE_E810T_P1_SMA2_TX_EN\t\tBIT(7)\n+\n+#endif /* _ICE_PTP_HW_H_ */\ndiff --git a/drivers/net/ice/base/ice_type.h b/drivers/net/ice/base/ice_type.h\nindex 2d21c21..2bc4b61 100644\n--- a/drivers/net/ice/base/ice_type.h\n+++ b/drivers/net/ice/base/ice_type.h\n@@ -55,6 +55,7 @@\n #include \"ice_lan_tx_rx.h\"\n #include \"ice_flex_type.h\"\n #include \"ice_protocol_type.h\"\n+#include \"ice_sbq_cmd.h\"\n #include \"ice_vlan_mode.h\"\n \n /**\n@@ -131,6 +132,7 @@ static inline u32 ice_round_to_num(u32 N, u32 R)\n #define ICE_DBG_PKG\t\tBIT_ULL(16)\n #define ICE_DBG_RES\t\tBIT_ULL(17)\n #define ICE_DBG_ACL\t\tBIT_ULL(18)\n+#define ICE_DBG_PTP\t\tBIT_ULL(19)\n #define ICE_DBG_AQ_MSG\t\tBIT_ULL(24)\n #define ICE_DBG_AQ_DESC\t\tBIT_ULL(25)\n #define ICE_DBG_AQ_DESC_BUF\tBIT_ULL(26)\n@@ -1012,6 +1014,7 @@ struct ice_hw {\n \n \t/* Control Queue info */\n \tstruct ice_ctl_q_info adminq;\n+\tstruct ice_ctl_q_info sbq;\n \tstruct ice_ctl_q_info mailboxq;\n \t/* Additional function to send AdminQ command */\n \tint (*aq_send_cmd_fn)(void *param, struct ice_aq_desc *desc,\ndiff --git a/drivers/net/ice/base/meson.build b/drivers/net/ice/base/meson.build\nindex 3305e5d..a5db1a5 100644\n--- a/drivers/net/ice/base/meson.build\n+++ b/drivers/net/ice/base/meson.build\n@@ -14,6 +14,7 @@ sources = [\n         'ice_acl.c',\n         'ice_acl_ctrl.c',\n         'ice_vlan_mode.c',\n+        'ice_ptp_hw.c',\n ]\n \n error_cflags = [\n",
    "prefixes": [
        "2/4"
    ]
}