Skip to content

Commit 35a2443

Browse files
mpalczew96anguy11
authored andcommitted
iavf: Add waiting for response from PF in set mac
Make iavf_set_mac synchronous by waiting for a response from a PF. Without this iavf_set_mac is always returning success even though set_mac can be rejected by a PF. This ensures that when set_mac exits netdev MAC is updated. This is needed for sending ARPs with correct MAC after changing VF's MAC. This is also needed by bonding module. Signed-off-by: Sylwester Dziedziuch <[email protected]> Signed-off-by: Mateusz Palczewski <[email protected]> Tested-by: Konrad Jankowski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent c87c938 commit 35a2443

File tree

3 files changed

+174
-21
lines changed

3 files changed

+174
-21
lines changed

drivers/net/ethernet/intel/iavf/iavf.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ struct iavf_mac_filter {
146146
u8 remove:1; /* filter needs to be removed */
147147
u8 add:1; /* filter needs to be added */
148148
u8 is_primary:1; /* filter is a default VF MAC */
149-
u8 padding:4;
149+
u8 add_handled:1; /* received response for filter add */
150+
u8 padding:3;
150151
};
151152
};
152153

@@ -248,6 +249,7 @@ struct iavf_adapter {
248249
struct work_struct adminq_task;
249250
struct delayed_work client_task;
250251
wait_queue_head_t down_waitqueue;
252+
wait_queue_head_t vc_waitqueue;
251253
struct iavf_q_vector *q_vectors;
252254
struct list_head vlan_filter_list;
253255
struct list_head mac_filter_list;
@@ -292,6 +294,7 @@ struct iavf_adapter {
292294
#define IAVF_FLAG_QUEUES_DISABLED BIT(17)
293295
#define IAVF_FLAG_SETUP_NETDEV_FEATURES BIT(18)
294296
#define IAVF_FLAG_REINIT_MSIX_NEEDED BIT(20)
297+
#define IAVF_FLAG_INITIAL_MAC_SET BIT(23)
295298
/* duplicates for common code */
296299
#define IAVF_FLAG_DCB_ENABLED 0
297300
/* flags for admin queue service task */
@@ -559,6 +562,8 @@ void iavf_enable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
559562
void iavf_disable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
560563
void iavf_enable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
561564
void iavf_disable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
565+
int iavf_replace_primary_mac(struct iavf_adapter *adapter,
566+
const u8 *new_mac);
562567
void
563568
iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
564569
netdev_features_t prev_features,

drivers/net/ethernet/intel/iavf/iavf_main.c

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,7 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
983983

984984
list_add_tail(&f->list, &adapter->mac_filter_list);
985985
f->add = true;
986+
f->add_handled = false;
986987
f->is_new_mac = true;
987988
f->is_primary = false;
988989
adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
@@ -994,47 +995,132 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
994995
}
995996

996997
/**
997-
* iavf_set_mac - NDO callback to set port mac address
998-
* @netdev: network interface device structure
999-
* @p: pointer to an address structure
998+
* iavf_replace_primary_mac - Replace current primary address
999+
* @adapter: board private structure
1000+
* @new_mac: new MAC address to be applied
10001001
*
1001-
* Returns 0 on success, negative on failure
1002+
* Replace current dev_addr and send request to PF for removal of previous
1003+
* primary MAC address filter and addition of new primary MAC filter.
1004+
* Return 0 for success, -ENOMEM for failure.
1005+
*
1006+
* Do not call this with mac_vlan_list_lock!
10021007
**/
1003-
static int iavf_set_mac(struct net_device *netdev, void *p)
1008+
int iavf_replace_primary_mac(struct iavf_adapter *adapter,
1009+
const u8 *new_mac)
10041010
{
1005-
struct iavf_adapter *adapter = netdev_priv(netdev);
10061011
struct iavf_hw *hw = &adapter->hw;
10071012
struct iavf_mac_filter *f;
1008-
struct sockaddr *addr = p;
1009-
1010-
if (!is_valid_ether_addr(addr->sa_data))
1011-
return -EADDRNOTAVAIL;
1012-
1013-
if (ether_addr_equal(netdev->dev_addr, addr->sa_data))
1014-
return 0;
10151013

10161014
spin_lock_bh(&adapter->mac_vlan_list_lock);
10171015

1016+
list_for_each_entry(f, &adapter->mac_filter_list, list) {
1017+
f->is_primary = false;
1018+
}
1019+
10181020
f = iavf_find_filter(adapter, hw->mac.addr);
10191021
if (f) {
10201022
f->remove = true;
1021-
f->is_primary = true;
10221023
adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
10231024
}
10241025

1025-
f = iavf_add_filter(adapter, addr->sa_data);
1026+
f = iavf_add_filter(adapter, new_mac);
1027+
10261028
if (f) {
1029+
/* Always send the request to add if changing primary MAC
1030+
* even if filter is already present on the list
1031+
*/
10271032
f->is_primary = true;
1028-
ether_addr_copy(hw->mac.addr, addr->sa_data);
1033+
f->add = true;
1034+
adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
1035+
ether_addr_copy(hw->mac.addr, new_mac);
10291036
}
10301037

10311038
spin_unlock_bh(&adapter->mac_vlan_list_lock);
10321039

10331040
/* schedule the watchdog task to immediately process the request */
1034-
if (f)
1041+
if (f) {
10351042
queue_work(iavf_wq, &adapter->watchdog_task.work);
1043+
return 0;
1044+
}
1045+
return -ENOMEM;
1046+
}
1047+
1048+
/**
1049+
* iavf_is_mac_set_handled - wait for a response to set MAC from PF
1050+
* @netdev: network interface device structure
1051+
* @macaddr: MAC address to set
1052+
*
1053+
* Returns true on success, false on failure
1054+
*/
1055+
static bool iavf_is_mac_set_handled(struct net_device *netdev,
1056+
const u8 *macaddr)
1057+
{
1058+
struct iavf_adapter *adapter = netdev_priv(netdev);
1059+
struct iavf_mac_filter *f;
1060+
bool ret = false;
1061+
1062+
spin_lock_bh(&adapter->mac_vlan_list_lock);
1063+
1064+
f = iavf_find_filter(adapter, macaddr);
1065+
1066+
if (!f || (!f->add && f->add_handled))
1067+
ret = true;
1068+
1069+
spin_unlock_bh(&adapter->mac_vlan_list_lock);
1070+
1071+
return ret;
1072+
}
1073+
1074+
/**
1075+
* iavf_set_mac - NDO callback to set port MAC address
1076+
* @netdev: network interface device structure
1077+
* @p: pointer to an address structure
1078+
*
1079+
* Returns 0 on success, negative on failure
1080+
*/
1081+
static int iavf_set_mac(struct net_device *netdev, void *p)
1082+
{
1083+
struct iavf_adapter *adapter = netdev_priv(netdev);
1084+
struct sockaddr *addr = p;
1085+
bool handle_mac = iavf_is_mac_set_handled(netdev, addr->sa_data);
1086+
int ret;
10361087

1037-
return (f == NULL) ? -ENOMEM : 0;
1088+
if (!is_valid_ether_addr(addr->sa_data))
1089+
return -EADDRNOTAVAIL;
1090+
1091+
ret = iavf_replace_primary_mac(adapter, addr->sa_data);
1092+
1093+
if (ret)
1094+
return ret;
1095+
1096+
/* If this is an initial set MAC during VF spawn do not wait */
1097+
if (adapter->flags & IAVF_FLAG_INITIAL_MAC_SET) {
1098+
adapter->flags &= ~IAVF_FLAG_INITIAL_MAC_SET;
1099+
return 0;
1100+
}
1101+
1102+
if (handle_mac)
1103+
goto done;
1104+
1105+
ret = wait_event_interruptible_timeout(adapter->vc_waitqueue, false, msecs_to_jiffies(2500));
1106+
1107+
/* If ret < 0 then it means wait was interrupted.
1108+
* If ret == 0 then it means we got a timeout.
1109+
* else it means we got response for set MAC from PF,
1110+
* check if netdev MAC was updated to requested MAC,
1111+
* if yes then set MAC succeeded otherwise it failed return -EACCES
1112+
*/
1113+
if (ret < 0)
1114+
return ret;
1115+
1116+
if (!ret)
1117+
return -EAGAIN;
1118+
1119+
done:
1120+
if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
1121+
return -EACCES;
1122+
1123+
return 0;
10381124
}
10391125

10401126
/**
@@ -2451,6 +2537,8 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
24512537
ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
24522538
}
24532539

2540+
adapter->flags |= IAVF_FLAG_INITIAL_MAC_SET;
2541+
24542542
adapter->tx_desc_count = IAVF_DEFAULT_TXD;
24552543
adapter->rx_desc_count = IAVF_DEFAULT_RXD;
24562544
err = iavf_init_interrupt_scheme(adapter);
@@ -4681,6 +4769,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
46814769
/* Setup the wait queue for indicating transition to down status */
46824770
init_waitqueue_head(&adapter->down_waitqueue);
46834771

4772+
/* Setup the wait queue for indicating virtchannel events */
4773+
init_waitqueue_head(&adapter->vc_waitqueue);
4774+
46844775
return 0;
46854776

46864777
err_ioremap:

drivers/net/ethernet/intel/iavf/iavf_virtchnl.c

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,8 @@ static void iavf_mac_add_ok(struct iavf_adapter *adapter)
598598
spin_lock_bh(&adapter->mac_vlan_list_lock);
599599
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
600600
f->is_new_mac = false;
601+
if (!f->add && !f->add_handled)
602+
f->add_handled = true;
601603
}
602604
spin_unlock_bh(&adapter->mac_vlan_list_lock);
603605
}
@@ -618,6 +620,9 @@ static void iavf_mac_add_reject(struct iavf_adapter *adapter)
618620
if (f->remove && ether_addr_equal(f->macaddr, netdev->dev_addr))
619621
f->remove = false;
620622

623+
if (!f->add && !f->add_handled)
624+
f->add_handled = true;
625+
621626
if (f->is_new_mac) {
622627
list_del(&f->list);
623628
kfree(f);
@@ -1932,6 +1937,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
19321937
iavf_mac_add_reject(adapter);
19331938
/* restore administratively set MAC address */
19341939
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
1940+
wake_up(&adapter->vc_waitqueue);
19351941
break;
19361942
case VIRTCHNL_OP_DEL_VLAN:
19371943
dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
@@ -2091,7 +2097,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
20912097
if (!v_retval)
20922098
iavf_mac_add_ok(adapter);
20932099
if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr))
2094-
eth_hw_addr_set(netdev, adapter->hw.mac.addr);
2100+
if (!ether_addr_equal(netdev->dev_addr,
2101+
adapter->hw.mac.addr)) {
2102+
netif_addr_lock_bh(netdev);
2103+
eth_hw_addr_set(netdev, adapter->hw.mac.addr);
2104+
netif_addr_unlock_bh(netdev);
2105+
}
2106+
wake_up(&adapter->vc_waitqueue);
20952107
break;
20962108
case VIRTCHNL_OP_GET_STATS: {
20972109
struct iavf_eth_stats *stats =
@@ -2121,10 +2133,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
21212133
/* restore current mac address */
21222134
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
21232135
} else {
2136+
netif_addr_lock_bh(netdev);
21242137
/* refresh current mac address if changed */
2125-
eth_hw_addr_set(netdev, adapter->hw.mac.addr);
21262138
ether_addr_copy(netdev->perm_addr,
21272139
adapter->hw.mac.addr);
2140+
netif_addr_unlock_bh(netdev);
21282141
}
21292142
spin_lock_bh(&adapter->mac_vlan_list_lock);
21302143
iavf_add_filter(adapter, adapter->hw.mac.addr);
@@ -2160,13 +2173,57 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
21602173
}
21612174
fallthrough;
21622175
case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS: {
2176+
struct iavf_mac_filter *f;
2177+
bool was_mac_changed;
2178+
u64 aq_required = 0;
2179+
21632180
if (v_opcode == VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS)
21642181
memcpy(&adapter->vlan_v2_caps, msg,
21652182
min_t(u16, msglen,
21662183
sizeof(adapter->vlan_v2_caps)));
21672184

21682185
iavf_process_config(adapter);
21692186
adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
2187+
was_mac_changed = !ether_addr_equal(netdev->dev_addr,
2188+
adapter->hw.mac.addr);
2189+
2190+
spin_lock_bh(&adapter->mac_vlan_list_lock);
2191+
2192+
/* re-add all MAC filters */
2193+
list_for_each_entry(f, &adapter->mac_filter_list, list) {
2194+
if (was_mac_changed &&
2195+
ether_addr_equal(netdev->dev_addr, f->macaddr))
2196+
ether_addr_copy(f->macaddr,
2197+
adapter->hw.mac.addr);
2198+
2199+
f->is_new_mac = true;
2200+
f->add = true;
2201+
f->add_handled = false;
2202+
f->remove = false;
2203+
}
2204+
2205+
/* re-add all VLAN filters */
2206+
if (VLAN_FILTERING_ALLOWED(adapter)) {
2207+
struct iavf_vlan_filter *vlf;
2208+
2209+
if (!list_empty(&adapter->vlan_filter_list)) {
2210+
list_for_each_entry(vlf,
2211+
&adapter->vlan_filter_list,
2212+
list)
2213+
vlf->add = true;
2214+
2215+
aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
2216+
}
2217+
}
2218+
2219+
spin_unlock_bh(&adapter->mac_vlan_list_lock);
2220+
2221+
netif_addr_lock_bh(netdev);
2222+
eth_hw_addr_set(netdev, adapter->hw.mac.addr);
2223+
netif_addr_unlock_bh(netdev);
2224+
2225+
adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER |
2226+
aq_required;
21702227
}
21712228
break;
21722229
case VIRTCHNL_OP_ENABLE_QUEUES:

0 commit comments

Comments
 (0)