net: hns3: fix interrupt clearing error for VF
Currently, VF driver has two kinds of interrupts, reset & CMDQ RX. For revision 0x21, according to the UM, each interrupt should be cleared by write 0 to the corresponding bit, but the implementation writes 0 to the whole register in fact, it will clear other interrupt at the same time, then the VF will loss the interrupt. But for revision 0x20, this interrupt clear register is a read & write register, for compatible, we just keep the old implementation for 0x20. This patch fixes it, also, adds a new register for reading the interrupt status according to hardware user manual. Fixes:e2cb1dec97
("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support") Fixes:b90fcc5bd9
("net: hns3: add reset handling for VF when doing Core/Global/IMP reset") Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com> Reviewed-by: Yunsheng Lin <linyunsheng@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9e6717af61
commit
130509213b
|
@ -1889,21 +1889,20 @@ static void hclgevf_clear_event_cause(struct hclgevf_dev *hdev, u32 regclr)
|
|||
static enum hclgevf_evt_cause hclgevf_check_evt_cause(struct hclgevf_dev *hdev,
|
||||
u32 *clearval)
|
||||
{
|
||||
u32 val, cmdq_src_reg, rst_ing_reg;
|
||||
u32 val, cmdq_stat_reg, rst_ing_reg;
|
||||
|
||||
/* fetch the events from their corresponding regs */
|
||||
cmdq_src_reg = hclgevf_read_dev(&hdev->hw,
|
||||
HCLGEVF_VECTOR0_CMDQ_SRC_REG);
|
||||
cmdq_stat_reg = hclgevf_read_dev(&hdev->hw,
|
||||
HCLGEVF_VECTOR0_CMDQ_STAT_REG);
|
||||
|
||||
if (BIT(HCLGEVF_VECTOR0_RST_INT_B) & cmdq_src_reg) {
|
||||
if (BIT(HCLGEVF_VECTOR0_RST_INT_B) & cmdq_stat_reg) {
|
||||
rst_ing_reg = hclgevf_read_dev(&hdev->hw, HCLGEVF_RST_ING);
|
||||
dev_info(&hdev->pdev->dev,
|
||||
"receive reset interrupt 0x%x!\n", rst_ing_reg);
|
||||
set_bit(HNAE3_VF_RESET, &hdev->reset_pending);
|
||||
set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
|
||||
set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state);
|
||||
cmdq_src_reg &= ~BIT(HCLGEVF_VECTOR0_RST_INT_B);
|
||||
*clearval = cmdq_src_reg;
|
||||
*clearval = ~(1U << HCLGEVF_VECTOR0_RST_INT_B);
|
||||
hdev->rst_stats.vf_rst_cnt++;
|
||||
/* set up VF hardware reset status, its PF will clear
|
||||
* this status when PF has initialized done.
|
||||
|
@ -1915,9 +1914,20 @@ static enum hclgevf_evt_cause hclgevf_check_evt_cause(struct hclgevf_dev *hdev,
|
|||
}
|
||||
|
||||
/* check for vector0 mailbox(=CMDQ RX) event source */
|
||||
if (BIT(HCLGEVF_VECTOR0_RX_CMDQ_INT_B) & cmdq_src_reg) {
|
||||
cmdq_src_reg &= ~BIT(HCLGEVF_VECTOR0_RX_CMDQ_INT_B);
|
||||
*clearval = cmdq_src_reg;
|
||||
if (BIT(HCLGEVF_VECTOR0_RX_CMDQ_INT_B) & cmdq_stat_reg) {
|
||||
/* for revision 0x21, clearing interrupt is writing bit 0
|
||||
* to the clear register, writing bit 1 means to keep the
|
||||
* old value.
|
||||
* for revision 0x20, the clear register is a read & write
|
||||
* register, so we should just write 0 to the bit we are
|
||||
* handling, and keep other bits as cmdq_stat_reg.
|
||||
*/
|
||||
if (hdev->pdev->revision >= 0x21)
|
||||
*clearval = ~(1U << HCLGEVF_VECTOR0_RX_CMDQ_INT_B);
|
||||
else
|
||||
*clearval = cmdq_stat_reg &
|
||||
~BIT(HCLGEVF_VECTOR0_RX_CMDQ_INT_B);
|
||||
|
||||
return HCLGEVF_VECTOR0_EVENT_MBX;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@
|
|||
|
||||
/* Vector0 interrupt CMDQ event source register(RW) */
|
||||
#define HCLGEVF_VECTOR0_CMDQ_SRC_REG 0x27100
|
||||
/* Vector0 interrupt CMDQ event status register(RO) */
|
||||
#define HCLGEVF_VECTOR0_CMDQ_STAT_REG 0x27104
|
||||
/* CMDQ register bits for RX event(=MBX event) */
|
||||
#define HCLGEVF_VECTOR0_RX_CMDQ_INT_B 1
|
||||
/* RST register bits for RESET event */
|
||||
|
|
Loading…
Reference in New Issue