Merge tag 'boards-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / intel / i40evf / i40e_adminq.c
index eb67cce3e8f9a1bed6a0eabfaaeb7067acd703ef..00300603361464b4e9f3b20da7774a1069bdf071 100644 (file)
@@ -53,16 +53,24 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw)
                hw->aq.asq.tail = I40E_VF_ATQT1;
                hw->aq.asq.head = I40E_VF_ATQH1;
                hw->aq.asq.len  = I40E_VF_ATQLEN1;
+               hw->aq.asq.bal  = I40E_VF_ATQBAL1;
+               hw->aq.asq.bah  = I40E_VF_ATQBAH1;
                hw->aq.arq.tail = I40E_VF_ARQT1;
                hw->aq.arq.head = I40E_VF_ARQH1;
                hw->aq.arq.len  = I40E_VF_ARQLEN1;
+               hw->aq.arq.bal  = I40E_VF_ARQBAL1;
+               hw->aq.arq.bah  = I40E_VF_ARQBAH1;
        } else {
                hw->aq.asq.tail = I40E_PF_ATQT;
                hw->aq.asq.head = I40E_PF_ATQH;
                hw->aq.asq.len  = I40E_PF_ATQLEN;
+               hw->aq.asq.bal  = I40E_PF_ATQBAL;
+               hw->aq.asq.bah  = I40E_PF_ATQBAH;
                hw->aq.arq.tail = I40E_PF_ARQT;
                hw->aq.arq.head = I40E_PF_ARQH;
                hw->aq.arq.len  = I40E_PF_ARQLEN;
+               hw->aq.arq.bal  = I40E_PF_ARQBAL;
+               hw->aq.arq.bah  = I40E_PF_ARQBAH;
        }
 }
 
@@ -294,27 +302,18 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw)
        i40e_status ret_code = 0;
        u32 reg = 0;
 
-       if (hw->mac.type == I40E_MAC_VF) {
-               /* configure the transmit queue */
-               wr32(hw, I40E_VF_ATQBAH1,
-                   upper_32_bits(hw->aq.asq.desc_buf.pa));
-               wr32(hw, I40E_VF_ATQBAL1,
-                   lower_32_bits(hw->aq.asq.desc_buf.pa));
-               wr32(hw, I40E_VF_ATQLEN1, (hw->aq.num_asq_entries |
-                                         I40E_VF_ATQLEN1_ATQENABLE_MASK));
-               reg = rd32(hw, I40E_VF_ATQBAL1);
-       } else {
-               /* configure the transmit queue */
-               wr32(hw, I40E_PF_ATQBAH,
-                   upper_32_bits(hw->aq.asq.desc_buf.pa));
-               wr32(hw, I40E_PF_ATQBAL,
-                   lower_32_bits(hw->aq.asq.desc_buf.pa));
-               wr32(hw, I40E_PF_ATQLEN, (hw->aq.num_asq_entries |
-                                         I40E_PF_ATQLEN_ATQENABLE_MASK));
-               reg = rd32(hw, I40E_PF_ATQBAL);
-       }
+       /* Clear Head and Tail */
+       wr32(hw, hw->aq.asq.head, 0);
+       wr32(hw, hw->aq.asq.tail, 0);
+
+       /* set starting point */
+       wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries |
+                                 I40E_PF_ATQLEN_ATQENABLE_MASK));
+       wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa));
+       wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa));
 
        /* Check one register to verify that config was applied */
+       reg = rd32(hw, hw->aq.asq.bal);
        if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa))
                ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
 
@@ -332,30 +331,21 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw)
        i40e_status ret_code = 0;
        u32 reg = 0;
 
-       if (hw->mac.type == I40E_MAC_VF) {
-               /* configure the receive queue */
-               wr32(hw, I40E_VF_ARQBAH1,
-                   upper_32_bits(hw->aq.arq.desc_buf.pa));
-               wr32(hw, I40E_VF_ARQBAL1,
-                   lower_32_bits(hw->aq.arq.desc_buf.pa));
-               wr32(hw, I40E_VF_ARQLEN1, (hw->aq.num_arq_entries |
-                                         I40E_VF_ARQLEN1_ARQENABLE_MASK));
-               reg = rd32(hw, I40E_VF_ARQBAL1);
-       } else {
-               /* configure the receive queue */
-               wr32(hw, I40E_PF_ARQBAH,
-                   upper_32_bits(hw->aq.arq.desc_buf.pa));
-               wr32(hw, I40E_PF_ARQBAL,
-                   lower_32_bits(hw->aq.arq.desc_buf.pa));
-               wr32(hw, I40E_PF_ARQLEN, (hw->aq.num_arq_entries |
-                                         I40E_PF_ARQLEN_ARQENABLE_MASK));
-               reg = rd32(hw, I40E_PF_ARQBAL);
-       }
+       /* Clear Head and Tail */
+       wr32(hw, hw->aq.arq.head, 0);
+       wr32(hw, hw->aq.arq.tail, 0);
+
+       /* set starting point */
+       wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries |
+                                 I40E_PF_ARQLEN_ARQENABLE_MASK));
+       wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa));
+       wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa));
 
        /* Update tail in the HW to post pre-allocated buffers */
        wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1);
 
        /* Check one register to verify that config was applied */
+       reg = rd32(hw, hw->aq.arq.bal);
        if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa))
                ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
 
@@ -497,6 +487,8 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw)
        wr32(hw, hw->aq.asq.head, 0);
        wr32(hw, hw->aq.asq.tail, 0);
        wr32(hw, hw->aq.asq.len, 0);
+       wr32(hw, hw->aq.asq.bal, 0);
+       wr32(hw, hw->aq.asq.bah, 0);
 
        /* make sure lock is available */
        mutex_lock(&hw->aq.asq_mutex);
@@ -528,6 +520,8 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw)
        wr32(hw, hw->aq.arq.head, 0);
        wr32(hw, hw->aq.arq.tail, 0);
        wr32(hw, hw->aq.arq.len, 0);
+       wr32(hw, hw->aq.arq.bal, 0);
+       wr32(hw, hw->aq.arq.bah, 0);
 
        /* make sure lock is available */
        mutex_lock(&hw->aq.arq_mutex);
@@ -573,6 +567,9 @@ i40e_status i40evf_init_adminq(struct i40e_hw *hw)
        /* Set up register offsets */
        i40e_adminq_init_regs(hw);
 
+       /* setup ASQ command write back timeout */
+       hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT;
+
        /* allocate the ASQ */
        ret_code = i40e_init_asq(hw);
        if (ret_code)
@@ -630,6 +627,10 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
        desc = I40E_ADMINQ_DESC(*asq, ntc);
        details = I40E_ADMINQ_DETAILS(*asq, ntc);
        while (rd32(hw, hw->aq.asq.head) != ntc) {
+               i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+                          "%s: ntc %d head %d.\n", __func__, ntc,
+                          rd32(hw, hw->aq.asq.head));
+
                if (details->callback) {
                        I40E_ADMINQ_CALLBACK cb_func =
                                        (I40E_ADMINQ_CALLBACK)details->callback;
@@ -690,17 +691,20 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
        struct i40e_aq_desc *desc_on_ring;
        bool cmd_completed = false;
        u16  retval = 0;
+       u32  val = 0;
 
-       if (hw->aq.asq.count == 0) {
+       val = rd32(hw, hw->aq.asq.head);
+       if (val >= hw->aq.num_asq_entries) {
                i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
-                          "AQTX: Admin queue not initialized.\n");
+                          "AQTX: head overrun at %d\n", val);
                status = I40E_ERR_QUEUE_EMPTY;
                goto asq_send_command_exit;
        }
 
-       if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) {
-               i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n");
-               status = I40E_ERR_NVM;
+       if (hw->aq.asq.count == 0) {
+               i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+                          "AQTX: Admin queue not initialized.\n");
+               status = I40E_ERR_QUEUE_EMPTY;
                goto asq_send_command_exit;
        }
 
@@ -783,6 +787,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
        }
 
        /* bump the tail */
+       i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
        i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff);
        (hw->aq.asq.next_to_use)++;
        if (hw->aq.asq.next_to_use == hw->aq.asq.count)
@@ -806,7 +811,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
                        /* ugh! delay while spin_lock */
                        udelay(delay_len);
                        total_delay += delay_len;
-               } while (total_delay <  I40E_ASQ_CMD_TIMEOUT);
+               } while (total_delay < hw->aq.asq_cmd_timeout);
        }
 
        /* if ready, copy the desc back to temp */
@@ -820,6 +825,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
                                   I40E_DEBUG_AQ_MESSAGE,
                                   "AQTX: Command completed with error 0x%X.\n",
                                   retval);
+
                        /* strip off FW internal code */
                        retval &= 0xff;
                }
@@ -834,6 +840,10 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
        if (i40e_is_nvm_update_op(desc))
                hw->aq.nvm_busy = true;
 
+       i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+                  "AQTX: desc and buffer writeback:\n");
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
+
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
            (!details->async && !details->postpone)) {
@@ -905,10 +915,6 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
        /* now clean the next descriptor */
        desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc);
        desc_idx = ntc;
-       i40evf_debug_aq(hw,
-                     I40E_DEBUG_AQ_COMMAND,
-                     (void *)desc,
-                     hw->aq.arq.r.arq_bi[desc_idx].va);
 
        flags = le16_to_cpu(desc->flags);
        if (flags & I40E_AQ_FLAG_ERR) {
@@ -919,18 +925,21 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
                           I40E_DEBUG_AQ_MESSAGE,
                           "AQRX: Event received with error 0x%X.\n",
                           hw->aq.arq_last_status);
-       } else {
-               e->desc = *desc;
-               datalen = le16_to_cpu(desc->datalen);
-               e->msg_size = min(datalen, e->msg_size);
-               if (e->msg_buf != NULL && (e->msg_size != 0))
-                       memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
-                              e->msg_size);
        }
 
+       e->desc = *desc;
+       datalen = le16_to_cpu(desc->datalen);
+       e->msg_size = min(datalen, e->msg_size);
+       if (e->msg_buf != NULL && (e->msg_size != 0))
+               memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
+                      e->msg_size);
+
        if (i40e_is_nvm_update_op(&e->desc))
                hw->aq.nvm_busy = false;
 
+       i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
+
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
         * size