net/i40e/base: add send ASQ command v2 functions
authorRobin Zhang <robinx.zhang@intel.com>
Sat, 9 Oct 2021 01:39:40 +0000 (01:39 +0000)
committerQi Zhang <qi.z.zhang@intel.com>
Sat, 9 Oct 2021 05:17:39 +0000 (07:17 +0200)
ASQ(Admin Send Queue) send command functions are returning only i40e
status codes yet some calling functions also need Admin Queue status that
is stored in hw->aq.asq_last_status. Since hw object is stored on a heap
it introduces a possibility for a race condition in access to hw if
calling function is not fast enough to read hw->aq.asq_last_status before
next send ASQ command is executed.

Added new versions of send ASQ command functions that return Admin Queue
status on the stack to avoid race conditions in access to
hw->aq.asq_last_status.
Added new _v2 version of i40e_aq_remove_macvlan and i40e_aq_add_macvlan
that is using new _v2 versions of ASQ send command functions and returns
the Admin Queue status on the stack.

Signed-off-by: Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
Signed-off-by: Robin Zhang <robinx.zhang@intel.com>
Acked-by: Beilei Xing <beilei.xing@intel.com>
drivers/net/i40e/base/i40e_adminq.c
drivers/net/i40e/base/i40e_common.c
drivers/net/i40e/base/i40e_prototype.h

index 235667d..38d3429 100644 (file)
@@ -838,7 +838,7 @@ STATIC bool i40e_asq_done(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_asq_send_command - send command to Admin Queue
+ *  i40e_asq_send_command_exec - send command to Admin Queue
  *  @hw: pointer to the hw struct
  *  @desc: prefilled descriptor describing the command (non DMA mem)
  *  @buff: buffer to use for indirect commands
@@ -848,11 +848,12 @@ STATIC bool i40e_asq_done(struct i40e_hw *hw)
  *  This is the main send command driver routine for the Admin Queue send
  *  queue.  It runs the queue, cleans the queue, etc
  **/
-enum i40e_status_code i40e_asq_send_command(struct i40e_hw *hw,
-                               struct i40e_aq_desc *desc,
-                               void *buff, /* can be NULL */
-                               u16  buff_size,
-                               struct i40e_asq_cmd_details *cmd_details)
+STATIC enum i40e_status_code
+i40e_asq_send_command_exec(struct i40e_hw *hw,
+                          struct i40e_aq_desc *desc,
+                          void *buff, /* can be NULL */
+                          u16  buff_size,
+                          struct i40e_asq_cmd_details *cmd_details)
 {
        enum i40e_status_code status = I40E_SUCCESS;
        struct i40e_dma_mem *dma_buff = NULL;
@@ -862,8 +863,6 @@ enum i40e_status_code i40e_asq_send_command(struct i40e_hw *hw,
        u16  retval = 0;
        u32  val = 0;
 
-       i40e_acquire_spinlock(&hw->aq.asq_spinlock);
-
        hw->aq.asq_last_status = I40E_AQ_RC_OK;
 
        if (hw->aq.asq.count == 0) {
@@ -1046,6 +1045,64 @@ enum i40e_status_code i40e_asq_send_command(struct i40e_hw *hw,
        }
 
 asq_send_command_error:
+       return status;
+}
+
+/**
+ *  i40e_asq_send_command - send command to Admin Queue
+ *  @hw: pointer to the hw struct
+ *  @desc: prefilled descriptor describing the command (non DMA mem)
+ *  @buff: buffer to use for indirect commands
+ *  @buff_size: size of buffer for indirect commands
+ *  @cmd_details: pointer to command details structure
+ *
+ *  Acquires the lock and calls the main send command execution
+ *  routine.
+ **/
+enum i40e_status_code
+i40e_asq_send_command(struct i40e_hw *hw,
+                     struct i40e_aq_desc *desc,
+                     void *buff, /* can be NULL */
+                     u16  buff_size,
+                     struct i40e_asq_cmd_details *cmd_details)
+{
+       enum i40e_status_code status = I40E_SUCCESS;
+
+       i40e_acquire_spinlock(&hw->aq.asq_spinlock);
+       status = i40e_asq_send_command_exec(hw, desc, buff, buff_size,
+                                           cmd_details);
+       i40e_release_spinlock(&hw->aq.asq_spinlock);
+       return status;
+}
+
+/**
+ *  i40e_asq_send_command_v2 - send command to Admin Queue
+ *  @hw: pointer to the hw struct
+ *  @desc: prefilled descriptor describing the command (non DMA mem)
+ *  @buff: buffer to use for indirect commands
+ *  @buff_size: size of buffer for indirect commands
+ *  @cmd_details: pointer to command details structure
+ *  @aq_status: pointer to Admin Queue status return value
+ *
+ *  Acquires the lock and calls the main send command execution
+ *  routine. Returns the last Admin Queue status in aq_status
+ *  to avoid race conditions in access to hw->aq.asq_last_status.
+ **/
+enum i40e_status_code
+i40e_asq_send_command_v2(struct i40e_hw *hw,
+                        struct i40e_aq_desc *desc,
+                        void *buff, /* can be NULL */
+                        u16  buff_size,
+                        struct i40e_asq_cmd_details *cmd_details,
+                        enum i40e_admin_queue_err *aq_status)
+{
+       enum i40e_status_code status = I40E_SUCCESS;
+
+       i40e_acquire_spinlock(&hw->aq.asq_spinlock);
+       status = i40e_asq_send_command_exec(hw, desc, buff, buff_size,
+                                           cmd_details);
+       if (aq_status)
+               *aq_status = hw->aq.asq_last_status;
        i40e_release_spinlock(&hw->aq.asq_spinlock);
        return status;
 }
index e20bb9a..32642f3 100644 (file)
@@ -3114,6 +3114,46 @@ get_veb_exit:
        return status;
 }
 
+/**
+ * i40e_prepare_add_macvlan
+ * @mv_list: list of macvlans to be added
+ * @desc: pointer to AQ descriptor structure
+ * @count: length of the list
+ * @seid: VSI for the mac address
+ *
+ * Internal helper function that prepares the add macvlan request
+ * and returns the buffer size.
+ **/
+static u16
+i40e_prepare_add_macvlan(struct i40e_aqc_add_macvlan_element_data *mv_list,
+                        struct i40e_aq_desc *desc, u16 count, u16 seid)
+{
+       struct i40e_aqc_macvlan *cmd =
+               (struct i40e_aqc_macvlan *)&desc->params.raw;
+       u16 buf_size;
+       int i;
+
+       buf_size = count * sizeof(*mv_list);
+
+       /* prep the rest of the request */
+       i40e_fill_default_direct_cmd_desc(desc, i40e_aqc_opc_add_macvlan);
+       cmd->num_addresses = CPU_TO_LE16(count);
+       cmd->seid[0] = CPU_TO_LE16(I40E_AQC_MACVLAN_CMD_SEID_VALID | seid);
+       cmd->seid[1] = 0;
+       cmd->seid[2] = 0;
+
+       for (i = 0; i < count; i++)
+               if (I40E_IS_MULTICAST(mv_list[i].mac_addr))
+                       mv_list[i].flags |=
+                           CPU_TO_LE16(I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC);
+
+       desc->flags |= CPU_TO_LE16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (buf_size > I40E_AQ_LARGE_BUF)
+               desc->flags |= CPU_TO_LE16((u16)I40E_AQ_FLAG_LB);
+
+       return buf_size;
+}
+
 /**
  * i40e_aq_add_macvlan
  * @hw: pointer to the hw struct
@@ -3124,8 +3164,74 @@ get_veb_exit:
  *
  * Add MAC/VLAN addresses to the HW filtering
  **/
-enum i40e_status_code i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
-                       struct i40e_aqc_add_macvlan_element_data *mv_list,
+enum i40e_status_code
+i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
+                   struct i40e_aqc_add_macvlan_element_data *mv_list,
+                   u16 count, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       enum i40e_status_code status;
+       u16 buf_size;
+
+       if (count == 0 || !mv_list || !hw)
+               return I40E_ERR_PARAM;
+
+       buf_size = i40e_prepare_add_macvlan(mv_list, &desc, count, seid);
+
+       status = i40e_asq_send_command(hw, &desc, mv_list, buf_size,
+                                      cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_add_macvlan_v2
+ * @hw: pointer to the hw struct
+ * @seid: VSI for the mac address
+ * @mv_list: list of macvlans to be added
+ * @count: length of the list
+ * @cmd_details: pointer to command details structure or NULL
+ * @aq_status: pointer to Admin Queue status return value
+ *
+ * Add MAC/VLAN addresses to the HW filtering.
+ * The _v2 version returns the last Admin Queue status in aq_status
+ * to avoid race conditions in access to hw->aq.asq_last_status.
+ * It also calls _v2 versions of asq_send_command functions to
+ * get the aq_status on the stack.
+ **/
+enum i40e_status_code
+i40e_aq_add_macvlan_v2(struct i40e_hw *hw, u16 seid,
+                      struct i40e_aqc_add_macvlan_element_data *mv_list,
+                      u16 count, struct i40e_asq_cmd_details *cmd_details,
+                      enum i40e_admin_queue_err *aq_status)
+{
+       struct i40e_aq_desc desc;
+       enum i40e_status_code status;
+       u16 buf_size;
+
+       if (count == 0 || !mv_list || !hw)
+               return I40E_ERR_PARAM;
+
+       buf_size = i40e_prepare_add_macvlan(mv_list, &desc, count, seid);
+
+       status = i40e_asq_send_command_v2(hw, &desc, mv_list, buf_size,
+                                         cmd_details, aq_status);
+
+       return status;
+}
+
+/**
+ * i40e_aq_remove_macvlan
+ * @hw: pointer to the hw struct
+ * @seid: VSI for the mac address
+ * @mv_list: list of macvlans to be removed
+ * @count: length of the list
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Remove MAC/VLAN addresses from the HW filtering
+ **/
+enum i40e_status_code i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
+                       struct i40e_aqc_remove_macvlan_element_data *mv_list,
                        u16 count, struct i40e_asq_cmd_details *cmd_details)
 {
        struct i40e_aq_desc desc;
@@ -3133,7 +3239,6 @@ enum i40e_status_code i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
                (struct i40e_aqc_macvlan *)&desc.params.raw;
        enum i40e_status_code status;
        u16 buf_size;
-       int i;
 
        if (count == 0 || !mv_list || !hw)
                return I40E_ERR_PARAM;
@@ -3141,17 +3246,12 @@ enum i40e_status_code i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
        buf_size = count * sizeof(*mv_list);
 
        /* prep the rest of the request */
-       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_add_macvlan);
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_remove_macvlan);
        cmd->num_addresses = CPU_TO_LE16(count);
        cmd->seid[0] = CPU_TO_LE16(I40E_AQC_MACVLAN_CMD_SEID_VALID | seid);
        cmd->seid[1] = 0;
        cmd->seid[2] = 0;
 
-       for (i = 0; i < count; i++)
-               if (I40E_IS_MULTICAST(mv_list[i].mac_addr))
-                       mv_list[i].flags |=
-                           CPU_TO_LE16(I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC);
-
        desc.flags |= CPU_TO_LE16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
        if (buf_size > I40E_AQ_LARGE_BUF)
                desc.flags |= CPU_TO_LE16((u16)I40E_AQ_FLAG_LB);
@@ -3163,18 +3263,25 @@ enum i40e_status_code i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
 }
 
 /**
- * i40e_aq_remove_macvlan
+ * i40e_aq_remove_macvlan_v2
  * @hw: pointer to the hw struct
  * @seid: VSI for the mac address
  * @mv_list: list of macvlans to be removed
  * @count: length of the list
  * @cmd_details: pointer to command details structure or NULL
+ * @aq_status: pointer to Admin Queue status return value
  *
- * Remove MAC/VLAN addresses from the HW filtering
+ * Remove MAC/VLAN addresses from the HW filtering.
+ * The _v2 version returns the last Admin Queue status in aq_status
+ * to avoid race conditions in access to hw->aq.asq_last_status.
+ * It also calls _v2 versions of asq_send_command functions to
+ * get the aq_status on the stack.
  **/
-enum i40e_status_code i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
-                       struct i40e_aqc_remove_macvlan_element_data *mv_list,
-                       u16 count, struct i40e_asq_cmd_details *cmd_details)
+enum i40e_status_code
+i40e_aq_remove_macvlan_v2(struct i40e_hw *hw, u16 seid,
+                         struct i40e_aqc_remove_macvlan_element_data *mv_list,
+                         u16 count, struct i40e_asq_cmd_details *cmd_details,
+                         enum i40e_admin_queue_err *aq_status)
 {
        struct i40e_aq_desc desc;
        struct i40e_aqc_macvlan *cmd =
@@ -3198,8 +3305,8 @@ enum i40e_status_code i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
        if (buf_size > I40E_AQ_LARGE_BUF)
                desc.flags |= CPU_TO_LE16((u16)I40E_AQ_FLAG_LB);
 
-       status = i40e_asq_send_command(hw, &desc, mv_list, buf_size,
-                                      cmd_details);
+       status = i40e_asq_send_command_v2(hw, &desc, mv_list, buf_size,
+                                         cmd_details, aq_status);
 
        return status;
 }
index 124222e..29c86c7 100644 (file)
@@ -38,6 +38,13 @@ enum i40e_status_code i40e_asq_send_command(struct i40e_hw *hw,
                                void *buff, /* can be NULL */
                                u16  buff_size,
                                struct i40e_asq_cmd_details *cmd_details);
+enum i40e_status_code
+i40e_asq_send_command_v2(struct i40e_hw *hw,
+                        struct i40e_aq_desc *desc,
+                        void *buff, /* can be NULL */
+                        u16  buff_size,
+                        struct i40e_asq_cmd_details *cmd_details,
+                        enum i40e_admin_queue_err *aq_status);
 #ifdef VF_DRIVER
 bool i40e_asq_done(struct i40e_hw *hw);
 #endif
@@ -188,9 +195,19 @@ enum i40e_status_code i40e_aq_get_veb_parameters(struct i40e_hw *hw,
 enum i40e_status_code i40e_aq_add_macvlan(struct i40e_hw *hw, u16 vsi_id,
                        struct i40e_aqc_add_macvlan_element_data *mv_list,
                        u16 count, struct i40e_asq_cmd_details *cmd_details);
+enum i40e_status_code
+i40e_aq_add_macvlan_v2(struct i40e_hw *hw, u16 seid,
+                      struct i40e_aqc_add_macvlan_element_data *mv_list,
+                      u16 count, struct i40e_asq_cmd_details *cmd_details,
+                      enum i40e_admin_queue_err *aq_status);
 enum i40e_status_code i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 vsi_id,
                        struct i40e_aqc_remove_macvlan_element_data *mv_list,
                        u16 count, struct i40e_asq_cmd_details *cmd_details);
+enum i40e_status_code
+i40e_aq_remove_macvlan_v2(struct i40e_hw *hw, u16 seid,
+                         struct i40e_aqc_remove_macvlan_element_data *mv_list,
+                         u16 count, struct i40e_asq_cmd_details *cmd_details,
+                         enum i40e_admin_queue_err *aq_status);
 enum i40e_status_code i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
                        u16 rule_type, u16 dest_vsi, u16 count, __le16 *mr_list,
                        struct i40e_asq_cmd_details *cmd_details,