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

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
...@@ -127,6 +127,7 @@ enum hnae3_reset_type { ...@@ -127,6 +127,7 @@ enum hnae3_reset_type {
HNAE3_VF_FUNC_RESET, HNAE3_VF_FUNC_RESET,
HNAE3_VF_PF_FUNC_RESET, HNAE3_VF_PF_FUNC_RESET,
HNAE3_VF_FULL_RESET, HNAE3_VF_FULL_RESET,
HNAE3_FLR_RESET,
HNAE3_FUNC_RESET, HNAE3_FUNC_RESET,
HNAE3_CORE_RESET, HNAE3_CORE_RESET,
HNAE3_GLOBAL_RESET, HNAE3_GLOBAL_RESET,
...@@ -134,6 +135,11 @@ enum hnae3_reset_type { ...@@ -134,6 +135,11 @@ enum hnae3_reset_type {
HNAE3_NONE_RESET, HNAE3_NONE_RESET,
}; };
enum hnae3_flr_state {
HNAE3_FLR_DOWN,
HNAE3_FLR_DONE,
};
struct hnae3_vector_info { struct hnae3_vector_info {
u8 __iomem *io_addr; u8 __iomem *io_addr;
int vector; int vector;
...@@ -299,7 +305,8 @@ struct hnae3_ae_dev { ...@@ -299,7 +305,8 @@ struct hnae3_ae_dev {
struct hnae3_ae_ops { struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
void (*uninit_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, int (*init_client_instance)(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev); struct hnae3_ae_dev *ae_dev);
void (*uninit_client_instance)(struct hnae3_client *client, void (*uninit_client_instance)(struct hnae3_client *client,
......
...@@ -1851,9 +1851,29 @@ static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev) ...@@ -1851,9 +1851,29 @@ static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT; 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 = { static const struct pci_error_handlers hns3_err_handler = {
.error_detected = hns3_error_detected, .error_detected = hns3_error_detected,
.slot_reset = hns3_slot_reset, .slot_reset = hns3_slot_reset,
.reset_prepare = hns3_reset_prepare,
.reset_done = hns3_reset_done,
}; };
static struct pci_driver hns3_driver = { static struct pci_driver hns3_driver = {
......
...@@ -594,7 +594,9 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value) ...@@ -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) static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev)
{ {
return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET || 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_FUNC_RESET ||
ae_dev->reset_type == HNAE3_VF_FULL_RESET ||
ae_dev->reset_type == HNAE3_VF_PF_FUNC_RESET)); ae_dev->reset_type == HNAE3_VF_PF_FUNC_RESET));
} }
......
...@@ -2374,6 +2374,8 @@ static int hclge_reset_wait(struct hclge_dev *hdev) ...@@ -2374,6 +2374,8 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
reg = HCLGE_FUN_RST_ING; reg = HCLGE_FUN_RST_ING;
reg_bit = HCLGE_FUN_RST_ING_B; reg_bit = HCLGE_FUN_RST_ING_B;
break; break;
case HNAE3_FLR_RESET:
break;
default: default:
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"Wait for unsupported reset type: %d\n", "Wait for unsupported reset type: %d\n",
...@@ -2381,6 +2383,20 @@ static int hclge_reset_wait(struct hclge_dev *hdev) ...@@ -2381,6 +2383,20 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
return -EINVAL; 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); val = hclge_read_dev(&hdev->hw, reg);
while (hnae3_get_bit(val, reg_bit) && cnt < HCLGE_RESET_WAIT_CNT) { while (hnae3_get_bit(val, reg_bit) && cnt < HCLGE_RESET_WAIT_CNT) {
msleep(HCLGE_RESET_WATI_MS); msleep(HCLGE_RESET_WATI_MS);
...@@ -2488,6 +2504,12 @@ static void hclge_do_reset(struct hclge_dev *hdev) ...@@ -2488,6 +2504,12 @@ static void hclge_do_reset(struct hclge_dev *hdev)
set_bit(HNAE3_FUNC_RESET, &hdev->reset_pending); set_bit(HNAE3_FUNC_RESET, &hdev->reset_pending);
hclge_reset_task_schedule(hdev); hclge_reset_task_schedule(hdev);
break; 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: default:
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"Unsupported reset type: %d\n", hdev->reset_type); "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, ...@@ -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)) { } else if (test_bit(HNAE3_FUNC_RESET, addr)) {
rst_level = HNAE3_FUNC_RESET; rst_level = HNAE3_FUNC_RESET;
clear_bit(HNAE3_FUNC_RESET, addr); 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; return rst_level;
...@@ -2555,6 +2580,8 @@ static int hclge_reset_prepare_down(struct hclge_dev *hdev) ...@@ -2555,6 +2580,8 @@ static int hclge_reset_prepare_down(struct hclge_dev *hdev)
switch (hdev->reset_type) { switch (hdev->reset_type) {
case HNAE3_FUNC_RESET: case HNAE3_FUNC_RESET:
/* fall through */
case HNAE3_FLR_RESET:
ret = hclge_set_all_vf_rst(hdev, true); ret = hclge_set_all_vf_rst(hdev, true);
break; break;
default: default:
...@@ -2589,6 +2616,14 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev) ...@@ -2589,6 +2616,14 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
*/ */
set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state); set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
break; 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: case HNAE3_IMP_RESET:
reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG);
hclge_write_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) ...@@ -2647,6 +2682,8 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev)
switch (hdev->reset_type) { switch (hdev->reset_type) {
case HNAE3_FUNC_RESET: case HNAE3_FUNC_RESET:
/* fall through */
case HNAE3_FLR_RESET:
ret = hclge_set_all_vf_rst(hdev, false); ret = hclge_set_all_vf_rst(hdev, false);
break; break;
default: default:
...@@ -6917,6 +6954,34 @@ static void hclge_state_uninit(struct hclge_dev *hdev) ...@@ -6917,6 +6954,34 @@ static void hclge_state_uninit(struct hclge_dev *hdev)
cancel_work_sync(&hdev->mbx_service_task); 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) static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{ {
struct pci_dev *pdev = ae_dev->pdev; struct pci_dev *pdev = ae_dev->pdev;
...@@ -7575,6 +7640,8 @@ static void hclge_get_link_mode(struct hnae3_handle *handle, ...@@ -7575,6 +7640,8 @@ static void hclge_get_link_mode(struct hnae3_handle *handle,
static const struct hnae3_ae_ops hclge_ops = { static const struct hnae3_ae_ops hclge_ops = {
.init_ae_dev = hclge_init_ae_dev, .init_ae_dev = hclge_init_ae_dev,
.uninit_ae_dev = hclge_uninit_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, .init_client_instance = hclge_init_client_instance,
.uninit_client_instance = hclge_uninit_client_instance, .uninit_client_instance = hclge_uninit_client_instance,
.map_ring_to_vector = hclge_map_ring_to_vector, .map_ring_to_vector = hclge_map_ring_to_vector,
......
...@@ -597,6 +597,7 @@ struct hclge_dev { ...@@ -597,6 +597,7 @@ struct hclge_dev {
struct hclge_misc_vector misc_vector; struct hclge_misc_vector misc_vector;
struct hclge_hw_stats hw_stats; struct hclge_hw_stats hw_stats;
unsigned long state; unsigned long state;
unsigned long flr_state;
unsigned long last_reset_time; unsigned long last_reset_time;
enum hnae3_reset_type reset_type; enum hnae3_reset_type reset_type;
......
...@@ -90,6 +90,8 @@ int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport) ...@@ -90,6 +90,8 @@ int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport)
if (hdev->reset_type == HNAE3_FUNC_RESET) if (hdev->reset_type == HNAE3_FUNC_RESET)
reset_type = HNAE3_VF_PF_FUNC_RESET; reset_type = HNAE3_VF_PF_FUNC_RESET;
else if (hdev->reset_type == HNAE3_FLR_RESET)
reset_type = HNAE3_VF_FULL_RESET;
else else
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment