Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sfc: save old MAC address in case sriov_mac_address_changed fails

Otherwise the PF and VF can disagree on the VF's MAC address and
this leads to strange behaviour, up to and including kernel panics.

Signed-off-by: Shradha Shah <sshah@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Shradha Shah and committed by
David S. Miller
cfc77c2f 88a37de6

+21 -7
+4 -1
drivers/net/ethernet/sfc/ef10_sriov.h
··· 31 31 32 32 int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs); 33 33 int efx_ef10_sriov_init(struct efx_nic *efx); 34 - static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {} 34 + static inline int efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) 35 + { 36 + return -EOPNOTSUPP; 37 + } 35 38 static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {} 36 39 void efx_ef10_sriov_fini(struct efx_nic *efx); 37 40 static inline void efx_ef10_sriov_flr(struct efx_nic *efx, unsigned vf_i) {}
+11 -2
drivers/net/ethernet/sfc/efx.c
··· 2196 2196 struct efx_nic *efx = netdev_priv(net_dev); 2197 2197 struct sockaddr *addr = data; 2198 2198 u8 *new_addr = addr->sa_data; 2199 + u8 old_addr[6]; 2200 + int rc; 2199 2201 2200 2202 if (!is_valid_ether_addr(new_addr)) { 2201 2203 netif_err(efx, drv, efx->net_dev, ··· 2206 2204 return -EADDRNOTAVAIL; 2207 2205 } 2208 2206 2207 + /* save old address */ 2208 + ether_addr_copy(old_addr, net_dev->dev_addr); 2209 2209 ether_addr_copy(net_dev->dev_addr, new_addr); 2210 - if (efx->type->sriov_mac_address_changed) 2211 - efx->type->sriov_mac_address_changed(efx); 2210 + if (efx->type->sriov_mac_address_changed) { 2211 + rc = efx->type->sriov_mac_address_changed(efx); 2212 + if (rc) { 2213 + ether_addr_copy(net_dev->dev_addr, old_addr); 2214 + return rc; 2215 + } 2216 + } 2212 2217 2213 2218 /* Reconfigure the MAC */ 2214 2219 mutex_lock(&efx->mac_lock);
+1 -1
drivers/net/ethernet/sfc/net_driver.h
··· 1334 1334 int (*sriov_configure)(struct efx_nic *efx, int num_vfs); 1335 1335 int (*sriov_init)(struct efx_nic *efx); 1336 1336 void (*sriov_fini)(struct efx_nic *efx); 1337 - void (*sriov_mac_address_changed)(struct efx_nic *efx); 1337 + int (*sriov_mac_address_changed)(struct efx_nic *efx); 1338 1338 bool (*sriov_wanted)(struct efx_nic *efx); 1339 1339 void (*sriov_reset)(struct efx_nic *efx); 1340 1340 void (*sriov_flr)(struct efx_nic *efx, unsigned vf_i);
+4 -2
drivers/net/ethernet/sfc/siena_sriov.c
··· 1476 1476 vf->evq0_count = 0; 1477 1477 } 1478 1478 1479 - void efx_siena_sriov_mac_address_changed(struct efx_nic *efx) 1479 + int efx_siena_sriov_mac_address_changed(struct efx_nic *efx) 1480 1480 { 1481 1481 struct siena_nic_data *nic_data = efx->nic_data; 1482 1482 struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr; 1483 1483 1484 1484 if (!efx->vf_init_count) 1485 - return; 1485 + return 0; 1486 1486 ether_addr_copy(vfdi_status->peers[0].mac_addr, 1487 1487 efx->net_dev->dev_addr); 1488 1488 queue_work(vfdi_workqueue, &nic_data->peer_work); 1489 + 1490 + return 0; 1489 1491 } 1490 1492 1491 1493 void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
+1 -1
drivers/net/ethernet/sfc/siena_sriov.h
··· 44 44 int efx_siena_sriov_configure(struct efx_nic *efx, int num_vfs); 45 45 int efx_siena_sriov_init(struct efx_nic *efx); 46 46 void efx_siena_sriov_fini(struct efx_nic *efx); 47 - void efx_siena_sriov_mac_address_changed(struct efx_nic *efx); 47 + int efx_siena_sriov_mac_address_changed(struct efx_nic *efx); 48 48 bool efx_siena_sriov_wanted(struct efx_nic *efx); 49 49 void efx_siena_sriov_reset(struct efx_nic *efx); 50 50 void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr);