Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13050921 authored by Huazhong Tan's avatar Huazhong Tan Committed by David S. Miller
Browse files

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: e2cb1dec ("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support")
Fixes: b90fcc5b ("net: hns3: add reset handling for VF when doing Core/Global/IMP reset")

Signed-off-by: default avatarHuazhong Tan <tanhuazhong@huawei.com>
Reviewed-by: default avatarYunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9e6717af
Loading
Loading
Loading
Loading
+19 −9
Original line number Diff line number Diff line
@@ -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;
	}

+2 −0
Original line number Diff line number Diff line
@@ -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 */