Adds the Set/Get Port Options commands (0x06EA/0x06EB), also include
additional status and ID bits to improve the Link topology configuration
as well as ability to change port option from pre-boot environment via
the UEFI driver.

Signed-off-by: Anatoly Burakov <anatoly.bura...@intel.com>
---
 drivers/net/ice/base/ice_adminq_cmd.h |  59 ++++++++++++++
 drivers/net/ice/base/ice_common.c     | 109 ++++++++++++++++++++++++++
 drivers/net/ice/base/ice_common.h     |   9 +++
 drivers/net/ice/base/ice_type.h       |   2 +
 4 files changed, 179 insertions(+)

diff --git a/drivers/net/ice/base/ice_adminq_cmd.h 
b/drivers/net/ice/base/ice_adminq_cmd.h
index a4b45b9fc5..457455fe85 100644
--- a/drivers/net/ice/base/ice_adminq_cmd.h
+++ b/drivers/net/ice/base/ice_adminq_cmd.h
@@ -1889,6 +1889,63 @@ struct ice_aqc_set_port_id_led {
        u8 rsvd[13];
 };
 
+/* Get Port Options (indirect, 0x06EA) */
+struct ice_aqc_get_port_options {
+       u8 lport_num;
+       u8 lport_num_valid;
+#define ICE_AQC_PORT_OPT_PORT_NUM_VALID        BIT(0)
+       u8 port_options_count;
+#define ICE_AQC_PORT_OPT_COUNT_S       0
+#define ICE_AQC_PORT_OPT_COUNT_M       (0xF << ICE_AQC_PORT_OPT_COUNT_S)
+#define ICE_AQC_PORT_OPT_MAX           16
+       u8 innermost_phy_index;
+       u8 port_options;
+#define ICE_AQC_PORT_OPT_ACTIVE_S      0
+#define ICE_AQC_PORT_OPT_ACTIVE_M      (0xF << ICE_AQC_PORT_OPT_ACTIVE_S)
+#define ICE_AQC_PORT_OPT_FORCED                BIT(6)
+#define ICE_AQC_PORT_OPT_VALID         BIT(7)
+       u8 pending_port_option_status;
+#define ICE_AQC_PENDING_PORT_OPT_IDX_S 0
+#define ICE_AQC_PENDING_PORT_OPT_IDX_M (0xF << ICE_AQC_PENDING_PORT_OPT_IDX_S)
+#define ICE_AQC_PENDING_PORT_OPT_VALID BIT(7)
+       u8 rsvd[2];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+struct ice_aqc_get_port_options_elem {
+       u8 pmd;
+#define ICE_AQC_PORT_INV_PORT_OPT      4
+#define ICE_AQC_PORT_OPT_PMD_COUNT_S   0
+#define ICE_AQC_PORT_OPT_PMD_COUNT_M   (0xF << ICE_AQC_PORT_OPT_PMD_COUNT_S)
+#define ICE_AQC_PORT_OPT_PMD_WIDTH_S   4
+#define ICE_AQC_PORT_OPT_PMD_WIDTH_M   (0xF << ICE_AQC_PORT_OPT_PMD_WIDTH_S)
+       u8 max_lane_speed;
+#define ICE_AQC_PORT_OPT_MAX_LANE_S    0
+#define ICE_AQC_PORT_OPT_MAX_LANE_M    (0xF << ICE_AQC_PORT_OPT_MAX_LANE_S)
+#define ICE_AQC_PORT_OPT_MAX_LANE_100M 0
+#define ICE_AQC_PORT_OPT_MAX_LANE_1G   1
+#define ICE_AQC_PORT_OPT_MAX_LANE_2500M        2
+#define ICE_AQC_PORT_OPT_MAX_LANE_5G   3
+#define ICE_AQC_PORT_OPT_MAX_LANE_10G  4
+#define ICE_AQC_PORT_OPT_MAX_LANE_25G  5
+#define ICE_AQC_PORT_OPT_MAX_LANE_50G  6
+#define ICE_AQC_PORT_OPT_MAX_LANE_100G 7
+#define ICE_AQC_PORT_OPT_MAX_LANE_200G 8
+       u8 global_scid[2];
+       u8 phy_scid[2];
+       u8 pf2port_cid[2];
+};
+
+/* Set Port Option (direct, 0x06EB) */
+struct ice_aqc_set_port_option {
+       u8 lport_num;
+       u8 lport_num_valid;
+#define ICE_AQC_SET_PORT_OPT_PORT_NUM_VALID    BIT(0)
+       u8 selected_port_option;
+       u8 rsvd[13];
+};
+
 /* Set/Get GPIO (direct, 0x06EC/0x06ED) */
 struct ice_aqc_gpio {
        __le16 gpio_ctrl_handle;
@@ -3152,6 +3209,8 @@ struct ice_aq_desc {
                struct ice_aqc_sw_gpio sw_read_write_gpio;
                struct ice_aqc_sff_eeprom read_write_sff_param;
                struct ice_aqc_set_port_id_led set_port_id_led;
+               struct ice_aqc_get_port_options get_port_options;
+               struct ice_aqc_set_port_option set_port_option;
                struct ice_aqc_get_sw_cfg get_sw_conf;
                struct ice_aqc_set_port_params set_port_params;
                struct ice_aqc_sw_rules sw_rules;
diff --git a/drivers/net/ice/base/ice_common.c 
b/drivers/net/ice/base/ice_common.c
index 3a91956ff2..1158bc5f30 100644
--- a/drivers/net/ice/base/ice_common.c
+++ b/drivers/net/ice/base/ice_common.c
@@ -6102,6 +6102,115 @@ bool ice_is_phy_caps_an_enabled(struct 
ice_aqc_get_phy_caps_data *caps)
        return false;
 }
 
+/**
+ * ice_aq_get_port_options
+ * @hw: pointer to the hw struct
+ * @options: buffer for the resultant port options
+ * @option_count: input - size of the buffer in port options structures,
+ *                output - number of returned port options
+ * @lport: logical port to call the command with (optional)
+ * @lport_valid: when false, FW uses port owned by the PF instead of lport,
+ *               when PF owns more than 1 port it must be true
+ * @active_option_idx: index of active port option in returned buffer
+ * @active_option_valid: active option in returned buffer is valid
+ * @pending_option_idx: index of pending port option in returned buffer
+ * @pending_option_valid: pending option in returned buffer is valid
+ *
+ * Calls Get Port Options AQC (0x06ea) and verifies result.
+ */
+int
+ice_aq_get_port_options(struct ice_hw *hw,
+                       struct ice_aqc_get_port_options_elem *options,
+                       u8 *option_count, u8 lport, bool lport_valid,
+                       u8 *active_option_idx, bool *active_option_valid,
+                       u8 *pending_option_idx, bool *pending_option_valid)
+{
+       struct ice_aqc_get_port_options *cmd;
+       struct ice_aq_desc desc;
+       int status;
+       u8 i;
+
+       /* options buffer shall be able to hold max returned options */
+       if (*option_count < ICE_AQC_PORT_OPT_COUNT_M)
+               return ICE_ERR_PARAM;
+
+       cmd = &desc.params.get_port_options;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_port_options);
+
+       cmd->lport_num = lport;
+       cmd->lport_num_valid = lport_valid;
+
+       status = ice_aq_send_cmd(hw, &desc, options,
+                                *option_count * sizeof(*options), NULL);
+       if (status)
+               return status;
+
+       /* verify direct FW response & set output parameters */
+       *option_count = cmd->port_options_count & ICE_AQC_PORT_OPT_COUNT_M;
+       ice_debug(hw, ICE_DBG_PHY, "options: %x\n", *option_count);
+       *active_option_valid = cmd->port_options & ICE_AQC_PORT_OPT_VALID;
+       if (*active_option_valid) {
+               *active_option_idx = cmd->port_options &
+                                    ICE_AQC_PORT_OPT_ACTIVE_M;
+               if (*active_option_idx > (*option_count - 1))
+                       return ICE_ERR_OUT_OF_RANGE;
+               ice_debug(hw, ICE_DBG_PHY, "active idx: %x\n",
+                         *active_option_idx);
+       }
+
+       *pending_option_valid = cmd->pending_port_option_status &
+                               ICE_AQC_PENDING_PORT_OPT_VALID;
+       if (*pending_option_valid) {
+               *pending_option_idx = cmd->pending_port_option_status &
+                                     ICE_AQC_PENDING_PORT_OPT_IDX_M;
+               if (*pending_option_idx > (*option_count - 1))
+                       return ICE_ERR_OUT_OF_RANGE;
+               ice_debug(hw, ICE_DBG_PHY, "pending idx: %x\n",
+                         *pending_option_idx);
+       }
+
+       /* mask output options fields */
+       for (i = 0; i < *option_count; i++) {
+               options[i].pmd &= ICE_AQC_PORT_OPT_PMD_COUNT_M;
+               options[i].max_lane_speed &= ICE_AQC_PORT_OPT_MAX_LANE_M;
+               ice_debug(hw, ICE_DBG_PHY, "pmds: %x max speed: %x\n",
+                         options[i].pmd, options[i].max_lane_speed);
+       }
+
+       return 0;
+}
+
+/**
+ * ice_aq_set_port_option
+ * @hw: pointer to the hw struct
+ * @lport: logical port to call the command with
+ * @lport_valid: when false, FW uses port owned by the PF instead of lport,
+ *               when PF owns more than 1 port it must be true
+ * @new_option: new port option to be written
+ *
+ * Calls Set Port Options AQC (0x06eb).
+ */
+int
+ice_aq_set_port_option(struct ice_hw *hw, u8 lport, u8 lport_valid,
+                      u8 new_option)
+{
+       struct ice_aqc_set_port_option *cmd;
+       struct ice_aq_desc desc;
+
+       if (new_option >= ICE_AQC_PORT_OPT_COUNT_M)
+               return ICE_ERR_PARAM;
+
+       cmd = &desc.params.set_port_option;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_option);
+
+       cmd->lport_num = lport;
+
+       cmd->lport_num_valid = lport_valid;
+       cmd->selected_port_option = new_option;
+
+       return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+}
+
 /**
  * ice_aq_set_lldp_mib - Set the LLDP MIB
  * @hw: pointer to the HW struct
diff --git a/drivers/net/ice/base/ice_common.h 
b/drivers/net/ice/base/ice_common.h
index 2f1b212812..93d4c48fa5 100644
--- a/drivers/net/ice/base/ice_common.h
+++ b/drivers/net/ice/base/ice_common.h
@@ -228,6 +228,15 @@ ice_aq_read_topo_dev_nvm(struct ice_hw *hw,
                         struct ice_sq_cd *cd);
 
 int
+ice_aq_get_port_options(struct ice_hw *hw,
+                       struct ice_aqc_get_port_options_elem *options,
+                       u8 *option_count, u8 lport, bool lport_valid,
+                       u8 *active_option_idx, bool *active_option_valid,
+                       u8 *pending_option_idx, bool *pending_option_valid);
+int
+ice_aq_set_port_option(struct ice_hw *hw, u8 lport, u8 lport_valid,
+                      u8 new_option);
+int
 ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
                u16 *q_handle, u16 *q_ids, u32 *q_teids,
                enum ice_disq_rst_src rst_src, u16 vmvf_num,
diff --git a/drivers/net/ice/base/ice_type.h b/drivers/net/ice/base/ice_type.h
index 724a31d775..14c5b2fa01 100644
--- a/drivers/net/ice/base/ice_type.h
+++ b/drivers/net/ice/base/ice_type.h
@@ -1065,6 +1065,8 @@ enum ice_rl_type {
 #define ICE_TXSCHED_GET_RL_WAKEUP_MV(p) LE16_TO_CPU((p)->info.wake_up_calc)
 #define ICE_TXSCHED_GET_RL_ENCODE(p) LE16_TO_CPU((p)->info.rl_encode)
 
+#define ICE_MAX_PORT_PER_PCI_DEV       8
+
 /* The following tree example shows the naming conventions followed under
  * ice_port_info struct for default scheduler tree topology.
  *
-- 
2.43.0

Reply via email to