sfc: Associate primary and secondary functions of controller
The primary function of an EF10 controller will share its clock device with other functions in the same domain (which we call secondary functions). To this end, we need to associate functions on the same controller. We do not control probe order, so allow primary and secondary functions to appear in any order. Maintain global lists of all primary functions and of unassociated secondary functions, and a list of secondary functions on each primary function. Use the VPD serial number to tell whether functions are part of the same controller. VPD will not be readable by virtual functions, so this may need to be revisited later. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
@@ -1117,6 +1117,77 @@ static void efx_remove_port(struct efx_nic *efx)
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
static LIST_HEAD(efx_primary_list);
|
||||
static LIST_HEAD(efx_unassociated_list);
|
||||
|
||||
static bool efx_same_controller(struct efx_nic *left, struct efx_nic *right)
|
||||
{
|
||||
return left->type == right->type &&
|
||||
left->vpd_sn && right->vpd_sn &&
|
||||
!strcmp(left->vpd_sn, right->vpd_sn);
|
||||
}
|
||||
|
||||
static void efx_associate(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_nic *other, *next;
|
||||
|
||||
if (efx->primary == efx) {
|
||||
/* Adding primary function; look for secondaries */
|
||||
|
||||
netif_dbg(efx, probe, efx->net_dev, "adding to primary list\n");
|
||||
list_add_tail(&efx->node, &efx_primary_list);
|
||||
|
||||
list_for_each_entry_safe(other, next, &efx_unassociated_list,
|
||||
node) {
|
||||
if (efx_same_controller(efx, other)) {
|
||||
list_del(&other->node);
|
||||
netif_dbg(other, probe, other->net_dev,
|
||||
"moving to secondary list of %s %s\n",
|
||||
pci_name(efx->pci_dev),
|
||||
efx->net_dev->name);
|
||||
list_add_tail(&other->node,
|
||||
&efx->secondary_list);
|
||||
other->primary = efx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Adding secondary function; look for primary */
|
||||
|
||||
list_for_each_entry(other, &efx_primary_list, node) {
|
||||
if (efx_same_controller(efx, other)) {
|
||||
netif_dbg(efx, probe, efx->net_dev,
|
||||
"adding to secondary list of %s %s\n",
|
||||
pci_name(other->pci_dev),
|
||||
other->net_dev->name);
|
||||
list_add_tail(&efx->node,
|
||||
&other->secondary_list);
|
||||
efx->primary = other;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
netif_dbg(efx, probe, efx->net_dev,
|
||||
"adding to unassociated list\n");
|
||||
list_add_tail(&efx->node, &efx_unassociated_list);
|
||||
}
|
||||
}
|
||||
|
||||
static void efx_dissociate(struct efx_nic *efx)
|
||||
{
|
||||
struct efx_nic *other, *next;
|
||||
|
||||
list_del(&efx->node);
|
||||
efx->primary = NULL;
|
||||
|
||||
list_for_each_entry_safe(other, next, &efx->secondary_list, node) {
|
||||
list_del(&other->node);
|
||||
netif_dbg(other, probe, other->net_dev,
|
||||
"moving to unassociated list\n");
|
||||
list_add_tail(&other->node, &efx_unassociated_list);
|
||||
other->primary = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* This configures the PCI device to enable I/O and DMA. */
|
||||
static int efx_init_io(struct efx_nic *efx)
|
||||
{
|
||||
@@ -2214,6 +2285,8 @@ static int efx_register_netdev(struct efx_nic *efx)
|
||||
efx_init_tx_queue_core_txq(tx_queue);
|
||||
}
|
||||
|
||||
efx_associate(efx);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
|
||||
@@ -2227,6 +2300,7 @@ static int efx_register_netdev(struct efx_nic *efx)
|
||||
|
||||
fail_registered:
|
||||
rtnl_lock();
|
||||
efx_dissociate(efx);
|
||||
unregister_netdevice(net_dev);
|
||||
fail_locked:
|
||||
efx->state = STATE_UNINIT;
|
||||
@@ -2568,6 +2642,8 @@ static int efx_init_struct(struct efx_nic *efx,
|
||||
int i;
|
||||
|
||||
/* Initialise common structures */
|
||||
INIT_LIST_HEAD(&efx->node);
|
||||
INIT_LIST_HEAD(&efx->secondary_list);
|
||||
spin_lock_init(&efx->biu_lock);
|
||||
#ifdef CONFIG_SFC_MTD
|
||||
INIT_LIST_HEAD(&efx->mtd_list);
|
||||
@@ -2674,6 +2750,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
|
||||
|
||||
/* Mark the NIC as fini, then stop the interface */
|
||||
rtnl_lock();
|
||||
efx_dissociate(efx);
|
||||
dev_close(efx->net_dev);
|
||||
efx_disable_interrupts(efx);
|
||||
rtnl_unlock();
|
||||
|
Reference in New Issue
Block a user