diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_adminq.c')
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_adminq.c | 132 |
1 files changed, 76 insertions, 56 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 7a027499fc57..b29c157b1f57 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -38,8 +38,8 @@ static void i40e_resume_aq(struct i40e_hw *hw); **/ static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) { - return (desc->opcode == i40e_aqc_opc_nvm_erase) || - (desc->opcode == i40e_aqc_opc_nvm_update); + return (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_erase)) || + (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_update)); } /** @@ -55,16 +55,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; } } @@ -296,27 +304,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; @@ -334,30 +333,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; @@ -499,6 +489,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); @@ -530,6 +522,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); @@ -577,6 +571,9 @@ i40e_status i40e_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) @@ -677,6 +674,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; @@ -736,6 +737,15 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, struct i40e_aq_desc *desc_on_ring; bool cmd_completed = false; u16 retval = 0; + u32 val = 0; + + val = rd32(hw, hw->aq.asq.head); + if (val >= hw->aq.num_asq_entries) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: head overrun at %d\n", val); + status = I40E_ERR_QUEUE_EMPTY; + goto asq_send_command_exit; + } if (hw->aq.asq.count == 0) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, @@ -829,6 +839,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, } /* bump the tail */ + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); i40e_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) @@ -852,7 +863,7 @@ i40e_status i40e_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 */ @@ -866,6 +877,7 @@ i40e_status i40e_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; } @@ -877,8 +889,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } - 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"); + i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); /* update the error if time out occurred */ if ((!cmd_completed) && @@ -889,6 +902,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; } + if (!status && i40e_is_nvm_update_op(desc)) + hw->aq.nvm_busy = true; + asq_send_command_error: mutex_unlock(&hw->aq.asq_mutex); asq_send_command_exit: @@ -951,10 +967,6 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, /* now clean the next descriptor */ desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc); desc_idx = ntc; - i40e_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) { @@ -965,17 +977,17 @@ i40e_status i40e_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); } - if (i40e_is_nvm_update_op(&e->desc)) - hw->aq.nvm_busy = false; + 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); + + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); + i40e_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 @@ -1006,6 +1018,14 @@ clean_arq_element_out: *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); mutex_unlock(&hw->aq.arq_mutex); + if (i40e_is_nvm_update_op(&e->desc)) { + hw->aq.nvm_busy = false; + if (hw->aq.nvm_release_on_done) { + i40e_release_nvm(hw); + hw->aq.nvm_release_on_done = false; + } + } + return ret_code; } |