|
@@ -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();
|