Merge branch 'devlink-sanitize-per-port-region-creation-destruction'
Jiri Pirko says: ==================== devlink: sanitize per-port region creation/destruction Currently the only user of per-port devlink regions is DSA. All drivers that use regions register them before devlink registration. For DSA, this was not possible as the internals of struct devlink_port needed for region creation are initialized during port registration. This introduced a mismatch in creation flow of devlink and devlink port regions. As you can see, it causes the DSA driver to make the port init/exit flow a bit cumbersome. Fix this by introducing port_init/fini() which could be optionally called by drivers like DSA, to prepare struct devlink_port to be used for region creation purposes before devlink port register is called. Tested by Vladimir on his setup. ==================== Link: https://lore.kernel.org/r/20220929072902.2986539-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
2483223e19
|
@ -129,7 +129,9 @@ struct devlink_port {
|
|||
void *type_dev;
|
||||
struct devlink_port_attrs attrs;
|
||||
u8 attrs_set:1,
|
||||
switch_port:1;
|
||||
switch_port:1,
|
||||
registered:1,
|
||||
initialized:1;
|
||||
struct delayed_work type_warn_dw;
|
||||
struct list_head reporter_list;
|
||||
struct mutex reporters_lock; /* Protects reporter_list */
|
||||
|
@ -1562,6 +1564,9 @@ void devlink_set_features(struct devlink *devlink, u64 features);
|
|||
void devlink_register(struct devlink *devlink);
|
||||
void devlink_unregister(struct devlink *devlink);
|
||||
void devlink_free(struct devlink *devlink);
|
||||
void devlink_port_init(struct devlink *devlink,
|
||||
struct devlink_port *devlink_port);
|
||||
void devlink_port_fini(struct devlink_port *devlink_port);
|
||||
int devl_port_register(struct devlink *devlink,
|
||||
struct devlink_port *devlink_port,
|
||||
unsigned int port_index);
|
||||
|
|
|
@ -294,8 +294,6 @@ struct dsa_port {
|
|||
|
||||
u8 lag_tx_enabled:1;
|
||||
|
||||
u8 devlink_port_setup:1;
|
||||
|
||||
/* Master state bits, valid only on CPU ports */
|
||||
u8 master_admin_up:1;
|
||||
u8 master_oper_up:1;
|
||||
|
|
|
@ -371,6 +371,13 @@ static struct devlink *devlink_get_from_attrs(struct net *net,
|
|||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
#define ASSERT_DEVLINK_PORT_REGISTERED(devlink_port) \
|
||||
WARN_ON_ONCE(!(devlink_port)->registered)
|
||||
#define ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port) \
|
||||
WARN_ON_ONCE((devlink_port)->registered)
|
||||
#define ASSERT_DEVLINK_PORT_INITIALIZED(devlink_port) \
|
||||
WARN_ON_ONCE(!(devlink_port)->initialized)
|
||||
|
||||
static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
|
||||
unsigned int port_index)
|
||||
{
|
||||
|
@ -9847,6 +9854,44 @@ static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
|
|||
cancel_delayed_work_sync(&devlink_port->type_warn_dw);
|
||||
}
|
||||
|
||||
/**
|
||||
* devlink_port_init() - Init devlink port
|
||||
*
|
||||
* @devlink: devlink
|
||||
* @devlink_port: devlink port
|
||||
*
|
||||
* Initialize essencial stuff that is needed for functions
|
||||
* that may be called before devlink port registration.
|
||||
* Call to this function is optional and not needed
|
||||
* in case the driver does not use such functions.
|
||||
*/
|
||||
void devlink_port_init(struct devlink *devlink,
|
||||
struct devlink_port *devlink_port)
|
||||
{
|
||||
if (devlink_port->initialized)
|
||||
return;
|
||||
devlink_port->devlink = devlink;
|
||||
INIT_LIST_HEAD(&devlink_port->region_list);
|
||||
devlink_port->initialized = true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_port_init);
|
||||
|
||||
/**
|
||||
* devlink_port_fini() - Deinitialize devlink port
|
||||
*
|
||||
* @devlink_port: devlink port
|
||||
*
|
||||
* Deinitialize essencial stuff that is in use for functions
|
||||
* that may be called after devlink port unregistration.
|
||||
* Call to this function is optional and not needed
|
||||
* in case the driver does not use such functions.
|
||||
*/
|
||||
void devlink_port_fini(struct devlink_port *devlink_port)
|
||||
{
|
||||
WARN_ON(!list_empty(&devlink_port->region_list));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_port_fini);
|
||||
|
||||
/**
|
||||
* devl_port_register() - Register devlink port
|
||||
*
|
||||
|
@ -9869,14 +9914,15 @@ int devl_port_register(struct devlink *devlink,
|
|||
if (devlink_port_index_exists(devlink, port_index))
|
||||
return -EEXIST;
|
||||
|
||||
WARN_ON(devlink_port->devlink);
|
||||
devlink_port->devlink = devlink;
|
||||
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
||||
|
||||
devlink_port_init(devlink, devlink_port);
|
||||
devlink_port->registered = true;
|
||||
devlink_port->index = port_index;
|
||||
spin_lock_init(&devlink_port->type_lock);
|
||||
INIT_LIST_HEAD(&devlink_port->reporter_list);
|
||||
mutex_init(&devlink_port->reporters_lock);
|
||||
list_add_tail(&devlink_port->list, &devlink->port_list);
|
||||
INIT_LIST_HEAD(&devlink_port->region_list);
|
||||
|
||||
INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
|
||||
devlink_port_type_warn_schedule(devlink_port);
|
||||
|
@ -9926,8 +9972,8 @@ void devl_port_unregister(struct devlink_port *devlink_port)
|
|||
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
|
||||
list_del(&devlink_port->list);
|
||||
WARN_ON(!list_empty(&devlink_port->reporter_list));
|
||||
WARN_ON(!list_empty(&devlink_port->region_list));
|
||||
mutex_destroy(&devlink_port->reporters_lock);
|
||||
devlink_port->registered = false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devl_port_unregister);
|
||||
|
||||
|
@ -9952,8 +9998,8 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
|
|||
enum devlink_port_type type,
|
||||
void *type_dev)
|
||||
{
|
||||
if (WARN_ON(!devlink_port->devlink))
|
||||
return;
|
||||
ASSERT_DEVLINK_PORT_REGISTERED(devlink_port);
|
||||
|
||||
devlink_port_type_warn_cancel(devlink_port);
|
||||
spin_lock_bh(&devlink_port->type_lock);
|
||||
devlink_port->type = type;
|
||||
|
@ -10072,8 +10118,8 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port,
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(devlink_port->devlink))
|
||||
return;
|
||||
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
||||
|
||||
devlink_port->attrs = *attrs;
|
||||
ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
|
||||
if (ret)
|
||||
|
@ -10096,8 +10142,8 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro
|
|||
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(devlink_port->devlink))
|
||||
return;
|
||||
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
||||
|
||||
ret = __devlink_port_attrs_set(devlink_port,
|
||||
DEVLINK_PORT_FLAVOUR_PCI_PF);
|
||||
if (ret)
|
||||
|
@ -10123,8 +10169,8 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro
|
|||
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(devlink_port->devlink))
|
||||
return;
|
||||
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
||||
|
||||
ret = __devlink_port_attrs_set(devlink_port,
|
||||
DEVLINK_PORT_FLAVOUR_PCI_VF);
|
||||
if (ret)
|
||||
|
@ -10151,8 +10197,8 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 contro
|
|||
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(devlink_port->devlink))
|
||||
return;
|
||||
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
||||
|
||||
ret = __devlink_port_attrs_set(devlink_port,
|
||||
DEVLINK_PORT_FLAVOUR_PCI_SF);
|
||||
if (ret)
|
||||
|
@ -10267,8 +10313,8 @@ EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy);
|
|||
void devlink_port_linecard_set(struct devlink_port *devlink_port,
|
||||
struct devlink_linecard *linecard)
|
||||
{
|
||||
if (WARN_ON(devlink_port->devlink))
|
||||
return;
|
||||
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
||||
|
||||
devlink_port->linecard = linecard;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_port_linecard_set);
|
||||
|
@ -11339,6 +11385,8 @@ devlink_port_region_create(struct devlink_port *port,
|
|||
struct devlink_region *region;
|
||||
int err = 0;
|
||||
|
||||
ASSERT_DEVLINK_PORT_INITIALIZED(port);
|
||||
|
||||
if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
|
|
184
net/dsa/dsa2.c
184
net/dsa/dsa2.c
|
@ -461,6 +461,72 @@ static void dsa_tree_teardown_cpu_ports(struct dsa_switch_tree *dst)
|
|||
dp->cpu_dp = NULL;
|
||||
}
|
||||
|
||||
static int dsa_port_devlink_setup(struct dsa_port *dp)
|
||||
{
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
struct dsa_switch_tree *dst = dp->ds->dst;
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink *dl = dp->ds->devlink;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
const unsigned char *id;
|
||||
unsigned char len;
|
||||
int err;
|
||||
|
||||
memset(dlp, 0, sizeof(*dlp));
|
||||
devlink_port_init(dl, dlp);
|
||||
|
||||
if (ds->ops->port_setup) {
|
||||
err = ds->ops->port_setup(ds, dp->index);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
id = (const unsigned char *)&dst->index;
|
||||
len = sizeof(dst->index);
|
||||
|
||||
attrs.phys.port_number = dp->index;
|
||||
memcpy(attrs.switch_id.id, id, len);
|
||||
attrs.switch_id.id_len = len;
|
||||
|
||||
switch (dp->type) {
|
||||
case DSA_PORT_TYPE_UNUSED:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
|
||||
break;
|
||||
case DSA_PORT_TYPE_CPU:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_CPU;
|
||||
break;
|
||||
case DSA_PORT_TYPE_DSA:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_DSA;
|
||||
break;
|
||||
case DSA_PORT_TYPE_USER:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
|
||||
break;
|
||||
}
|
||||
|
||||
devlink_port_attrs_set(dlp, &attrs);
|
||||
err = devlink_port_register(dl, dlp, dp->index);
|
||||
if (err) {
|
||||
if (ds->ops->port_teardown)
|
||||
ds->ops->port_teardown(ds, dp->index);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsa_port_devlink_teardown(struct dsa_port *dp)
|
||||
{
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
|
||||
devlink_port_unregister(dlp);
|
||||
|
||||
if (ds->ops->port_teardown)
|
||||
ds->ops->port_teardown(ds, dp->index);
|
||||
|
||||
devlink_port_fini(dlp);
|
||||
}
|
||||
|
||||
static int dsa_port_setup(struct dsa_port *dp)
|
||||
{
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
|
@ -472,11 +538,9 @@ static int dsa_port_setup(struct dsa_port *dp)
|
|||
if (dp->setup)
|
||||
return 0;
|
||||
|
||||
if (ds->ops->port_setup) {
|
||||
err = ds->ops->port_setup(ds, dp->index);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = dsa_port_devlink_setup(dp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (dp->type) {
|
||||
case DSA_PORT_TYPE_UNUSED:
|
||||
|
@ -533,8 +597,7 @@ static int dsa_port_setup(struct dsa_port *dp)
|
|||
if (err && dsa_port_link_registered)
|
||||
dsa_shared_port_link_unregister_of(dp);
|
||||
if (err) {
|
||||
if (ds->ops->port_teardown)
|
||||
ds->ops->port_teardown(ds, dp->index);
|
||||
dsa_port_devlink_teardown(dp);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -543,59 +606,13 @@ static int dsa_port_setup(struct dsa_port *dp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dsa_port_devlink_setup(struct dsa_port *dp)
|
||||
{
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
struct dsa_switch_tree *dst = dp->ds->dst;
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink *dl = dp->ds->devlink;
|
||||
const unsigned char *id;
|
||||
unsigned char len;
|
||||
int err;
|
||||
|
||||
id = (const unsigned char *)&dst->index;
|
||||
len = sizeof(dst->index);
|
||||
|
||||
attrs.phys.port_number = dp->index;
|
||||
memcpy(attrs.switch_id.id, id, len);
|
||||
attrs.switch_id.id_len = len;
|
||||
memset(dlp, 0, sizeof(*dlp));
|
||||
|
||||
switch (dp->type) {
|
||||
case DSA_PORT_TYPE_UNUSED:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED;
|
||||
break;
|
||||
case DSA_PORT_TYPE_CPU:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_CPU;
|
||||
break;
|
||||
case DSA_PORT_TYPE_DSA:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_DSA;
|
||||
break;
|
||||
case DSA_PORT_TYPE_USER:
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
|
||||
break;
|
||||
}
|
||||
|
||||
devlink_port_attrs_set(dlp, &attrs);
|
||||
err = devlink_port_register(dl, dlp, dp->index);
|
||||
|
||||
if (!err)
|
||||
dp->devlink_port_setup = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dsa_port_teardown(struct dsa_port *dp)
|
||||
{
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
|
||||
if (!dp->setup)
|
||||
return;
|
||||
|
||||
if (ds->ops->port_teardown)
|
||||
ds->ops->port_teardown(ds, dp->index);
|
||||
|
||||
devlink_port_type_clear(dlp);
|
||||
|
||||
switch (dp->type) {
|
||||
|
@ -619,46 +636,15 @@ static void dsa_port_teardown(struct dsa_port *dp)
|
|||
break;
|
||||
}
|
||||
|
||||
dsa_port_devlink_teardown(dp);
|
||||
|
||||
dp->setup = false;
|
||||
}
|
||||
|
||||
static void dsa_port_devlink_teardown(struct dsa_port *dp)
|
||||
static int dsa_port_setup_as_unused(struct dsa_port *dp)
|
||||
{
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
|
||||
if (dp->devlink_port_setup)
|
||||
devlink_port_unregister(dlp);
|
||||
dp->devlink_port_setup = false;
|
||||
}
|
||||
|
||||
/* Destroy the current devlink port, and create a new one which has the UNUSED
|
||||
* flavour. At this point, any call to ds->ops->port_setup has been already
|
||||
* balanced out by a call to ds->ops->port_teardown, so we know that any
|
||||
* devlink port regions the driver had are now unregistered. We then call its
|
||||
* ds->ops->port_setup again, in order for the driver to re-create them on the
|
||||
* new devlink port.
|
||||
*/
|
||||
static int dsa_port_reinit_as_unused(struct dsa_port *dp)
|
||||
{
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
int err;
|
||||
|
||||
dsa_port_devlink_teardown(dp);
|
||||
dp->type = DSA_PORT_TYPE_UNUSED;
|
||||
err = dsa_port_devlink_setup(dp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ds->ops->port_setup) {
|
||||
/* On error, leave the devlink port registered,
|
||||
* dsa_switch_teardown will clean it up later.
|
||||
*/
|
||||
err = ds->ops->port_setup(ds, dp->index);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return dsa_port_setup(dp);
|
||||
}
|
||||
|
||||
static int dsa_devlink_info_get(struct devlink *dl,
|
||||
|
@ -882,7 +868,6 @@ static int dsa_switch_setup(struct dsa_switch *ds)
|
|||
{
|
||||
struct dsa_devlink_priv *dl_priv;
|
||||
struct device_node *dn;
|
||||
struct dsa_port *dp;
|
||||
int err;
|
||||
|
||||
if (ds->setup)
|
||||
|
@ -905,18 +890,9 @@ static int dsa_switch_setup(struct dsa_switch *ds)
|
|||
dl_priv = devlink_priv(ds->devlink);
|
||||
dl_priv->ds = ds;
|
||||
|
||||
/* Setup devlink port instances now, so that the switch
|
||||
* setup() can register regions etc, against the ports
|
||||
*/
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
err = dsa_port_devlink_setup(dp);
|
||||
if (err)
|
||||
goto unregister_devlink_ports;
|
||||
}
|
||||
|
||||
err = dsa_switch_register_notifier(ds);
|
||||
if (err)
|
||||
goto unregister_devlink_ports;
|
||||
goto devlink_free;
|
||||
|
||||
ds->configure_vlan_while_not_filtering = true;
|
||||
|
||||
|
@ -957,9 +933,7 @@ teardown:
|
|||
ds->ops->teardown(ds);
|
||||
unregister_notifier:
|
||||
dsa_switch_unregister_notifier(ds);
|
||||
unregister_devlink_ports:
|
||||
dsa_switch_for_each_port(dp, ds)
|
||||
dsa_port_devlink_teardown(dp);
|
||||
devlink_free:
|
||||
devlink_free(ds->devlink);
|
||||
ds->devlink = NULL;
|
||||
return err;
|
||||
|
@ -967,8 +941,6 @@ unregister_devlink_ports:
|
|||
|
||||
static void dsa_switch_teardown(struct dsa_switch *ds)
|
||||
{
|
||||
struct dsa_port *dp;
|
||||
|
||||
if (!ds->setup)
|
||||
return;
|
||||
|
||||
|
@ -987,8 +959,6 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
|
|||
dsa_switch_unregister_notifier(ds);
|
||||
|
||||
if (ds->devlink) {
|
||||
dsa_switch_for_each_port(dp, ds)
|
||||
dsa_port_devlink_teardown(dp);
|
||||
devlink_free(ds->devlink);
|
||||
ds->devlink = NULL;
|
||||
}
|
||||
|
@ -1041,7 +1011,7 @@ static int dsa_tree_setup_ports(struct dsa_switch_tree *dst)
|
|||
if (dsa_port_is_user(dp) || dsa_port_is_unused(dp)) {
|
||||
err = dsa_port_setup(dp);
|
||||
if (err) {
|
||||
err = dsa_port_reinit_as_unused(dp);
|
||||
err = dsa_port_setup_as_unused(dp);
|
||||
if (err)
|
||||
goto teardown;
|
||||
}
|
||||
|
|
|
@ -294,6 +294,7 @@ int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
|
|||
int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
|
||||
const struct switchdev_obj_ring_role_mrp *mrp);
|
||||
int dsa_port_phylink_create(struct dsa_port *dp);
|
||||
void dsa_port_phylink_destroy(struct dsa_port *dp);
|
||||
int dsa_shared_port_link_register_of(struct dsa_port *dp);
|
||||
void dsa_shared_port_link_unregister_of(struct dsa_port *dp);
|
||||
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
|
||||
|
|
|
@ -1661,6 +1661,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
|
|||
{
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
phy_interface_t mode;
|
||||
struct phylink *pl;
|
||||
int err;
|
||||
|
||||
err = of_get_phy_mode(dp->dn, &mode);
|
||||
|
@ -1677,16 +1678,24 @@ int dsa_port_phylink_create(struct dsa_port *dp)
|
|||
if (ds->ops->phylink_get_caps)
|
||||
ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config);
|
||||
|
||||
dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
|
||||
mode, &dsa_port_phylink_mac_ops);
|
||||
if (IS_ERR(dp->pl)) {
|
||||
pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
|
||||
mode, &dsa_port_phylink_mac_ops);
|
||||
if (IS_ERR(pl)) {
|
||||
pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
|
||||
return PTR_ERR(dp->pl);
|
||||
return PTR_ERR(pl);
|
||||
}
|
||||
|
||||
dp->pl = pl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dsa_port_phylink_destroy(struct dsa_port *dp)
|
||||
{
|
||||
phylink_destroy(dp->pl);
|
||||
dp->pl = NULL;
|
||||
}
|
||||
|
||||
static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable)
|
||||
{
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
|
@ -1781,7 +1790,7 @@ static int dsa_shared_port_phylink_register(struct dsa_port *dp)
|
|||
return 0;
|
||||
|
||||
err_phy_connect:
|
||||
phylink_destroy(dp->pl);
|
||||
dsa_port_phylink_destroy(dp);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1983,8 +1992,7 @@ void dsa_shared_port_link_unregister_of(struct dsa_port *dp)
|
|||
rtnl_lock();
|
||||
phylink_disconnect_phy(dp->pl);
|
||||
rtnl_unlock();
|
||||
phylink_destroy(dp->pl);
|
||||
dp->pl = NULL;
|
||||
dsa_port_phylink_destroy(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2304,7 +2304,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
|
|||
if (ret) {
|
||||
netdev_err(slave_dev, "failed to connect to PHY: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
phylink_destroy(dp->pl);
|
||||
dsa_port_phylink_destroy(dp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -2476,7 +2476,7 @@ out_phy:
|
|||
rtnl_lock();
|
||||
phylink_disconnect_phy(p->dp->pl);
|
||||
rtnl_unlock();
|
||||
phylink_destroy(p->dp->pl);
|
||||
dsa_port_phylink_destroy(p->dp);
|
||||
out_gcells:
|
||||
gro_cells_destroy(&p->gcells);
|
||||
out_free:
|
||||
|
@ -2499,7 +2499,7 @@ void dsa_slave_destroy(struct net_device *slave_dev)
|
|||
phylink_disconnect_phy(dp->pl);
|
||||
rtnl_unlock();
|
||||
|
||||
phylink_destroy(dp->pl);
|
||||
dsa_port_phylink_destroy(dp);
|
||||
gro_cells_destroy(&p->gcells);
|
||||
free_percpu(slave_dev->tstats);
|
||||
free_netdev(slave_dev);
|
||||
|
|
Loading…
Reference in New Issue