/* FW Admin Queue command wrappers */
 
+/**
+ * ice_should_retry_sq_send_cmd
+ * @opcode: AQ opcode
+ *
+ * Decide if we should retry the send command routine for the ATQ, depending
+ * on the opcode.
+ */
+static bool ice_should_retry_sq_send_cmd(u16 opcode)
+{
+       switch (opcode) {
+       case ice_aqc_opc_get_link_topo:
+       case ice_aqc_opc_lldp_stop:
+       case ice_aqc_opc_lldp_start:
+       case ice_aqc_opc_lldp_filter_ctrl:
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * ice_sq_send_cmd_retry - send command to Control Queue (ATQ)
+ * @hw: pointer to the HW struct
+ * @cq: pointer to the specific Control queue
+ * @desc: prefilled descriptor describing the command
+ * @buf: buffer to use for indirect commands (or NULL for direct commands)
+ * @buf_size: size of buffer for indirect commands (or 0 for direct commands)
+ * @cd: pointer to command details structure
+ *
+ * Retry sending the FW Admin Queue command, multiple times, to the FW Admin
+ * Queue if the EBUSY AQ error is returned.
+ */
+static enum ice_status
+ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
+                     struct ice_aq_desc *desc, void *buf, u16 buf_size,
+                     struct ice_sq_cd *cd)
+{
+       struct ice_aq_desc desc_cpy;
+       enum ice_status status;
+       bool is_cmd_for_retry;
+       u8 *buf_cpy = NULL;
+       u8 idx = 0;
+       u16 opcode;
+
+       opcode = LE16_TO_CPU(desc->opcode);
+       is_cmd_for_retry = ice_should_retry_sq_send_cmd(opcode);
+       ice_memset(&desc_cpy, 0, sizeof(desc_cpy), ICE_NONDMA_MEM);
+
+       if (is_cmd_for_retry) {
+               if (buf) {
+                       buf_cpy = (u8 *)ice_malloc(hw, buf_size);
+                       if (!buf_cpy)
+                               return ICE_ERR_NO_MEMORY;
+               }
+
+               ice_memcpy(&desc_cpy, desc, sizeof(desc_cpy),
+                          ICE_NONDMA_TO_NONDMA);
+       }
+
+       do {
+               status = ice_sq_send_cmd(hw, cq, desc, buf, buf_size, cd);
+
+               if (!is_cmd_for_retry || status == ICE_SUCCESS ||
+                   hw->adminq.sq_last_status != ICE_AQ_RC_EBUSY)
+                       break;
+
+               if (buf_cpy)
+                       ice_memcpy(buf, buf_cpy, buf_size,
+                                  ICE_NONDMA_TO_NONDMA);
+
+               ice_memcpy(desc, &desc_cpy, sizeof(desc_cpy),
+                          ICE_NONDMA_TO_NONDMA);
+
+               ice_msec_delay(ICE_SQ_SEND_DELAY_TIME_MS, false);
+
+       } while (++idx < ICE_SQ_SEND_MAX_EXECUTE);
+
+       if (buf_cpy)
+               ice_free(hw, buf_cpy);
+
+       return status;
+}
+
 /**
  * ice_aq_send_cmd - send FW Admin Queue command to FW Admin Queue
  * @hw: pointer to the HW struct
 
                return status;
        }
-       return ice_sq_send_cmd(hw, &hw->adminq, desc, buf, buf_size, cd);
+       return ice_sq_send_cmd_retry(hw, &hw->adminq, desc, buf, buf_size, cd);
 }
 
 /**
        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_manage_mac_write);
 
        cmd->flags = flags;
-       ice_memcpy(cmd->mac_addr, mac_addr, ETH_ALEN, ICE_NONDMA_TO_DMA);
+       ice_memcpy(cmd->mac_addr, mac_addr, ETH_ALEN, ICE_NONDMA_TO_NONDMA);
 
        return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
 }