diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 03a2eb0de926427d4b82410033c34c3c174611e3..3bac7b24b37c71262b4c3d171ff5d9e08b7c1852 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -541,6 +541,7 @@ struct hnae3_ae_ops { struct ifla_vf_info *ivf); int (*set_vf_link_state)(struct hnae3_handle *handle, int vf, int link_state); + int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p); }; 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 24857b046af7e1687420296b17caf6970ae2f3f1..582ad8b8e1b99dddadcf67a2bc45566e5bcc7864 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1916,6 +1916,23 @@ static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf, return h->ae_algo->ops->set_vf_link_state(h, vf, link_state); } +static int hns3_nic_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + + if (!h->ae_algo->ops->set_vf_mac) + return -EOPNOTSUPP; + + if (is_broadcast_ether_addr(mac) || + is_multicast_ether_addr(mac)) { + netdev_err(netdev, + "Set VF MAC error! invalid mac:%pM.\n", mac); + return -EINVAL; + } + + return h->ae_algo->ops->set_vf_mac(h, vf_id, mac); +} + struct net_device_ops hns3_nic_netdev_ops = { .ndo_open = hns3_nic_net_open, .ndo_stop = hns3_nic_net_stop, @@ -1939,6 +1956,7 @@ struct net_device_ops hns3_nic_netdev_ops = { #endif .ndo_get_vf_config = hns3_nic_get_vf_config, .ndo_set_vf_link_state = hns3_nic_set_vf_link_state, + .ndo_set_vf_mac = hns3_nic_set_vf_mac, }; @@ -3868,14 +3886,14 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv) } /* Set mac addr if it is configured. or leave it to the AE driver */ -static int hns3_init_mac_addr(struct net_device *netdev, bool init) +static int hns3_init_mac_addr(struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); struct hnae3_handle *h = priv->ae_handle; u8 mac_addr_temp[ETH_ALEN]; int ret = 0; - if (h->ae_algo->ops->get_mac_addr && init) { + if (h->ae_algo->ops->get_mac_addr) { h->ae_algo->ops->get_mac_addr(h, mac_addr_temp); ether_addr_copy(netdev->dev_addr, mac_addr_temp); } @@ -3988,7 +4006,7 @@ static int hns3_client_init(struct hnae3_handle *handle) handle->kinfo.netdev = netdev; handle->priv = (void *)priv; - hns3_init_mac_addr(netdev, true); + hns3_init_mac_addr(netdev); hns3_set_default_feature(netdev); @@ -4467,7 +4485,7 @@ static int hns3_reset_notify_restore_enet(struct hnae3_handle *handle) bool vlan_filter_enable; int ret = 0; - ret = hns3_init_mac_addr(netdev, false); + ret = hns3_init_mac_addr(netdev); if (ret) return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index a193f960b8eb962086a75d1bd84a86cbfde359dc..415cf28faede6753151fff386bba403493581daf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2843,8 +2843,12 @@ static struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf) { #define HCLGE_VF_VPORT_START_NUM 1 - if (vf < 0 || vf >= pci_num_vf(hdev->pdev)) + if (vf < 0 || vf >= pci_num_vf(hdev->pdev)) { + dev_err(&hdev->pdev->dev, + "Out-of-range(1 < vfid < %d) or Invalid VF(=%d) specified.\n", + pci_num_vf(hdev->pdev), vf); return NULL; + } /* vf start from 1 in vport */ vf += HCLGE_VF_VPORT_START_NUM; @@ -2884,6 +2888,31 @@ static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf, return 0; } +static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf, + u8 *mac_addr) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + if (ether_addr_equal(mac_addr, vport->mac)) { + dev_info(&hdev->pdev->dev, + "Specified MAC(=%pM) is same as before, no change committed!\n", + vport->mac); + return 0; + } + + ether_addr_copy(vport->mac, mac_addr); + dev_info(&hdev->pdev->dev, + "VF %d has been set to %pM. Please reload/reset VF\n", + vf, vport->mac); + + return 0; +} + static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) { u32 rst_src_reg; @@ -10368,6 +10397,7 @@ struct hnae3_ae_ops hclge_ops = { .get_vf_config = hclge_get_vf_config, .set_vf_link_state = hclge_set_vf_link_state, .set_vf_spoofchk = hclge_set_vf_spoofchk, + .set_vf_mac = hclge_set_vf_mac, }; struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 67d2be019f4921fc8d931cf58d0c1d0d3b597542..91b87293d41efd80f8d97db68b903fa492a5bd5e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -260,21 +260,18 @@ 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) { 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) { hclge_rm_vport_mac_table(vport, mac_addr, false, HCLGE_MAC_ADDR_UC); - eth_zero_addr(vport->mac); } } else { dev_err(&hdev->pdev->dev, @@ -433,6 +430,13 @@ static int hclge_get_vf_queue_info(struct hclge_vport *vport, HCLGE_TQPS_RSS_INFO_LEN); } +static int hclge_get_vf_mac_addr(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req) +{ + return hclge_gen_resp_to_vf(vport, mbx_req, 0, vport->mac, + ETH_ALEN); +} + static int hclge_get_vf_queue_depth(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req, bool gen_resp) @@ -789,6 +793,13 @@ void hclge_mbx_handler(struct hclge_dev *hdev) "PF fail(%d) to media type for VF\n", ret); break; + case HCLGE_MBX_GET_MAC_ADDR: + ret = hclge_get_vf_mac_addr(vport, req); + if (ret) + dev_err(&hdev->pdev->dev, + "PF failed(%d) to get MAC for VF\n", + ret); + break; case HCLGE_MBX_NCSI_ERROR: ae_dev->ops->set_default_reset_request(ae_dev, HNAE3_GLOBAL_RESET); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 3be82810f1b6f6edba295f045648f1e92cd0cb27..b47f7b978fd5a699388292434316c8bad01e13b4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1175,11 +1175,37 @@ static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle) } } +static int hclgevf_get_host_mac_addr(struct hclgevf_dev *hdev, u8 *p) +{ + u8 host_mac[ETH_ALEN]; + int status; + + status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_MAC_ADDR, 0, NULL, 0, + true, host_mac, ETH_ALEN); + if (status) { + dev_err(&hdev->pdev->dev, + "fail to get VF MAC from host %d", status); + return status; + } + + ether_addr_copy(p, host_mac); + + return 0; +} + static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + u8 host_mac_addr[ETH_ALEN]; + + if (hclgevf_get_host_mac_addr(hdev, host_mac_addr)) + return; - ether_addr_copy(p, hdev->hw.mac.mac_addr); + hdev->has_pf_mac = !is_zero_ether_addr(host_mac_addr); + if (hdev->has_pf_mac) + ether_addr_copy(p, host_mac_addr); + else + ether_addr_copy(p, hdev->hw.mac.mac_addr); } static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p, @@ -1188,10 +1214,22 @@ static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p, struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); u8 *old_mac_addr = (u8 *)hdev->hw.mac.mac_addr; u8 *new_mac_addr = (u8 *)p; + u8 host_mac_addr[ETH_ALEN]; u8 msg_data[ETH_ALEN * 2]; u16 subcode; int status; + status = hclgevf_get_host_mac_addr(hdev, host_mac_addr); + if (status) + return status; + + if (!is_first && hdev->has_pf_mac) { + dev_err(&hdev->pdev->dev, + "has host VF mac %pM, user MAC %pM not allow\n", + old_mac_addr, p); + return -EPERM; + } + ether_addr_copy(msg_data, new_mac_addr); ether_addr_copy(&msg_data[ETH_ALEN], old_mac_addr); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index e71a4c761392026036f99143f37d93e6fc264a9f..11d4382b6a0bf825e223f79a926b5ae9790ca8dd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -267,6 +267,7 @@ struct hclgevf_dev { u16 num_tx_desc; /* desc num of per tx queue */ u16 num_rx_desc; /* desc num of per rx queue */ u8 hw_tc_map; + u8 has_pf_mac; u16 num_msi; u16 num_msi_left;