diff options
author | Yuval Mintz <Yuval.Mintz@qlogic.com> | 2016-05-11 09:36:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-12 00:04:08 -0400 |
commit | eff169608c250193e72089dc4ab15cb79e0bd68c (patch) | |
tree | 1e2c0fef7a427954be8800ee21914e34a6c61d87 | |
parent | 08feecd7fc709077ce92d21a979f522a5f57170a (diff) |
qed*: Support forced MAC
Allows the PF to enforce the VF's mac.
i.e., by using `ip link ... vf <x> mac <value>'.
While a MAC is forced, PF would prevent the VF from configuring any other
MAC.
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_l2.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_sriov.c | 120 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_sriov.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_vf.c | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_vf.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qede/qede_main.c | 31 | ||||
-rw-r--r-- | include/linux/qed/qed_eth_if.h | 3 | ||||
-rw-r--r-- | include/linux/qed/qed_iov_if.h | 2 |
8 files changed, 234 insertions, 0 deletions
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 7fb6b82f1a97..8d83250aa5ba 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c | |||
@@ -1701,6 +1701,14 @@ static void qed_register_eth_ops(struct qed_dev *cdev, | |||
1701 | qed_vf_start_iov_wq(cdev); | 1701 | qed_vf_start_iov_wq(cdev); |
1702 | } | 1702 | } |
1703 | 1703 | ||
1704 | static bool qed_check_mac(struct qed_dev *cdev, u8 *mac) | ||
1705 | { | ||
1706 | if (IS_PF(cdev)) | ||
1707 | return true; | ||
1708 | |||
1709 | return qed_vf_check_mac(&cdev->hwfns[0], mac); | ||
1710 | } | ||
1711 | |||
1704 | static int qed_start_vport(struct qed_dev *cdev, | 1712 | static int qed_start_vport(struct qed_dev *cdev, |
1705 | struct qed_start_vport_params *params) | 1713 | struct qed_start_vport_params *params) |
1706 | { | 1714 | { |
@@ -2149,6 +2157,7 @@ static const struct qed_eth_ops qed_eth_ops_pass = { | |||
2149 | #endif | 2157 | #endif |
2150 | .fill_dev_info = &qed_fill_eth_dev_info, | 2158 | .fill_dev_info = &qed_fill_eth_dev_info, |
2151 | .register_ops = &qed_register_eth_ops, | 2159 | .register_ops = &qed_register_eth_ops, |
2160 | .check_mac = &qed_check_mac, | ||
2152 | .vport_start = &qed_start_vport, | 2161 | .vport_start = &qed_start_vport, |
2153 | .vport_stop = &qed_stop_vport, | 2162 | .vport_stop = &qed_stop_vport, |
2154 | .vport_update = &qed_update_vport, | 2163 | .vport_update = &qed_update_vport, |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 77d44baa5df3..c1b79190ce4d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c | |||
@@ -1295,6 +1295,29 @@ static int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn, | |||
1295 | if (!p_vf->vport_instance) | 1295 | if (!p_vf->vport_instance) |
1296 | return -EINVAL; | 1296 | return -EINVAL; |
1297 | 1297 | ||
1298 | if (events & (1 << MAC_ADDR_FORCED)) { | ||
1299 | /* Since there's no way [currently] of removing the MAC, | ||
1300 | * we can always assume this means we need to force it. | ||
1301 | */ | ||
1302 | memset(&filter, 0, sizeof(filter)); | ||
1303 | filter.type = QED_FILTER_MAC; | ||
1304 | filter.opcode = QED_FILTER_REPLACE; | ||
1305 | filter.is_rx_filter = 1; | ||
1306 | filter.is_tx_filter = 1; | ||
1307 | filter.vport_to_add_to = p_vf->vport_id; | ||
1308 | ether_addr_copy(filter.mac, p_vf->bulletin.p_virt->mac); | ||
1309 | |||
1310 | rc = qed_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid, | ||
1311 | &filter, QED_SPQ_MODE_CB, NULL); | ||
1312 | if (rc) { | ||
1313 | DP_NOTICE(p_hwfn, | ||
1314 | "PF failed to configure MAC for VF\n"); | ||
1315 | return rc; | ||
1316 | } | ||
1317 | |||
1318 | p_vf->configured_features |= 1 << MAC_ADDR_FORCED; | ||
1319 | } | ||
1320 | |||
1298 | if (events & (1 << VLAN_ADDR_FORCED)) { | 1321 | if (events & (1 << VLAN_ADDR_FORCED)) { |
1299 | struct qed_sp_vport_update_params vport_update; | 1322 | struct qed_sp_vport_update_params vport_update; |
1300 | u8 removal; | 1323 | u8 removal; |
@@ -2199,6 +2222,16 @@ static void qed_iov_vf_mbx_ucast_filter(struct qed_hwfn *p_hwfn, | |||
2199 | goto out; | 2222 | goto out; |
2200 | } | 2223 | } |
2201 | 2224 | ||
2225 | if ((p_bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED)) && | ||
2226 | (params.type == QED_FILTER_MAC || | ||
2227 | params.type == QED_FILTER_MAC_VLAN)) { | ||
2228 | if (!ether_addr_equal(p_bulletin->mac, params.mac) || | ||
2229 | (params.opcode != QED_FILTER_ADD && | ||
2230 | params.opcode != QED_FILTER_REPLACE)) | ||
2231 | status = PFVF_STATUS_FORCED; | ||
2232 | goto out; | ||
2233 | } | ||
2234 | |||
2202 | rc = qed_iov_chk_ucast(p_hwfn, vf->relative_vf_id, ¶ms); | 2235 | rc = qed_iov_chk_ucast(p_hwfn, vf->relative_vf_id, ¶ms); |
2203 | if (rc) { | 2236 | if (rc) { |
2204 | status = PFVF_STATUS_FAILURE; | 2237 | status = PFVF_STATUS_FAILURE; |
@@ -2702,6 +2735,30 @@ static int qed_iov_copy_vf_msg(struct qed_hwfn *p_hwfn, struct qed_ptt *ptt, | |||
2702 | return 0; | 2735 | return 0; |
2703 | } | 2736 | } |
2704 | 2737 | ||
2738 | static void qed_iov_bulletin_set_forced_mac(struct qed_hwfn *p_hwfn, | ||
2739 | u8 *mac, int vfid) | ||
2740 | { | ||
2741 | struct qed_vf_info *vf_info; | ||
2742 | u64 feature; | ||
2743 | |||
2744 | vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true); | ||
2745 | if (!vf_info) { | ||
2746 | DP_NOTICE(p_hwfn->cdev, | ||
2747 | "Can not set forced MAC, invalid vfid [%d]\n", vfid); | ||
2748 | return; | ||
2749 | } | ||
2750 | |||
2751 | feature = 1 << MAC_ADDR_FORCED; | ||
2752 | memcpy(vf_info->bulletin.p_virt->mac, mac, ETH_ALEN); | ||
2753 | |||
2754 | vf_info->bulletin.p_virt->valid_bitmap |= feature; | ||
2755 | /* Forced MAC will disable MAC_ADDR */ | ||
2756 | vf_info->bulletin.p_virt->valid_bitmap &= | ||
2757 | ~(1 << VFPF_BULLETIN_MAC_ADDR); | ||
2758 | |||
2759 | qed_iov_configure_vport_forced(p_hwfn, vf_info, feature); | ||
2760 | } | ||
2761 | |||
2705 | void qed_iov_bulletin_set_forced_vlan(struct qed_hwfn *p_hwfn, | 2762 | void qed_iov_bulletin_set_forced_vlan(struct qed_hwfn *p_hwfn, |
2706 | u16 pvid, int vfid) | 2763 | u16 pvid, int vfid) |
2707 | { | 2764 | { |
@@ -2736,6 +2793,21 @@ bool qed_iov_is_vf_stopped(struct qed_hwfn *p_hwfn, int vfid) | |||
2736 | return p_vf_info->state == VF_STOPPED; | 2793 | return p_vf_info->state == VF_STOPPED; |
2737 | } | 2794 | } |
2738 | 2795 | ||
2796 | static u8 *qed_iov_bulletin_get_forced_mac(struct qed_hwfn *p_hwfn, | ||
2797 | u16 rel_vf_id) | ||
2798 | { | ||
2799 | struct qed_vf_info *p_vf; | ||
2800 | |||
2801 | p_vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true); | ||
2802 | if (!p_vf || !p_vf->bulletin.p_virt) | ||
2803 | return NULL; | ||
2804 | |||
2805 | if (!(p_vf->bulletin.p_virt->valid_bitmap & (1 << MAC_ADDR_FORCED))) | ||
2806 | return NULL; | ||
2807 | |||
2808 | return p_vf->bulletin.p_virt->mac; | ||
2809 | } | ||
2810 | |||
2739 | u16 qed_iov_bulletin_get_forced_vlan(struct qed_hwfn *p_hwfn, u16 rel_vf_id) | 2811 | u16 qed_iov_bulletin_get_forced_vlan(struct qed_hwfn *p_hwfn, u16 rel_vf_id) |
2740 | { | 2812 | { |
2741 | struct qed_vf_info *p_vf; | 2813 | struct qed_vf_info *p_vf; |
@@ -2899,6 +2971,38 @@ static int qed_sriov_configure(struct qed_dev *cdev, int num_vfs_param) | |||
2899 | return qed_sriov_disable(cdev, true); | 2971 | return qed_sriov_disable(cdev, true); |
2900 | } | 2972 | } |
2901 | 2973 | ||
2974 | static int qed_sriov_pf_set_mac(struct qed_dev *cdev, u8 *mac, int vfid) | ||
2975 | { | ||
2976 | int i; | ||
2977 | |||
2978 | if (!IS_QED_SRIOV(cdev) || !IS_PF_SRIOV_ALLOC(&cdev->hwfns[0])) { | ||
2979 | DP_VERBOSE(cdev, QED_MSG_IOV, | ||
2980 | "Cannot set a VF MAC; Sriov is not enabled\n"); | ||
2981 | return -EINVAL; | ||
2982 | } | ||
2983 | |||
2984 | if (!qed_iov_is_valid_vfid(&cdev->hwfns[0], vfid, true)) { | ||
2985 | DP_VERBOSE(cdev, QED_MSG_IOV, | ||
2986 | "Cannot set VF[%d] MAC (VF is not active)\n", vfid); | ||
2987 | return -EINVAL; | ||
2988 | } | ||
2989 | |||
2990 | for_each_hwfn(cdev, i) { | ||
2991 | struct qed_hwfn *hwfn = &cdev->hwfns[i]; | ||
2992 | struct qed_public_vf_info *vf_info; | ||
2993 | |||
2994 | vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); | ||
2995 | if (!vf_info) | ||
2996 | continue; | ||
2997 | |||
2998 | /* Set the forced MAC, and schedule the IOV task */ | ||
2999 | ether_addr_copy(vf_info->forced_mac, mac); | ||
3000 | qed_schedule_iov(hwfn, QED_IOV_WQ_SET_UNICAST_FILTER_FLAG); | ||
3001 | } | ||
3002 | |||
3003 | return 0; | ||
3004 | } | ||
3005 | |||
2902 | static int qed_sriov_pf_set_vlan(struct qed_dev *cdev, u16 vid, int vfid) | 3006 | static int qed_sriov_pf_set_vlan(struct qed_dev *cdev, u16 vid, int vfid) |
2903 | { | 3007 | { |
2904 | int i; | 3008 | int i; |
@@ -3000,12 +3104,27 @@ static void qed_handle_pf_set_vf_unicast(struct qed_hwfn *hwfn) | |||
3000 | qed_for_each_vf(hwfn, i) { | 3104 | qed_for_each_vf(hwfn, i) { |
3001 | struct qed_public_vf_info *info; | 3105 | struct qed_public_vf_info *info; |
3002 | bool update = false; | 3106 | bool update = false; |
3107 | u8 *mac; | ||
3003 | 3108 | ||
3004 | info = qed_iov_get_public_vf_info(hwfn, i, true); | 3109 | info = qed_iov_get_public_vf_info(hwfn, i, true); |
3005 | if (!info) | 3110 | if (!info) |
3006 | continue; | 3111 | continue; |
3007 | 3112 | ||
3008 | /* Update data on bulletin board */ | 3113 | /* Update data on bulletin board */ |
3114 | mac = qed_iov_bulletin_get_forced_mac(hwfn, i); | ||
3115 | if (is_valid_ether_addr(info->forced_mac) && | ||
3116 | (!mac || !ether_addr_equal(mac, info->forced_mac))) { | ||
3117 | DP_VERBOSE(hwfn, | ||
3118 | QED_MSG_IOV, | ||
3119 | "Handling PF setting of VF MAC to VF 0x%02x [Abs 0x%02x]\n", | ||
3120 | i, | ||
3121 | hwfn->cdev->p_iov_info->first_vf_in_pf + i); | ||
3122 | |||
3123 | /* Update bulletin board with forced MAC */ | ||
3124 | qed_iov_bulletin_set_forced_mac(hwfn, | ||
3125 | info->forced_mac, i); | ||
3126 | update = true; | ||
3127 | } | ||
3009 | 3128 | ||
3010 | if (qed_iov_bulletin_get_forced_vlan(hwfn, i) ^ | 3129 | if (qed_iov_bulletin_get_forced_vlan(hwfn, i) ^ |
3011 | info->forced_vlan) { | 3130 | info->forced_vlan) { |
@@ -3133,5 +3252,6 @@ int qed_iov_wq_start(struct qed_dev *cdev) | |||
3133 | 3252 | ||
3134 | const struct qed_iov_hv_ops qed_iov_ops_pass = { | 3253 | const struct qed_iov_hv_ops qed_iov_ops_pass = { |
3135 | .configure = &qed_sriov_configure, | 3254 | .configure = &qed_sriov_configure, |
3255 | .set_mac = &qed_sriov_pf_set_mac, | ||
3136 | .set_vlan = &qed_sriov_pf_set_vlan, | 3256 | .set_vlan = &qed_sriov_pf_set_vlan, |
3137 | }; | 3257 | }; |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index e65f403349c2..e38ea985abe1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h | |||
@@ -43,6 +43,7 @@ struct qed_public_vf_info { | |||
43 | /* These copies will later be reflected in the bulletin board, | 43 | /* These copies will later be reflected in the bulletin board, |
44 | * but this copy should be newer. | 44 | * but this copy should be newer. |
45 | */ | 45 | */ |
46 | u8 forced_mac[ETH_ALEN]; | ||
46 | u16 forced_vlan; | 47 | u16 forced_vlan; |
47 | u8 mac[ETH_ALEN]; | 48 | u8 mac[ETH_ALEN]; |
48 | }; | 49 | }; |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 3c8911de3ed4..db14e230c9a4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/crc32.h> | 9 | #include <linux/crc32.h> |
10 | #include <linux/etherdevice.h> | ||
10 | #include "qed.h" | 11 | #include "qed.h" |
11 | #include "qed_sriov.h" | 12 | #include "qed_sriov.h" |
12 | #include "qed_vf.h" | 13 | #include "qed_vf.h" |
@@ -1004,6 +1005,43 @@ void qed_vf_get_num_vlan_filters(struct qed_hwfn *p_hwfn, u8 *num_vlan_filters) | |||
1004 | *num_vlan_filters = p_vf->acquire_resp.resc.num_vlan_filters; | 1005 | *num_vlan_filters = p_vf->acquire_resp.resc.num_vlan_filters; |
1005 | } | 1006 | } |
1006 | 1007 | ||
1008 | bool qed_vf_check_mac(struct qed_hwfn *p_hwfn, u8 *mac) | ||
1009 | { | ||
1010 | struct qed_bulletin_content *bulletin; | ||
1011 | |||
1012 | bulletin = &p_hwfn->vf_iov_info->bulletin_shadow; | ||
1013 | if (!(bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED))) | ||
1014 | return true; | ||
1015 | |||
1016 | /* Forbid VF from changing a MAC enforced by PF */ | ||
1017 | if (ether_addr_equal(bulletin->mac, mac)) | ||
1018 | return false; | ||
1019 | |||
1020 | return false; | ||
1021 | } | ||
1022 | |||
1023 | bool qed_vf_bulletin_get_forced_mac(struct qed_hwfn *hwfn, | ||
1024 | u8 *dst_mac, u8 *p_is_forced) | ||
1025 | { | ||
1026 | struct qed_bulletin_content *bulletin; | ||
1027 | |||
1028 | bulletin = &hwfn->vf_iov_info->bulletin_shadow; | ||
1029 | |||
1030 | if (bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED)) { | ||
1031 | if (p_is_forced) | ||
1032 | *p_is_forced = 1; | ||
1033 | } else if (bulletin->valid_bitmap & (1 << VFPF_BULLETIN_MAC_ADDR)) { | ||
1034 | if (p_is_forced) | ||
1035 | *p_is_forced = 0; | ||
1036 | } else { | ||
1037 | return false; | ||
1038 | } | ||
1039 | |||
1040 | ether_addr_copy(dst_mac, bulletin->mac); | ||
1041 | |||
1042 | return true; | ||
1043 | } | ||
1044 | |||
1007 | void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn, | 1045 | void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn, |
1008 | u16 *fw_major, u16 *fw_minor, | 1046 | u16 *fw_major, u16 *fw_minor, |
1009 | u16 *fw_rev, u16 *fw_eng) | 1047 | u16 *fw_rev, u16 *fw_eng) |
@@ -1020,6 +1058,15 @@ void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn, | |||
1020 | 1058 | ||
1021 | static void qed_handle_bulletin_change(struct qed_hwfn *hwfn) | 1059 | static void qed_handle_bulletin_change(struct qed_hwfn *hwfn) |
1022 | { | 1060 | { |
1061 | struct qed_eth_cb_ops *ops = hwfn->cdev->protocol_ops.eth; | ||
1062 | u8 mac[ETH_ALEN], is_mac_exist, is_mac_forced; | ||
1063 | void *cookie = hwfn->cdev->ops_cookie; | ||
1064 | |||
1065 | is_mac_exist = qed_vf_bulletin_get_forced_mac(hwfn, mac, | ||
1066 | &is_mac_forced); | ||
1067 | if (is_mac_exist && is_mac_forced && cookie) | ||
1068 | ops->force_mac(cookie, mac); | ||
1069 | |||
1023 | /* Always update link configuration according to bulletin */ | 1070 | /* Always update link configuration according to bulletin */ |
1024 | qed_link_update(hwfn); | 1071 | qed_link_update(hwfn); |
1025 | } | 1072 | } |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 35eced3691ba..b82fda964bbd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h | |||
@@ -418,6 +418,8 @@ union pfvf_tlvs { | |||
418 | }; | 418 | }; |
419 | 419 | ||
420 | enum qed_bulletin_bit { | 420 | enum qed_bulletin_bit { |
421 | /* Alert the VF that a forced MAC was set by the PF */ | ||
422 | MAC_ADDR_FORCED = 0, | ||
421 | /* Alert the VF that a forced VLAN was set by the PF */ | 423 | /* Alert the VF that a forced VLAN was set by the PF */ |
422 | VLAN_ADDR_FORCED = 2, | 424 | VLAN_ADDR_FORCED = 2, |
423 | 425 | ||
@@ -425,6 +427,10 @@ enum qed_bulletin_bit { | |||
425 | VFPF_BULLETIN_UNTAGGED_DEFAULT = 3, | 427 | VFPF_BULLETIN_UNTAGGED_DEFAULT = 3, |
426 | VFPF_BULLETIN_UNTAGGED_DEFAULT_FORCED = 4, | 428 | VFPF_BULLETIN_UNTAGGED_DEFAULT_FORCED = 4, |
427 | 429 | ||
430 | /* Alert the VF that suggested mac was sent by the PF. | ||
431 | * MAC_ADDR will be disabled in case MAC_ADDR_FORCED is set. | ||
432 | */ | ||
433 | VFPF_BULLETIN_MAC_ADDR = 5 | ||
428 | }; | 434 | }; |
429 | 435 | ||
430 | struct qed_bulletin_content { | 436 | struct qed_bulletin_content { |
@@ -602,6 +608,16 @@ void qed_vf_get_num_vlan_filters(struct qed_hwfn *p_hwfn, | |||
602 | u8 *num_vlan_filters); | 608 | u8 *num_vlan_filters); |
603 | 609 | ||
604 | /** | 610 | /** |
611 | * @brief Check if VF can set a MAC address | ||
612 | * | ||
613 | * @param p_hwfn | ||
614 | * @param mac | ||
615 | * | ||
616 | * @return bool | ||
617 | */ | ||
618 | bool qed_vf_check_mac(struct qed_hwfn *p_hwfn, u8 *mac); | ||
619 | |||
620 | /** | ||
605 | * @brief Set firmware version information in dev_info from VFs acquire response tlv | 621 | * @brief Set firmware version information in dev_info from VFs acquire response tlv |
606 | * | 622 | * |
607 | * @param p_hwfn | 623 | * @param p_hwfn |
@@ -841,6 +857,11 @@ static inline void qed_vf_get_num_vlan_filters(struct qed_hwfn *p_hwfn, | |||
841 | { | 857 | { |
842 | } | 858 | } |
843 | 859 | ||
860 | static inline bool qed_vf_check_mac(struct qed_hwfn *p_hwfn, u8 *mac) | ||
861 | { | ||
862 | return false; | ||
863 | } | ||
864 | |||
844 | static inline void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn, | 865 | static inline void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn, |
845 | u16 *fw_major, u16 *fw_minor, | 866 | u16 *fw_major, u16 *fw_minor, |
846 | u16 *fw_rev, u16 *fw_eng) | 867 | u16 *fw_rev, u16 *fw_eng) |
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 4d59d7e00e42..b326b15d5196 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c | |||
@@ -118,6 +118,22 @@ static int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos) | |||
118 | return edev->ops->iov->set_vlan(edev->cdev, vlan, vf); | 118 | return edev->ops->iov->set_vlan(edev->cdev, vlan, vf); |
119 | } | 119 | } |
120 | 120 | ||
121 | static int qede_set_vf_mac(struct net_device *ndev, int vfidx, u8 *mac) | ||
122 | { | ||
123 | struct qede_dev *edev = netdev_priv(ndev); | ||
124 | |||
125 | DP_VERBOSE(edev, QED_MSG_IOV, | ||
126 | "Setting MAC %02x:%02x:%02x:%02x:%02x:%02x to VF [%d]\n", | ||
127 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], vfidx); | ||
128 | |||
129 | if (!is_valid_ether_addr(mac)) { | ||
130 | DP_VERBOSE(edev, QED_MSG_IOV, "MAC address isn't valid\n"); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | return edev->ops->iov->set_mac(edev->cdev, mac, vfidx); | ||
135 | } | ||
136 | |||
121 | static int qede_sriov_configure(struct pci_dev *pdev, int num_vfs_param) | 137 | static int qede_sriov_configure(struct pci_dev *pdev, int num_vfs_param) |
122 | { | 138 | { |
123 | struct qede_dev *edev = netdev_priv(pci_get_drvdata(pdev)); | 139 | struct qede_dev *edev = netdev_priv(pci_get_drvdata(pdev)); |
@@ -138,10 +154,19 @@ static struct pci_driver qede_pci_driver = { | |||
138 | #endif | 154 | #endif |
139 | }; | 155 | }; |
140 | 156 | ||
157 | static void qede_force_mac(void *dev, u8 *mac) | ||
158 | { | ||
159 | struct qede_dev *edev = dev; | ||
160 | |||
161 | ether_addr_copy(edev->ndev->dev_addr, mac); | ||
162 | ether_addr_copy(edev->primary_mac, mac); | ||
163 | } | ||
164 | |||
141 | static struct qed_eth_cb_ops qede_ll_ops = { | 165 | static struct qed_eth_cb_ops qede_ll_ops = { |
142 | { | 166 | { |
143 | .link_update = qede_link_update, | 167 | .link_update = qede_link_update, |
144 | }, | 168 | }, |
169 | .force_mac = qede_force_mac, | ||
145 | }; | 170 | }; |
146 | 171 | ||
147 | static int qede_netdev_event(struct notifier_block *this, unsigned long event, | 172 | static int qede_netdev_event(struct notifier_block *this, unsigned long event, |
@@ -2087,6 +2112,7 @@ static const struct net_device_ops qede_netdev_ops = { | |||
2087 | .ndo_validate_addr = eth_validate_addr, | 2112 | .ndo_validate_addr = eth_validate_addr, |
2088 | .ndo_change_mtu = qede_change_mtu, | 2113 | .ndo_change_mtu = qede_change_mtu, |
2089 | #ifdef CONFIG_QED_SRIOV | 2114 | #ifdef CONFIG_QED_SRIOV |
2115 | .ndo_set_vf_mac = qede_set_vf_mac, | ||
2090 | .ndo_set_vf_vlan = qede_set_vf_vlan, | 2116 | .ndo_set_vf_vlan = qede_set_vf_vlan, |
2091 | #endif | 2117 | #endif |
2092 | .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, | 2118 | .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, |
@@ -3512,6 +3538,11 @@ static int qede_set_mac_addr(struct net_device *ndev, void *p) | |||
3512 | return -EFAULT; | 3538 | return -EFAULT; |
3513 | } | 3539 | } |
3514 | 3540 | ||
3541 | if (!edev->ops->check_mac(edev->cdev, addr->sa_data)) { | ||
3542 | DP_NOTICE(edev, "qed prevents setting MAC\n"); | ||
3543 | return -EINVAL; | ||
3544 | } | ||
3545 | |||
3515 | ether_addr_copy(ndev->dev_addr, addr->sa_data); | 3546 | ether_addr_copy(ndev->dev_addr, addr->sa_data); |
3516 | 3547 | ||
3517 | if (!netif_running(ndev)) { | 3548 | if (!netif_running(ndev)) { |
diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h index acfafca43aa5..e0f6e6482031 100644 --- a/include/linux/qed/qed_eth_if.h +++ b/include/linux/qed/qed_eth_if.h | |||
@@ -122,6 +122,7 @@ struct qed_tunn_params { | |||
122 | 122 | ||
123 | struct qed_eth_cb_ops { | 123 | struct qed_eth_cb_ops { |
124 | struct qed_common_cb_ops common; | 124 | struct qed_common_cb_ops common; |
125 | void (*force_mac) (void *dev, u8 *mac); | ||
125 | }; | 126 | }; |
126 | 127 | ||
127 | struct qed_eth_ops { | 128 | struct qed_eth_ops { |
@@ -137,6 +138,8 @@ struct qed_eth_ops { | |||
137 | struct qed_eth_cb_ops *ops, | 138 | struct qed_eth_cb_ops *ops, |
138 | void *cookie); | 139 | void *cookie); |
139 | 140 | ||
141 | bool(*check_mac) (struct qed_dev *cdev, u8 *mac); | ||
142 | |||
140 | int (*vport_start)(struct qed_dev *cdev, | 143 | int (*vport_start)(struct qed_dev *cdev, |
141 | struct qed_start_vport_params *params); | 144 | struct qed_start_vport_params *params); |
142 | 145 | ||
diff --git a/include/linux/qed/qed_iov_if.h b/include/linux/qed/qed_iov_if.h index 825c007d50f1..7a67fbf4336a 100644 --- a/include/linux/qed/qed_iov_if.h +++ b/include/linux/qed/qed_iov_if.h | |||
@@ -15,6 +15,8 @@ | |||
15 | struct qed_iov_hv_ops { | 15 | struct qed_iov_hv_ops { |
16 | int (*configure)(struct qed_dev *cdev, int num_vfs_param); | 16 | int (*configure)(struct qed_dev *cdev, int num_vfs_param); |
17 | 17 | ||
18 | int (*set_mac) (struct qed_dev *cdev, u8 *mac, int vfid); | ||
19 | |||
18 | int (*set_vlan) (struct qed_dev *cdev, u16 vid, int vfid); | 20 | int (*set_vlan) (struct qed_dev *cdev, u16 vid, int vfid); |
19 | }; | 21 | }; |
20 | 22 | ||