Skip to content

Commit

Permalink
net: hns3: Add handling of MAC tunnel interruption
Browse files Browse the repository at this point in the history
MAC tnl interruptions are different from other type of RAS and MSI-X
errors, because some bits, such as OVF/LR/RF will occur during link up
and down.

The drivers should clear status of all MAC tnl interruption bits but
shouldn't print any message that would mislead the users.

In case that link down and re-up in a short time because of some reasons,
we record when they occurred, and users can query them by debugfs.

Signed-off-by: Weihang Li <liweihang@hisilicon.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Weihang Li authored and David S. Miller committed Apr 20, 2019
1 parent ffd140e commit a634578
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "dump mng tbl\n");
dev_info(&h->pdev->dev, "dump reset info\n");
dev_info(&h->pdev->dev, "dump ncl_config <offset> <length>(in hex)\n");
dev_info(&h->pdev->dev, "dump mac tnl status\n");

memset(printf_buf, 0, HNS3_DBG_BUF_LEN);
strncat(printf_buf, "dump reg [[bios common] [ssu <prt_id>]",
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ enum hclge_opcode_type {
HCLGE_OPC_QUERY_LINK_STATUS = 0x0307,
HCLGE_OPC_CONFIG_MAX_FRM_SIZE = 0x0308,
HCLGE_OPC_CONFIG_SPEED_DUP = 0x0309,
HCLGE_OPC_QUERY_MAC_TNL_INT = 0x0310,
HCLGE_OPC_MAC_TNL_INT_EN = 0x0311,
HCLGE_OPC_CLEAR_MAC_TNL_INT = 0x0312,
HCLGE_OPC_SERDES_LOOPBACK = 0x0315,

/* PFC/Pause commands */
Expand Down
22 changes: 22 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,26 @@ static void hclge_dbg_dump_ncl_config(struct hclge_dev *hdev, char *cmd_buf)
}
}

/* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt
* @hdev: pointer to struct hclge_dev
*/
static void hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev)
{
#define HCLGE_BILLION_NANO_SECONDS 1000000000

struct hclge_mac_tnl_stats stats;
unsigned long rem_nsec;

dev_info(&hdev->pdev->dev, "Recently generated mac tnl interruption:\n");

while (kfifo_get(&hdev->mac_tnl_log, &stats)) {
rem_nsec = do_div(stats.time, HCLGE_BILLION_NANO_SECONDS);
dev_info(&hdev->pdev->dev, "[%07lu.%03lu]status = 0x%x\n",
(unsigned long)stats.time, rem_nsec / 1000,
stats.status);
}
}

int hclge_dbg_run_cmd(struct hnae3_handle *handle, char *cmd_buf)
{
struct hclge_vport *vport = hclge_get_vport(handle);
Expand Down Expand Up @@ -1012,6 +1032,8 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, char *cmd_buf)
} else if (strncmp(cmd_buf, "dump ncl_config", 15) == 0) {
hclge_dbg_dump_ncl_config(hdev,
&cmd_buf[sizeof("dump ncl_config")]);
} else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
hclge_dbg_dump_mac_tnl_status(hdev);
} else {
dev_info(&hdev->pdev->dev, "unknown command\n");
return -EINVAL;
Expand Down
51 changes: 51 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,16 @@ static int hclge_cmd_query_error(struct hclge_dev *hdev,
return ret;
}

static int hclge_clear_mac_tnl_int(struct hclge_dev *hdev)
{
struct hclge_desc desc;

hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CLEAR_MAC_TNL_INT, false);
desc.data[0] = cpu_to_le32(HCLGE_MAC_TNL_INT_CLR);

return hclge_cmd_send(&hdev->hw, &desc, 1);
}

static int hclge_config_common_hw_err_int(struct hclge_dev *hdev, bool en)
{
struct device *dev = &hdev->pdev->dev;
Expand Down Expand Up @@ -911,6 +921,21 @@ static int hclge_config_mac_err_int(struct hclge_dev *hdev, bool en)
return ret;
}

int hclge_config_mac_tnl_int(struct hclge_dev *hdev, bool en)
{
struct hclge_desc desc;

hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_TNL_INT_EN, false);
if (en)
desc.data[0] = cpu_to_le32(HCLGE_MAC_TNL_INT_EN);
else
desc.data[0] = 0;

desc.data[1] = cpu_to_le32(HCLGE_MAC_TNL_INT_EN_MASK);

return hclge_cmd_send(&hdev->hw, &desc, 1);
}

static int hclge_config_ppu_error_interrupts(struct hclge_dev *hdev, u32 cmd,
bool en)
{
Expand Down Expand Up @@ -1611,6 +1636,7 @@ pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev)
int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
unsigned long *reset_requests)
{
struct hclge_mac_tnl_stats mac_tnl_stats;
struct device *dev = &hdev->pdev->dev;
u32 mpf_bd_num, pf_bd_num, bd_num;
enum hnae3_reset_type reset_level;
Expand Down Expand Up @@ -1745,6 +1771,31 @@ int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
set_bit(HNAE3_GLOBAL_RESET, reset_requests);
}

/* query and clear mac tnl interruptions */
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_MAC_TNL_INT,
true);
ret = hclge_cmd_send(&hdev->hw, &desc[0], 1);
if (ret) {
dev_err(dev, "query mac tnl int cmd failed (%d)\n", ret);
goto msi_error;
}

status = le32_to_cpu(desc->data[0]);
if (status) {
/* When mac tnl interrupt occurs, we record current time and
* register status here in a fifo, then clear the status. So
* that if link status changes suddenly at some time, we can
* query them by debugfs.
*/
mac_tnl_stats.time = local_clock();
mac_tnl_stats.status = status;
kfifo_put(&hdev->mac_tnl_log, mac_tnl_stats);
ret = hclge_clear_mac_tnl_int(hdev);
if (ret)
dev_err(dev, "clear mac tnl int failed (%d)\n", ret);
set_bit(HNAE3_NONE_RESET, reset_requests);
}

msi_error:
kfree(desc);
out:
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
#define HCLGE_NCSI_ERR_INT_TYPE 0x9
#define HCLGE_MAC_COMMON_ERR_INT_EN 0x107FF
#define HCLGE_MAC_COMMON_ERR_INT_EN_MASK 0x107FF
#define HCLGE_MAC_TNL_INT_EN GENMASK(7, 0)
#define HCLGE_MAC_TNL_INT_EN_MASK GENMASK(7, 0)
#define HCLGE_MAC_TNL_INT_CLR GENMASK(7, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT0_EN GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT0_EN_MASK GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT1_EN GENMASK(31, 0)
Expand Down Expand Up @@ -115,6 +118,7 @@ struct hclge_hw_error {
enum hnae3_reset_type reset_level;
};

int hclge_config_mac_tnl_int(struct hclge_dev *hdev, bool en);
int hclge_hw_error_set_state(struct hclge_dev *hdev, bool state);
pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev);
int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2248,6 +2248,7 @@ static void hclge_update_link_status(struct hclge_dev *hdev)
for (i = 0; i < hdev->num_vmdq_vport + 1; i++) {
handle = &hdev->vport[i].nic;
client->ops->link_status_change(handle, state);
hclge_config_mac_tnl_int(hdev, state);
rhandle = &hdev->vport[i].roce;
if (rclient && rclient->ops->link_status_change)
rclient->ops->link_status_change(rhandle,
Expand Down Expand Up @@ -7963,6 +7964,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
goto err_mdiobus_unreg;
}

INIT_KFIFO(hdev->mac_tnl_log);

hclge_dcb_ops_set(hdev);

timer_setup(&hdev->service_timer, hclge_service_timer, 0);
Expand Down Expand Up @@ -8116,6 +8119,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_enable_vector(&hdev->misc_vector, false);
synchronize_irq(hdev->misc_vector.vector_irq);

hclge_config_mac_tnl_int(hdev, false);
hclge_hw_error_set_state(hdev, false);
hclge_cmd_uninit(hdev);
hclge_misc_irq_uninit(hdev);
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/phy.h>
#include <linux/if_vlan.h>
#include <linux/kfifo.h>

#include "hclge_cmd.h"
#include "hnae3.h"
Expand Down Expand Up @@ -660,6 +661,12 @@ struct hclge_rst_stats {
u32 reset_cnt; /* the number of reset */
};

/* time and register status when mac tunnel interruption occur */
struct hclge_mac_tnl_stats {
u64 time;
u32 status;
};

/* For each bit of TCAM entry, it uses a pair of 'x' and
* 'y' to indicate which value to match, like below:
* ----------------------------------
Expand All @@ -686,6 +693,7 @@ struct hclge_rst_stats {
(y) = (_k_ ^ ~_v_) & (_k_); \
} while (0)

#define HCLGE_MAC_TNL_LOG_SIZE 8
#define HCLGE_VPORT_NUM 256
struct hclge_dev {
struct pci_dev *pdev;
Expand Down Expand Up @@ -802,6 +810,9 @@ struct hclge_dev {
struct mutex umv_mutex; /* protect share_umv_size */

struct mutex vport_cfg_mutex; /* Protect stored vf table */

DECLARE_KFIFO(mac_tnl_log, struct hclge_mac_tnl_stats,
HCLGE_MAC_TNL_LOG_SIZE);
};

/* VPort level vlan tag configuration for TX direction */
Expand Down

0 comments on commit a634578

Please sign in to comment.