net: hns3: fix set port based VLAN issue for VF
authorJian Shen <shenjian15@huawei.com>
Sun, 14 Apr 2019 01:47:38 +0000 (09:47 +0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 14 Apr 2019 20:47:35 +0000 (13:47 -0700)
In original codes, ndo_set_vf_vlan() in hns3 driver was implemented
wrong. It adds or removes VLAN into VLAN filter for VF, but VF is
unaware of it.

This patch fixes it. When VF loads up, it firstly queries the port
based VLAN state from PF. When user change port based VLAN state
from PF, PF firstly checks whether the VF is alive. If the VF is
alive, then PF notifies the VF the modification; otherwise PF
configure the port based VLAN state directly.

Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support")
Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c

index 9d3d45f02be19cf2fda5035069b153eb07363c8d..360463a40ba9d74f258506118322baa10ab31148 100644 (file)
@@ -43,6 +43,7 @@ enum HCLGE_MBX_OPCODE {
        HCLGE_MBX_GET_QID_IN_PF,        /* (VF -> PF) get queue id in pf */
        HCLGE_MBX_LINK_STAT_MODE,       /* (PF -> VF) link mode has changed */
        HCLGE_MBX_GET_LINK_MODE,        /* (VF -> PF) get the link mode of pf */
+       HLCGE_MBX_PUSH_VLAN_INFO,       /* (PF -> VF) push port base vlan */
        HCLGE_MBX_GET_MEDIA_TYPE,       /* (VF -> PF) get media type */
 
        HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */
@@ -63,6 +64,8 @@ enum hclge_mbx_vlan_cfg_subcode {
        HCLGE_MBX_VLAN_FILTER = 0,      /* set vlan filter */
        HCLGE_MBX_VLAN_TX_OFF_CFG,      /* set tx side vlan offload */
        HCLGE_MBX_VLAN_RX_OFF_CFG,      /* set rx side vlan offload */
+       HCLGE_MBX_PORT_BASE_VLAN_CFG,   /* set port based vlan configuration */
+       HCLGE_MBX_GET_PORT_BASE_VLAN_STATE,     /* get port based vlan state */
 };
 
 #define HCLGE_MBX_MAX_MSG_SIZE 16
index 0a99a97b19bfa277268c11771815f06899abbac7..0d1cd3f5eafd04f4f7fd56f85d1dd9581b57de84 100644 (file)
@@ -7067,7 +7067,16 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
                return ret;
        }
 
-       return -EOPNOTSUPP;
+       if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) {
+               return hclge_update_port_base_vlan_cfg(vport, state,
+                                                      &vlan_info);
+       } else {
+               ret = hclge_push_vf_port_base_vlan_info(&hdev->vport[0],
+                                                       (u8)vfid, state,
+                                                       vlan, qos,
+                                                       ntohs(proto));
+               return ret;
+       }
 }
 
 int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
index 45c946741f5f1b2ee1320f70a92d197d5cc951e8..f04a52f143ae1f56a9af4318e6e3cff60254eb76 100644 (file)
@@ -941,4 +941,7 @@ void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list);
 void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev);
 int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
                                    struct hclge_vlan_info *vlan_info);
+int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
+                                     u16 state, u16 vlan_tag, u16 qos,
+                                     u16 vlan_proto);
 #endif
index fddbbcaa681a5e91fbcca724c8383f88139a9a3e..24386bd894f713b4541bddb7062d7a0a93e1ff16 100644 (file)
@@ -289,9 +289,25 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
        return 0;
 }
 
+int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
+                                     u16 state, u16 vlan_tag, u16 qos,
+                                     u16 vlan_proto)
+{
+#define MSG_DATA_SIZE  8
+
+       u8 msg_data[MSG_DATA_SIZE];
+
+       memcpy(&msg_data[0], &state, sizeof(u16));
+       memcpy(&msg_data[2], &vlan_proto, sizeof(u16));
+       memcpy(&msg_data[4], &qos, sizeof(u16));
+       memcpy(&msg_data[6], &vlan_tag, sizeof(u16));
+
+       return hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
+                                 HLCGE_MBX_PUSH_VLAN_INFO, vfid);
+}
+
 static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
-                                struct hclge_mbx_vf_to_pf_cmd *mbx_req,
-                                bool gen_resp)
+                                struct hclge_mbx_vf_to_pf_cmd *mbx_req)
 {
        int status = 0;
 
@@ -310,11 +326,22 @@ static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
                bool en = mbx_req->msg[2] ? true : false;
 
                status = hclge_en_hw_strip_rxvtag(handle, en);
+       } else if (mbx_req->msg[1] == HCLGE_MBX_PORT_BASE_VLAN_CFG) {
+               struct hclge_vlan_info *vlan_info;
+               u16 *state;
+
+               state = (u16 *)&mbx_req->msg[2];
+               vlan_info = (struct hclge_vlan_info *)&mbx_req->msg[4];
+               status = hclge_update_port_base_vlan_cfg(vport, *state,
+                                                        vlan_info);
+       } else if (mbx_req->msg[1] == HCLGE_MBX_GET_PORT_BASE_VLAN_STATE) {
+               u8 state;
+
+               state = vport->port_base_vlan_cfg.state;
+               status = hclge_gen_resp_to_vf(vport, mbx_req, 0, &state,
+                                             sizeof(u8));
        }
 
-       if (gen_resp)
-               status = hclge_gen_resp_to_vf(vport, mbx_req, status, NULL, 0);
-
        return status;
 }
 
@@ -584,7 +611,7 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
                                        ret);
                        break;
                case HCLGE_MBX_SET_VLAN:
-                       ret = hclge_set_vf_vlan_cfg(vport, req, false);
+                       ret = hclge_set_vf_vlan_cfg(vport, req);
                        if (ret)
                                dev_err(&hdev->pdev->dev,
                                        "PF failed(%d) to config VF's VLAN\n",
index b91796007200ef4b75d738a8c29e0eca1a8c126e..2e277c91a106b50a5a9fa7052b30bf031cdd67b6 100644 (file)
@@ -245,6 +245,27 @@ static int hclgevf_get_tc_info(struct hclgevf_dev *hdev)
        return 0;
 }
 
+static int hclgevf_get_port_base_vlan_filter_state(struct hclgevf_dev *hdev)
+{
+       struct hnae3_handle *nic = &hdev->nic;
+       u8 resp_msg;
+       int ret;
+
+       ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
+                                  HCLGE_MBX_GET_PORT_BASE_VLAN_STATE,
+                                  NULL, 0, true, &resp_msg, sizeof(u8));
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "VF request to get port based vlan state failed %d",
+                       ret);
+               return ret;
+       }
+
+       nic->port_base_vlan_state = resp_msg;
+
+       return 0;
+}
+
 static int hclgevf_get_queue_info(struct hclgevf_dev *hdev)
 {
 #define HCLGEVF_TQPS_RSS_INFO_LEN      6
@@ -1834,6 +1855,11 @@ static int hclgevf_configure(struct hclgevf_dev *hdev)
 {
        int ret;
 
+       /* get current port based vlan state from PF */
+       ret = hclgevf_get_port_base_vlan_filter_state(hdev);
+       if (ret)
+               return ret;
+
        /* get queue configuration from PF */
        ret = hclgevf_get_queue_info(hdev);
        if (ret)
@@ -2790,6 +2816,31 @@ static void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version,
        }
 }
 
+void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state,
+                                       u8 *port_base_vlan_info, u8 data_size)
+{
+       struct hnae3_handle *nic = &hdev->nic;
+
+       rtnl_lock();
+       hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT);
+       rtnl_unlock();
+
+       /* send msg to PF and wait update port based vlan info */
+       hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
+                            HCLGE_MBX_PORT_BASE_VLAN_CFG,
+                            port_base_vlan_info, data_size,
+                            false, NULL, 0);
+
+       if (state == HNAE3_PORT_BASE_VLAN_DISABLE)
+               nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_DISABLE;
+       else
+               nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_ENABLE;
+
+       rtnl_lock();
+       hclgevf_notify_client(hdev, HNAE3_UP_CLIENT);
+       rtnl_unlock();
+}
+
 static const struct hnae3_ae_ops hclgevf_ops = {
        .init_ae_dev = hclgevf_init_ae_dev,
        .uninit_ae_dev = hclgevf_uninit_ae_dev,
index c128863ee7d07f5bd7922a286e9d24a6c5fac6ed..49e5bec53d45624d8afae0475d4f1737f02e59b4 100644 (file)
@@ -290,4 +290,6 @@ void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed,
                                 u8 duplex);
 void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev);
 void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev);
+void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state,
+                                       u8 *port_base_vlan_info, u8 data_size);
 #endif
index 3bcf49bde11a3c60bdfffb930b97cf726c6a2423..bf570840b1f4e65538b9a6bba3b402c978842499 100644 (file)
@@ -198,6 +198,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
                case HCLGE_MBX_LINK_STAT_CHANGE:
                case HCLGE_MBX_ASSERTING_RESET:
                case HCLGE_MBX_LINK_STAT_MODE:
+               case HLCGE_MBX_PUSH_VLAN_INFO:
                        /* set this mbx event as pending. This is required as we
                         * might loose interrupt event when mbx task is busy
                         * handling. This shall be cleared when mbx task just
@@ -243,8 +244,8 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
 void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
 {
        enum hnae3_reset_type reset_type;
-       u16 link_status;
-       u16 *msg_q;
+       u16 link_status, state;
+       u16 *msg_q, *vlan_info;
        u8 duplex;
        u32 speed;
        u32 tail;
@@ -299,6 +300,12 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
                        hclgevf_reset_task_schedule(hdev);
 
                        break;
+               case HLCGE_MBX_PUSH_VLAN_INFO:
+                       state = le16_to_cpu(msg_q[1]);
+                       vlan_info = &msg_q[1];
+                       hclgevf_update_port_base_vlan_info(hdev, state,
+                                                          (u8 *)vlan_info, 8);
+                       break;
                default:
                        dev_err(&hdev->pdev->dev,
                                "fetched unsupported(%d) message from arq\n",