diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 8fc488e6db019d3f37e23a7379a087e06f1c1f06..3c65633b0971e4e70cb7529bceeb7798c59bb4cb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -533,6 +533,10 @@ struct hnae3_ae_ops { int (*priv_ops)(struct hnae3_handle *handle, int opcode, void *data, int length); #endif + int (*get_vf_config)(struct hnae3_handle *handle, int vf, + struct ifla_vf_info *ivf); + int (*set_vf_link_state)(struct hnae3_handle *handle, int vf, + int link_state); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 109919747bdfaed0ee3fe4f2b2ed4037e827a331..0cb10c793dffb853de3139740807ec9ff347590d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1881,6 +1881,28 @@ static int hns3_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, } #endif +static int hns3_nic_get_vf_config(struct net_device *ndev, int vf, + struct ifla_vf_info *ivf) +{ + struct hnae3_handle *h = hns3_get_handle(ndev); + + if (!h->ae_algo->ops->get_vf_config) + return -EOPNOTSUPP; + + return h->ae_algo->ops->get_vf_config(h, vf, ivf); +} + +static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf, + int link_state) +{ + struct hnae3_handle *h = hns3_get_handle(ndev); + + if (!h->ae_algo->ops->set_vf_link_state) + return -EOPNOTSUPP; + + return h->ae_algo->ops->set_vf_link_state(h, vf, link_state); +} + struct net_device_ops hns3_nic_netdev_ops = { .ndo_open = hns3_nic_net_open, .ndo_stop = hns3_nic_net_stop, @@ -1901,6 +1923,8 @@ struct net_device_ops hns3_nic_netdev_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = hns3_rx_flow_steer, #endif + .ndo_get_vf_config = hns3_nic_get_vf_config, + .ndo_set_vf_link_state = hns3_nic_set_vf_link_state, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 0e3ebb701b24be20e07fe4ad73ef869f9933d339..29df4c784c0b8272fb985a4dd3ef8f0b16dea11a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1612,6 +1612,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) for (i = 0; i < num_vport; i++) { vport->back = hdev; vport->vport_id = i; + vport->link_state = IFLA_VF_LINK_STATE_AUTO; vport->mps = HCLGE_MAC_DEFAULT_FRAME; vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE; vport->rxvlan_cfg.rx_vlan_offload_en = true; @@ -2830,6 +2831,39 @@ static int hclge_get_status(struct hnae3_handle *handle) return hdev->hw.mac.link; } +static int hclge_get_vf_config(struct hnae3_handle *handle, int vf, + struct ifla_vf_info *ivf) +{ +#define HCLGE_VF_VPORT_START_NUM 1 + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + if (vf < 0 || vf >= hdev->num_alloc_vport - HCLGE_VF_VPORT_START_NUM) + return -EINVAL; + + /* vf start from 1 in vport */ + vf += HCLGE_VF_VPORT_START_NUM; + ivf->vf = vf; + ivf->linkstate = hdev->vport[vf].link_state; + ether_addr_copy(ivf->mac, hdev->vport[vf].mac); + + return 0; +} + +static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf, + int link_state) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + if (vf <= 0 || vf >= hdev->num_alloc_vport) + return -EINVAL; + + hdev->vport[vf].link_state = link_state; + + return 0; +} + static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) { u32 rst_src_reg; @@ -10185,6 +10219,8 @@ struct hnae3_ae_ops hclge_ops = { .restore_vlan_table = hclge_restore_vlan_table, .reset_done = hclge_reset_done, .handle_imp_error = hclge_handle_imp_error, + .get_vf_config = hclge_get_vf_config, + .set_vf_link_state = hclge_set_vf_link_state, }; struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 335dc26322abacdcee8fec146cc9cfb67dfc21db..01956f346a54478a4885253bec305b28121ccb66 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -969,6 +969,8 @@ struct hclge_vport { unsigned long state; unsigned long last_active_jiffies; + int link_state; + u8 mac[ETH_ALEN]; int mps; /* Max packet size */ struct list_head uc_mac_list; /* Store VF unicast table */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index ce6ac9a38d5e40a3c42a32f7f8aa4b555a2004c3..48441f1e9ad395f75862a062c07d144161bba3c6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -260,17 +260,22 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, false, HCLGE_MAC_ADDR_UC); hclge_add_vport_mac_table(vport, mac_addr, HCLGE_MAC_ADDR_UC); + ether_addr_copy(vport->mac, mac_addr); } } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_UC_ADD) { status = hclge_add_uc_addr_common(vport, mac_addr); - if (!status) + if (!status) { hclge_add_vport_mac_table(vport, mac_addr, HCLGE_MAC_ADDR_UC); + ether_addr_copy(vport->mac, mac_addr); + } } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_UC_REMOVE) { status = hclge_rm_uc_addr_common(vport, mac_addr); - if (!status) + if (!status) { hclge_rm_vport_mac_table(vport, mac_addr, false, HCLGE_MAC_ADDR_UC); + eth_zero_addr(vport->mac); + } } else { dev_err(&hdev->pdev->dev, "failed to set unicast mac addr, unknown subcode %d\n", @@ -455,6 +460,8 @@ static int hclge_get_vf_media_type(struct hclge_vport *vport, static int hclge_get_link_info(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req) { +#define HCLGE_VF_LINK_STATE_UP 1U +#define HCLGE_VF_LINK_STATE_DOWN 0U struct hclge_dev *hdev = vport->back; u16 link_status; u8 msg_data[8]; @@ -462,7 +469,19 @@ static int hclge_get_link_info(struct hclge_vport *vport, u16 duplex; /* mac.link can only be 0 or 1 */ - link_status = (u16)hdev->hw.mac.link; + switch (vport->link_state) { + case IFLA_VF_LINK_STATE_ENABLE: + link_status = HCLGE_VF_LINK_STATE_UP; + break; + case IFLA_VF_LINK_STATE_DISABLE: + link_status = HCLGE_VF_LINK_STATE_DOWN; + break; + case IFLA_VF_LINK_STATE_AUTO: + default: + link_status = (u16)hdev->hw.mac.link; + break; + } + duplex = hdev->hw.mac.duplex; memcpy(&msg_data[0], &link_status, sizeof(u16)); memcpy(&msg_data[2], &hdev->hw.mac.speed, sizeof(u32));