net/ice/base: add method to disable FDIR swap option
[dpdk.git] / drivers / net / ice / base / ice_ptp_hw.c
index bf68890..7e797c9 100644 (file)
@@ -709,7 +709,7 @@ ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
  * applicable to E822 devices.
  */
 static enum ice_status
-ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
+ice_read_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 *val)
 {
        struct ice_sbq_msg_input cgu_msg;
        enum ice_status status;
@@ -741,7 +741,7 @@ ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
  * applicable to E822 devices.
  */
 static enum ice_status
-ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val)
+ice_write_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 val)
 {
        struct ice_sbq_msg_input cgu_msg;
        enum ice_status status;
@@ -1634,7 +1634,7 @@ static enum ice_status ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
 #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */
 
        /* Program the 10Gb/40Gb conversion ratio */
-       uix = (tu_per_sec * LINE_UI_10G_40G) / 390625000;
+       uix = DIV_64BIT(tu_per_sec * LINE_UI_10G_40G, 390625000);
 
        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
                                            uix);
@@ -1645,7 +1645,7 @@ static enum ice_status ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
        }
 
        /* Program the 25Gb/100Gb conversion ratio */
-       uix = (tu_per_sec * LINE_UI_25G_100G) / 390625000;
+       uix = DIV_64BIT(tu_per_sec * LINE_UI_25G_100G, 390625000);
 
        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
                                            uix);
@@ -1727,7 +1727,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_PAR_TX_TUS */
        if (e822_vernier[link_spd].tx_par_clk)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].tx_par_clk;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].tx_par_clk);
        else
                phy_tus = 0;
 
@@ -1738,7 +1739,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_PAR_RX_TUS */
        if (e822_vernier[link_spd].rx_par_clk)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].rx_par_clk;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].rx_par_clk);
        else
                phy_tus = 0;
 
@@ -1749,7 +1751,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_PCS_TX_TUS */
        if (e822_vernier[link_spd].tx_pcs_clk)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].tx_pcs_clk;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].tx_pcs_clk);
        else
                phy_tus = 0;
 
@@ -1760,7 +1763,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_PCS_RX_TUS */
        if (e822_vernier[link_spd].rx_pcs_clk)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].rx_pcs_clk;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].rx_pcs_clk);
        else
                phy_tus = 0;
 
@@ -1771,7 +1775,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_DESK_PAR_TX_TUS */
        if (e822_vernier[link_spd].tx_desk_rsgb_par)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].tx_desk_rsgb_par;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].tx_desk_rsgb_par);
        else
                phy_tus = 0;
 
@@ -1782,7 +1787,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_DESK_PAR_RX_TUS */
        if (e822_vernier[link_spd].rx_desk_rsgb_par)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].rx_desk_rsgb_par;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].rx_desk_rsgb_par);
        else
                phy_tus = 0;
 
@@ -1793,7 +1799,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_DESK_PCS_TX_TUS */
        if (e822_vernier[link_spd].tx_desk_rsgb_pcs)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].tx_desk_rsgb_pcs;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].tx_desk_rsgb_pcs);
        else
                phy_tus = 0;
 
@@ -1804,7 +1811,8 @@ static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
 
        /* P_REG_DESK_PCS_RX_TUS */
        if (e822_vernier[link_spd].rx_desk_rsgb_pcs)
-               phy_tus = tu_per_sec / e822_vernier[link_spd].rx_desk_rsgb_pcs;
+               phy_tus = DIV_64BIT(tu_per_sec,
+                                   e822_vernier[link_spd].rx_desk_rsgb_pcs);
        else
                phy_tus = 0;
 
@@ -1836,9 +1844,9 @@ ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
         * overflows 64 bit integer arithmetic, so break it up into two
         * divisions by 1e4 first then by 1e7.
         */
-       fixed_offset = tu_per_sec / 10000;
+       fixed_offset = DIV_64BIT(tu_per_sec, 10000);
        fixed_offset *= e822_vernier[link_spd].tx_fixed_delay;
-       fixed_offset /= 10000000;
+       fixed_offset = DIV_64BIT(fixed_offset, 10000000);
 
        return fixed_offset;
 }
@@ -1982,9 +1990,9 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
                          enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj)
 {
        u64 cur_freq, clk_incval, tu_per_sec, mult, adj;
+       u32 pmd_adj_divisor, val;
        enum ice_status status;
        u8 pmd_align;
-       u32 val;
 
        status = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val);
        if (status) {
@@ -2001,6 +2009,9 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
        /* Calculate TUs per second */
        tu_per_sec = cur_freq * clk_incval;
 
+       /* Get the link speed dependent PMD adjustment divisor */
+       pmd_adj_divisor = e822_vernier[link_spd].pmd_adj_divisor;
+
        /* The PMD alignment adjustment measurement depends on the link speed,
         * and whether FEC is enabled. For each link speed, the alignment
         * adjustment is calculated by dividing a value by the length of
@@ -2063,9 +2074,9 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
         * divide by 125, and then handle remaining divisor based on the link
         * speed pmd_adj_divisor value.
         */
-       adj = tu_per_sec / 125;
+       adj = DIV_64BIT(tu_per_sec, 125);
        adj *= mult;
-       adj /= e822_vernier[link_spd].pmd_adj_divisor;
+       adj = DIV_64BIT(adj, pmd_adj_divisor);
 
        /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx
         * cycle count is necessary.
@@ -2086,9 +2097,9 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
                if (rx_cycle) {
                        mult = (4 - rx_cycle) * 40;
 
-                       cycle_adj = tu_per_sec / 125;
+                       cycle_adj = DIV_64BIT(tu_per_sec, 125);
                        cycle_adj *= mult;
-                       cycle_adj /= e822_vernier[link_spd].pmd_adj_divisor;
+                       cycle_adj = DIV_64BIT(cycle_adj, pmd_adj_divisor);
 
                        adj += cycle_adj;
                }
@@ -2108,9 +2119,9 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
                if (rx_cycle) {
                        mult = rx_cycle * 40;
 
-                       cycle_adj = tu_per_sec / 125;
+                       cycle_adj = DIV_64BIT(tu_per_sec, 125);
                        cycle_adj *= mult;
-                       cycle_adj /= e822_vernier[link_spd].pmd_adj_divisor;
+                       cycle_adj = DIV_64BIT(cycle_adj, pmd_adj_divisor);
 
                        adj += cycle_adj;
                }
@@ -2146,9 +2157,9 @@ ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
         * overflows 64 bit integer arithmetic, so break it up into two
         * divisions by 1e4 first then by 1e7.
         */
-       fixed_offset = tu_per_sec / 10000;
+       fixed_offset = DIV_64BIT(tu_per_sec, 10000);
        fixed_offset *= e822_vernier[link_spd].rx_fixed_delay;
-       fixed_offset /= 10000000;
+       fixed_offset = DIV_64BIT(fixed_offset, 10000000);
 
        return fixed_offset;
 }
@@ -2572,6 +2583,90 @@ ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass)
        return ICE_SUCCESS;
 }
 
+/**
+ * ice_phy_exit_bypass_e822 - Exit bypass mode, after vernier calculations
+ * @hw: pointer to the HW struct
+ * @port: the PHY port to configure
+ *
+ * After hardware finishes vernier calculations for the Tx and Rx offset, this
+ * function can be used to exit bypass mode by updating the total Tx and Rx
+ * offsets, and then disabling bypass. This will enable hardware to include
+ * the more precise offset calibrations, increasing precision of the generated
+ * timestamps.
+ *
+ * This cannot be done until hardware has measured the offsets, which requires
+ * waiting until at least one packet has been sent and received by the device.
+ */
+enum ice_status ice_phy_exit_bypass_e822(struct ice_hw *hw, u8 port)
+{
+       enum ice_status status;
+       u32 val;
+
+       status = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val);
+       if (status) {
+               ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, status %d\n",
+                         port, status);
+               return status;
+       }
+
+       if (!(val & P_REG_TX_OV_STATUS_OV_M)) {
+               ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n",
+                         port);
+               return ICE_ERR_NOT_READY;
+       }
+
+       status = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val);
+       if (status) {
+               ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, status %d\n",
+                         port, status);
+               return status;
+       }
+
+       if (!(val & P_REG_TX_OV_STATUS_OV_M)) {
+               ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n",
+                         port);
+               return ICE_ERR_NOT_READY;
+       }
+
+       status = ice_phy_cfg_tx_offset_e822(hw, port);
+       if (status) {
+               ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, status %d\n",
+                         port, status);
+               return status;
+       }
+
+       status = ice_phy_cfg_rx_offset_e822(hw, port);
+       if (status) {
+               ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, status %d\n",
+                         port, status);
+               return status;
+       }
+
+       /* Exit bypass mode now that the offset has been updated */
+       status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
+       if (status) {
+               ice_debug(hw, ICE_DBG_PTP, "Failed to read P_REG_PS for port %u, status %d\n",
+                         port, status);
+               return status;
+       }
+
+       if (!(val & P_REG_PS_BYPASS_MODE_M))
+               ice_debug(hw, ICE_DBG_PTP, "Port %u not in bypass mode\n",
+                         port);
+
+       val &= ~P_REG_PS_BYPASS_MODE_M;
+       status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+       if (status) {
+               ice_debug(hw, ICE_DBG_PTP, "Failed to disable bypass for port %u, status %d\n",
+                         port, status);
+               return status;
+       }
+
+       ice_info(hw, "Exiting bypass mode on PHY port %u\n", port);
+
+       return ICE_SUCCESS;
+}
+
 /* E810 functions
  *
  * The following functions operate on the E810 series devices which use
@@ -2982,6 +3077,219 @@ ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,
        return ICE_SUCCESS;
 }
 
+/* E810T SMA functions
+ *
+ * The following functions operate specifically on E810T hardware and are used
+ * to access the extended GPIOs available.
+ */
+
+/**
+ * ice_get_pca9575_handle
+ * @hw: pointer to the hw struct
+ * @pca9575_handle: GPIO controller's handle
+ *
+ * Find and return the GPIO controller's handle in the netlist.
+ * When found - the value will be cached in the hw structure and following calls
+ * will return cached value
+ */
+static enum ice_status
+ice_get_pca9575_handle(struct ice_hw *hw, __le16 *pca9575_handle)
+{
+       struct ice_aqc_get_link_topo *cmd;
+       struct ice_aq_desc desc;
+       enum ice_status status;
+       u8 idx;
+
+       if (!hw || !pca9575_handle)
+               return ICE_ERR_PARAM;
+
+       /* If handle was read previously return cached value */
+       if (hw->io_expander_handle) {
+               *pca9575_handle = hw->io_expander_handle;
+               return ICE_SUCCESS;
+       }
+
+       /* If handle was not detected read it from the netlist */
+       cmd = &desc.params.get_link_topo;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
+
+       /* Set node type to GPIO controller */
+       cmd->addr.topo_params.node_type_ctx =
+               (ICE_AQC_LINK_TOPO_NODE_TYPE_M &
+                ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
+
+#define SW_PCA9575_SFP_TOPO_IDX                2
+#define SW_PCA9575_QSFP_TOPO_IDX       1
+
+       /* Check if the SW IO expander controlling SMA exists in the netlist. */
+       if (hw->device_id == ICE_DEV_ID_E810C_SFP)
+               idx = SW_PCA9575_SFP_TOPO_IDX;
+       else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
+               idx = SW_PCA9575_QSFP_TOPO_IDX;
+       else
+               return ICE_ERR_NOT_SUPPORTED;
+
+       cmd->addr.topo_params.index = idx;
+
+       status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+       if (status)
+               return ICE_ERR_NOT_SUPPORTED;
+
+       /* Verify if we found the right IO expander type */
+       if (desc.params.get_link_topo.node_part_num !=
+               ICE_ACQ_GET_LINK_TOPO_NODE_NR_PCA9575)
+               return ICE_ERR_NOT_SUPPORTED;
+
+       /* If present save the handle and return it */
+       hw->io_expander_handle = desc.params.get_link_topo.addr.handle;
+       *pca9575_handle = hw->io_expander_handle;
+
+       return ICE_SUCCESS;
+}
+
+/**
+ * ice_read_e810t_pca9575_reg
+ * @hw: pointer to the hw struct
+ * @offset: GPIO controller register offset
+ * @data: pointer to data to be read from the GPIO controller
+ *
+ * Read the register from the GPIO controller
+ */
+enum ice_status
+ice_read_e810t_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data)
+{
+       struct ice_aqc_link_topo_addr link_topo;
+       enum ice_status status;
+       __le16 addr;
+
+       memset(&link_topo, 0, sizeof(link_topo));
+
+       status = ice_get_pca9575_handle(hw, &link_topo.handle);
+       if (status)
+               return status;
+
+       link_topo.topo_params.node_type_ctx =
+               (ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED <<
+                ICE_AQC_LINK_TOPO_NODE_CTX_S);
+
+       addr = CPU_TO_LE16((u16)offset);
+
+       return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL);
+}
+
+/**
+ * ice_write_e810t_pca9575_reg
+ * @hw: pointer to the hw struct
+ * @offset: GPIO controller register offset
+ * @data: data to be written to the GPIO controller
+ *
+ * Write the data to the GPIO controller register
+ */
+enum ice_status
+ice_write_e810t_pca9575_reg(struct ice_hw *hw, u8 offset, u8 data)
+{
+       struct ice_aqc_link_topo_addr link_topo;
+       enum ice_status status;
+       __le16 addr;
+
+       memset(&link_topo, 0, sizeof(link_topo));
+
+       status = ice_get_pca9575_handle(hw, &link_topo.handle);
+       if (status)
+               return status;
+
+       link_topo.topo_params.node_type_ctx =
+               (ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED <<
+                ICE_AQC_LINK_TOPO_NODE_CTX_S);
+
+       addr = CPU_TO_LE16((u16)offset);
+
+       return ice_aq_write_i2c(hw, link_topo, 0, addr, 1, &data, NULL);
+}
+
+/**
+ * ice_read_sma_ctrl_e810t
+ * @hw: pointer to the hw struct
+ * @data: pointer to data to be read from the GPIO controller
+ *
+ * Read the SMA controller state. Only bits 3-7 in data are valid.
+ */
+enum ice_status ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
+{
+       enum ice_status status;
+       u16 handle;
+       u8 i;
+
+       status = ice_get_pca9575_handle(hw, &handle);
+       if (status)
+               return status;
+
+       *data = 0;
+
+       for (i = ICE_E810T_SMA_MIN_BIT; i <= ICE_E810T_SMA_MAX_BIT; i++) {
+               bool pin;
+
+               status = ice_aq_get_gpio(hw, handle, i + ICE_E810T_P1_OFFSET,
+                                        &pin, NULL);
+               if (status)
+                       break;
+               *data |= (u8)(!pin) << i;
+       }
+
+       return status;
+}
+
+/**
+ * ice_write_sma_ctrl_e810t
+ * @hw: pointer to the hw struct
+ * @data: data to be written to the GPIO controller
+ *
+ * Write the data to the SMA controller. Only bits 3-7 in data are valid.
+ */
+enum ice_status ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
+{
+       enum ice_status status;
+       u16 handle;
+       u8 i;
+
+       status = ice_get_pca9575_handle(hw, &handle);
+       if (status)
+               return status;
+
+       for (i = ICE_E810T_SMA_MIN_BIT; i <= ICE_E810T_SMA_MAX_BIT; i++) {
+               bool pin;
+
+               pin = !(data & (1 << i));
+               status = ice_aq_set_gpio(hw, handle, i + ICE_E810T_P1_OFFSET,
+                                        pin, NULL);
+               if (status)
+                       break;
+       }
+
+       return status;
+}
+
+/**
+ * ice_e810t_is_pca9575_present
+ * @hw: pointer to the hw struct
+ *
+ * Check if the SW IO expander is present in the netlist
+ */
+bool ice_e810t_is_pca9575_present(struct ice_hw *hw)
+{
+       enum ice_status status;
+       __le16 handle = 0;
+
+       if (!ice_is_e810t(hw))
+               return false;
+
+       status = ice_get_pca9575_handle(hw, &handle);
+       if (!status && handle)
+               return true;
+
+       return false;
+}
+
 /* Device agnostic functions
  *
  * The following functions implement shared behavior common to both E822 and