@@ -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
46864777err_ioremap :
0 commit comments