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

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

net: hns3: add PCIe FLR support for PF



This patch implements the .reset_prepare and .reset_done
ops from pci framework to support the PF FLR.

Signed-off-by: default avatarHuazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6dd22bbc
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ enum hnae3_reset_type {
	HNAE3_VF_FUNC_RESET,
	HNAE3_VF_PF_FUNC_RESET,
	HNAE3_VF_FULL_RESET,
	HNAE3_FLR_RESET,
	HNAE3_FUNC_RESET,
	HNAE3_CORE_RESET,
	HNAE3_GLOBAL_RESET,
@@ -134,6 +135,11 @@ enum hnae3_reset_type {
	HNAE3_NONE_RESET,
};

enum hnae3_flr_state {
	HNAE3_FLR_DOWN,
	HNAE3_FLR_DONE,
};

struct hnae3_vector_info {
	u8 __iomem *io_addr;
	int vector;
@@ -299,7 +305,8 @@ struct hnae3_ae_dev {
struct hnae3_ae_ops {
	int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
	void (*uninit_ae_dev)(struct hnae3_ae_dev *ae_dev);

	void (*flr_prepare)(struct hnae3_ae_dev *ae_dev);
	void (*flr_done)(struct hnae3_ae_dev *ae_dev);
	int (*init_client_instance)(struct hnae3_client *client,
				    struct hnae3_ae_dev *ae_dev);
	void (*uninit_client_instance)(struct hnae3_client *client,
+20 −0
Original line number Diff line number Diff line
@@ -1851,9 +1851,29 @@ static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev)
	return PCI_ERS_RESULT_DISCONNECT;
}

static void hns3_reset_prepare(struct pci_dev *pdev)
{
	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);

	dev_info(&pdev->dev, "hns3 flr prepare\n");
	if (ae_dev && ae_dev->ops && ae_dev->ops->flr_prepare)
		ae_dev->ops->flr_prepare(ae_dev);
}

static void hns3_reset_done(struct pci_dev *pdev)
{
	struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);

	dev_info(&pdev->dev, "hns3 flr done\n");
	if (ae_dev && ae_dev->ops && ae_dev->ops->flr_done)
		ae_dev->ops->flr_done(ae_dev);
}

static const struct pci_error_handlers hns3_err_handler = {
	.error_detected = hns3_error_detected,
	.slot_reset     = hns3_slot_reset,
	.reset_prepare	= hns3_reset_prepare,
	.reset_done	= hns3_reset_done,
};

static struct pci_driver hns3_driver = {
+2 −0
Original line number Diff line number Diff line
@@ -594,7 +594,9 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev)
{
	return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET ||
			   ae_dev->reset_type == HNAE3_FLR_RESET ||
			   ae_dev->reset_type == HNAE3_VF_FUNC_RESET ||
			   ae_dev->reset_type == HNAE3_VF_FULL_RESET ||
			   ae_dev->reset_type == HNAE3_VF_PF_FUNC_RESET));
}

+67 −0
Original line number Diff line number Diff line
@@ -2374,6 +2374,8 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
		reg = HCLGE_FUN_RST_ING;
		reg_bit = HCLGE_FUN_RST_ING_B;
		break;
	case HNAE3_FLR_RESET:
		break;
	default:
		dev_err(&hdev->pdev->dev,
			"Wait for unsupported reset type: %d\n",
@@ -2381,6 +2383,20 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
		return -EINVAL;
	}

	if (hdev->reset_type == HNAE3_FLR_RESET) {
		while (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state) &&
		       cnt++ < HCLGE_RESET_WAIT_CNT)
			msleep(HCLGE_RESET_WATI_MS);

		if (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state)) {
			dev_err(&hdev->pdev->dev,
				"flr wait timeout: %d\n", cnt);
			return -EBUSY;
		}

		return 0;
	}

	val = hclge_read_dev(&hdev->hw, reg);
	while (hnae3_get_bit(val, reg_bit) && cnt < HCLGE_RESET_WAIT_CNT) {
		msleep(HCLGE_RESET_WATI_MS);
@@ -2488,6 +2504,12 @@ static void hclge_do_reset(struct hclge_dev *hdev)
		set_bit(HNAE3_FUNC_RESET, &hdev->reset_pending);
		hclge_reset_task_schedule(hdev);
		break;
	case HNAE3_FLR_RESET:
		dev_info(&pdev->dev, "FLR requested\n");
		/* schedule again to check later */
		set_bit(HNAE3_FLR_RESET, &hdev->reset_pending);
		hclge_reset_task_schedule(hdev);
		break;
	default:
		dev_warn(&pdev->dev,
			 "Unsupported reset type: %d\n", hdev->reset_type);
@@ -2519,6 +2541,9 @@ static enum hnae3_reset_type hclge_get_reset_level(struct hclge_dev *hdev,
	} else if (test_bit(HNAE3_FUNC_RESET, addr)) {
		rst_level = HNAE3_FUNC_RESET;
		clear_bit(HNAE3_FUNC_RESET, addr);
	} else if (test_bit(HNAE3_FLR_RESET, addr)) {
		rst_level = HNAE3_FLR_RESET;
		clear_bit(HNAE3_FLR_RESET, addr);
	}

	return rst_level;
@@ -2555,6 +2580,8 @@ static int hclge_reset_prepare_down(struct hclge_dev *hdev)

	switch (hdev->reset_type) {
	case HNAE3_FUNC_RESET:
		/* fall through */
	case HNAE3_FLR_RESET:
		ret = hclge_set_all_vf_rst(hdev, true);
		break;
	default:
@@ -2589,6 +2616,14 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
		 */
		set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
		break;
	case HNAE3_FLR_RESET:
		/* There is no mechanism for PF to know if VF has stopped IO
		 * for now, just wait 100 ms for VF to stop IO
		 */
		msleep(100);
		set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
		set_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
		break;
	case HNAE3_IMP_RESET:
		reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG);
		hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG,
@@ -2647,6 +2682,8 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev)

	switch (hdev->reset_type) {
	case HNAE3_FUNC_RESET:
		/* fall through */
	case HNAE3_FLR_RESET:
		ret = hclge_set_all_vf_rst(hdev, false);
		break;
	default:
@@ -6917,6 +6954,34 @@ static void hclge_state_uninit(struct hclge_dev *hdev)
		cancel_work_sync(&hdev->mbx_service_task);
}

static void hclge_flr_prepare(struct hnae3_ae_dev *ae_dev)
{
#define HCLGE_FLR_WAIT_MS	100
#define HCLGE_FLR_WAIT_CNT	50
	struct hclge_dev *hdev = ae_dev->priv;
	int cnt = 0;

	clear_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
	clear_bit(HNAE3_FLR_DONE, &hdev->flr_state);
	set_bit(HNAE3_FLR_RESET, &hdev->default_reset_request);
	hclge_reset_event(hdev->pdev, NULL);

	while (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state) &&
	       cnt++ < HCLGE_FLR_WAIT_CNT)
		msleep(HCLGE_FLR_WAIT_MS);

	if (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state))
		dev_err(&hdev->pdev->dev,
			"flr wait down timeout: %d\n", cnt);
}

static void hclge_flr_done(struct hnae3_ae_dev *ae_dev)
{
	struct hclge_dev *hdev = ae_dev->priv;

	set_bit(HNAE3_FLR_DONE, &hdev->flr_state);
}

static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{
	struct pci_dev *pdev = ae_dev->pdev;
@@ -7575,6 +7640,8 @@ static void hclge_get_link_mode(struct hnae3_handle *handle,
static const struct hnae3_ae_ops hclge_ops = {
	.init_ae_dev = hclge_init_ae_dev,
	.uninit_ae_dev = hclge_uninit_ae_dev,
	.flr_prepare = hclge_flr_prepare,
	.flr_done = hclge_flr_done,
	.init_client_instance = hclge_init_client_instance,
	.uninit_client_instance = hclge_uninit_client_instance,
	.map_ring_to_vector = hclge_map_ring_to_vector,
+1 −0
Original line number Diff line number Diff line
@@ -597,6 +597,7 @@ struct hclge_dev {
	struct hclge_misc_vector misc_vector;
	struct hclge_hw_stats hw_stats;
	unsigned long state;
	unsigned long flr_state;
	unsigned long last_reset_time;

	enum hnae3_reset_type reset_type;
Loading