int mib_next_port;
u64 *mib_stats;
+ struct list_head list;
+ unsigned int use_count;
+
/* all fields below are cleared on reset */
bool vlan;
u16 vlan_id[AR8X16_MAX_VLANS];
MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"),
};
+static DEFINE_MUTEX(ar8xxx_dev_list_lock);
+static LIST_HEAD(ar8xxx_dev_list);
+
static inline struct ar8216_priv *
swdev_to_ar8216(struct switch_dev *swdev)
{
struct switch_dev *swdev;
int ret;
- if (!priv) {
- priv = ar8xxx_create_mii(phydev->bus);
- if (priv == NULL)
- return -ENOMEM;
-
- ret = ar8xxx_probe_switch(priv);
- if (ret)
- goto err_free_priv;
- }
+ if (WARN_ON(!priv))
+ return -ENODEV;
priv->phy = phydev;
if (chip_is_ar8316(priv)) {
/* check if we're attaching to the switch twice */
phydev = phydev->bus->phy_map[0];
- if (!phydev) {
- ar8xxx_free(priv);
+ if (!phydev)
return 0;
- }
/* switch device has not been initialized, reuse priv */
if (!phydev->priv) {
priv->port4_phy = true;
priv->dev.ports = (AR8216_NUM_PORTS - 1);
- phydev->priv = priv;
return 0;
}
- ar8xxx_free(priv);
-
/* switch device has been initialized, reinit */
- priv = phydev->priv;
priv->dev.ports = (AR8216_NUM_PORTS - 1);
priv->initialized = false;
priv->port4_phy = true;
return 0;
}
- ar8xxx_free(priv);
return 0;
}
- phydev->priv = priv;
-
swdev = &priv->dev;
ret = register_switch(swdev, phydev->attached_dev);
if (ret)
- goto err_free_priv;
+ goto err;
pr_info("%s: %s switch driver attached.\n",
phydev->attached_dev->name, swdev->name);
err_unregister_switch:
unregister_switch(&priv->dev);
-err_free_priv:
- ar8xxx_free(priv);
- phydev->priv = NULL;
+err:
return ret;
}
if (!ar8xxx_is_possible(phydev->bus))
return -ENODEV;
- priv = ar8xxx_create_mii(phydev->bus);
- if (priv == NULL)
- return -ENOMEM;
+ mutex_lock(&ar8xxx_dev_list_lock);
+ list_for_each_entry(priv, &ar8xxx_dev_list, list)
+ if (priv->mii_bus == phydev->bus)
+ goto found;
- priv->phy = phydev;
+ priv = ar8xxx_create_mii(phydev->bus);
+ if (priv == NULL) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
ret = ar8xxx_probe_switch(priv);
if (ret)
- goto out;
+ goto free_priv;
+found:
if (phydev->addr == 0) {
if (ar8xxx_has_gige(priv)) {
phydev->supported = SUPPORTED_1000baseT_Full;
}
}
- ret = 0;
+ phydev->priv = priv;
+ priv->use_count++;
-out:
+ list_add(&priv->list, &ar8xxx_dev_list);
+
+ mutex_unlock(&ar8xxx_dev_list_lock);
+
+ return 0;
+
+free_priv:
ar8xxx_free(priv);
+unlock:
+ mutex_unlock(&ar8xxx_dev_list_lock);
return ret;
}
{
struct ar8216_priv *priv = phydev->priv;
- if (!priv)
+ if (WARN_ON(!priv))
return;
phydev->priv = NULL;
+ if (--priv->use_count > 0)
+ return;
- if (phydev->addr == 0)
- unregister_switch(&priv->dev);
+ mutex_lock(&ar8xxx_dev_list_lock);
+ list_del(&priv->list);
+ mutex_unlock(&ar8xxx_dev_list_lock);
+ unregister_switch(&priv->dev);
ar8xxx_mib_stop(priv);
ar8xxx_free(priv);
}