Commit 2483223e authored by Jakub Kicinski's avatar Jakub Kicinski

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.usSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3406079b 61e4a516
...@@ -129,7 +129,9 @@ struct devlink_port { ...@@ -129,7 +129,9 @@ struct devlink_port {
void *type_dev; void *type_dev;
struct devlink_port_attrs attrs; struct devlink_port_attrs attrs;
u8 attrs_set:1, u8 attrs_set:1,
switch_port:1; switch_port:1,
registered:1,
initialized:1;
struct delayed_work type_warn_dw; struct delayed_work type_warn_dw;
struct list_head reporter_list; struct list_head reporter_list;
struct mutex reporters_lock; /* Protects reporter_list */ struct mutex reporters_lock; /* Protects reporter_list */
...@@ -1562,6 +1564,9 @@ void devlink_set_features(struct devlink *devlink, u64 features); ...@@ -1562,6 +1564,9 @@ void devlink_set_features(struct devlink *devlink, u64 features);
void devlink_register(struct devlink *devlink); void devlink_register(struct devlink *devlink);
void devlink_unregister(struct devlink *devlink); void devlink_unregister(struct devlink *devlink);
void devlink_free(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, int devl_port_register(struct devlink *devlink,
struct devlink_port *devlink_port, struct devlink_port *devlink_port,
unsigned int port_index); unsigned int port_index);
......
...@@ -294,8 +294,6 @@ struct dsa_port { ...@@ -294,8 +294,6 @@ struct dsa_port {
u8 lag_tx_enabled:1; u8 lag_tx_enabled:1;
u8 devlink_port_setup:1;
/* Master state bits, valid only on CPU ports */ /* Master state bits, valid only on CPU ports */
u8 master_admin_up:1; u8 master_admin_up:1;
u8 master_oper_up:1; u8 master_oper_up:1;
......
...@@ -371,6 +371,13 @@ static struct devlink *devlink_get_from_attrs(struct net *net, ...@@ -371,6 +371,13 @@ static struct devlink *devlink_get_from_attrs(struct net *net,
return ERR_PTR(-ENODEV); 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, static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
unsigned int port_index) unsigned int port_index)
{ {
...@@ -9847,6 +9854,44 @@ static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port) ...@@ -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); 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 * devl_port_register() - Register devlink port
* *
...@@ -9869,14 +9914,15 @@ int devl_port_register(struct devlink *devlink, ...@@ -9869,14 +9914,15 @@ int devl_port_register(struct devlink *devlink,
if (devlink_port_index_exists(devlink, port_index)) if (devlink_port_index_exists(devlink, port_index))
return -EEXIST; return -EEXIST;
WARN_ON(devlink_port->devlink); ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
devlink_port->devlink = devlink;
devlink_port_init(devlink, devlink_port);
devlink_port->registered = true;
devlink_port->index = port_index; devlink_port->index = port_index;
spin_lock_init(&devlink_port->type_lock); spin_lock_init(&devlink_port->type_lock);
INIT_LIST_HEAD(&devlink_port->reporter_list); INIT_LIST_HEAD(&devlink_port->reporter_list);
mutex_init(&devlink_port->reporters_lock); mutex_init(&devlink_port->reporters_lock);
list_add_tail(&devlink_port->list, &devlink->port_list); 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); INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
devlink_port_type_warn_schedule(devlink_port); devlink_port_type_warn_schedule(devlink_port);
...@@ -9926,8 +9972,8 @@ void devl_port_unregister(struct devlink_port *devlink_port) ...@@ -9926,8 +9972,8 @@ void devl_port_unregister(struct devlink_port *devlink_port)
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL); devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
list_del(&devlink_port->list); list_del(&devlink_port->list);
WARN_ON(!list_empty(&devlink_port->reporter_list)); WARN_ON(!list_empty(&devlink_port->reporter_list));
WARN_ON(!list_empty(&devlink_port->region_list));
mutex_destroy(&devlink_port->reporters_lock); mutex_destroy(&devlink_port->reporters_lock);
devlink_port->registered = false;
} }
EXPORT_SYMBOL_GPL(devl_port_unregister); EXPORT_SYMBOL_GPL(devl_port_unregister);
...@@ -9952,8 +9998,8 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port, ...@@ -9952,8 +9998,8 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
enum devlink_port_type type, enum devlink_port_type type,
void *type_dev) void *type_dev)
{ {
if (WARN_ON(!devlink_port->devlink)) ASSERT_DEVLINK_PORT_REGISTERED(devlink_port);
return;
devlink_port_type_warn_cancel(devlink_port); devlink_port_type_warn_cancel(devlink_port);
spin_lock_bh(&devlink_port->type_lock); spin_lock_bh(&devlink_port->type_lock);
devlink_port->type = type; devlink_port->type = type;
...@@ -10072,8 +10118,8 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port, ...@@ -10072,8 +10118,8 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port,
{ {
int ret; int ret;
if (WARN_ON(devlink_port->devlink)) ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
return;
devlink_port->attrs = *attrs; devlink_port->attrs = *attrs;
ret = __devlink_port_attrs_set(devlink_port, attrs->flavour); ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
if (ret) if (ret)
...@@ -10096,8 +10142,8 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro ...@@ -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; struct devlink_port_attrs *attrs = &devlink_port->attrs;
int ret; int ret;
if (WARN_ON(devlink_port->devlink)) ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
return;
ret = __devlink_port_attrs_set(devlink_port, ret = __devlink_port_attrs_set(devlink_port,
DEVLINK_PORT_FLAVOUR_PCI_PF); DEVLINK_PORT_FLAVOUR_PCI_PF);
if (ret) if (ret)
...@@ -10123,8 +10169,8 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro ...@@ -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; struct devlink_port_attrs *attrs = &devlink_port->attrs;
int ret; int ret;
if (WARN_ON(devlink_port->devlink)) ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
return;
ret = __devlink_port_attrs_set(devlink_port, ret = __devlink_port_attrs_set(devlink_port,
DEVLINK_PORT_FLAVOUR_PCI_VF); DEVLINK_PORT_FLAVOUR_PCI_VF);
if (ret) if (ret)
...@@ -10151,8 +10197,8 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 contro ...@@ -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; struct devlink_port_attrs *attrs = &devlink_port->attrs;
int ret; int ret;
if (WARN_ON(devlink_port->devlink)) ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
return;
ret = __devlink_port_attrs_set(devlink_port, ret = __devlink_port_attrs_set(devlink_port,
DEVLINK_PORT_FLAVOUR_PCI_SF); DEVLINK_PORT_FLAVOUR_PCI_SF);
if (ret) if (ret)
...@@ -10267,8 +10313,8 @@ EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy); ...@@ -10267,8 +10313,8 @@ EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy);
void devlink_port_linecard_set(struct devlink_port *devlink_port, void devlink_port_linecard_set(struct devlink_port *devlink_port,
struct devlink_linecard *linecard) struct devlink_linecard *linecard)
{ {
if (WARN_ON(devlink_port->devlink)) ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
return;
devlink_port->linecard = linecard; devlink_port->linecard = linecard;
} }
EXPORT_SYMBOL_GPL(devlink_port_linecard_set); EXPORT_SYMBOL_GPL(devlink_port_linecard_set);
...@@ -11339,6 +11385,8 @@ devlink_port_region_create(struct devlink_port *port, ...@@ -11339,6 +11385,8 @@ devlink_port_region_create(struct devlink_port *port,
struct devlink_region *region; struct devlink_region *region;
int err = 0; int err = 0;
ASSERT_DEVLINK_PORT_INITIALIZED(port);
if (WARN_ON(!ops) || WARN_ON(!ops->destructor)) if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
......
...@@ -461,6 +461,72 @@ static void dsa_tree_teardown_cpu_ports(struct dsa_switch_tree *dst) ...@@ -461,6 +461,72 @@ static void dsa_tree_teardown_cpu_ports(struct dsa_switch_tree *dst)
dp->cpu_dp = NULL; 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) static int dsa_port_setup(struct dsa_port *dp)
{ {
struct devlink_port *dlp = &dp->devlink_port; struct devlink_port *dlp = &dp->devlink_port;
...@@ -472,11 +538,9 @@ static int dsa_port_setup(struct dsa_port *dp) ...@@ -472,11 +538,9 @@ static int dsa_port_setup(struct dsa_port *dp)
if (dp->setup) if (dp->setup)
return 0; return 0;
if (ds->ops->port_setup) { err = dsa_port_devlink_setup(dp);
err = ds->ops->port_setup(ds, dp->index);
if (err) if (err)
return err; return err;
}
switch (dp->type) { switch (dp->type) {
case DSA_PORT_TYPE_UNUSED: case DSA_PORT_TYPE_UNUSED:
...@@ -533,8 +597,7 @@ static int dsa_port_setup(struct dsa_port *dp) ...@@ -533,8 +597,7 @@ static int dsa_port_setup(struct dsa_port *dp)
if (err && dsa_port_link_registered) if (err && dsa_port_link_registered)
dsa_shared_port_link_unregister_of(dp); dsa_shared_port_link_unregister_of(dp);
if (err) { if (err) {
if (ds->ops->port_teardown) dsa_port_devlink_teardown(dp);
ds->ops->port_teardown(ds, dp->index);
return err; return err;
} }
...@@ -543,59 +606,13 @@ static int dsa_port_setup(struct dsa_port *dp) ...@@ -543,59 +606,13 @@ static int dsa_port_setup(struct dsa_port *dp)
return 0; 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) static void dsa_port_teardown(struct dsa_port *dp)
{ {
struct devlink_port *dlp = &dp->devlink_port; struct devlink_port *dlp = &dp->devlink_port;
struct dsa_switch *ds = dp->ds;
if (!dp->setup) if (!dp->setup)
return; return;
if (ds->ops->port_teardown)
ds->ops->port_teardown(ds, dp->index);
devlink_port_type_clear(dlp); devlink_port_type_clear(dlp);
switch (dp->type) { switch (dp->type) {
...@@ -619,46 +636,15 @@ static void dsa_port_teardown(struct dsa_port *dp) ...@@ -619,46 +636,15 @@ static void dsa_port_teardown(struct dsa_port *dp)
break; break;
} }
dp->setup = false; dsa_port_devlink_teardown(dp);
}
static void dsa_port_devlink_teardown(struct dsa_port *dp)
{
struct devlink_port *dlp = &dp->devlink_port;
if (dp->devlink_port_setup) dp->setup = false;
devlink_port_unregister(dlp);
dp->devlink_port_setup = false;
} }
/* Destroy the current devlink port, and create a new one which has the UNUSED static int dsa_port_setup_as_unused(struct dsa_port *dp)
* 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; dp->type = DSA_PORT_TYPE_UNUSED;
err = dsa_port_devlink_setup(dp); return dsa_port_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;
} }
static int dsa_devlink_info_get(struct devlink *dl, static int dsa_devlink_info_get(struct devlink *dl,
...@@ -882,7 +868,6 @@ static int dsa_switch_setup(struct dsa_switch *ds) ...@@ -882,7 +868,6 @@ static int dsa_switch_setup(struct dsa_switch *ds)
{ {
struct dsa_devlink_priv *dl_priv; struct dsa_devlink_priv *dl_priv;
struct device_node *dn; struct device_node *dn;
struct dsa_port *dp;
int err; int err;
if (ds->setup) if (ds->setup)
...@@ -905,18 +890,9 @@ static int dsa_switch_setup(struct dsa_switch *ds) ...@@ -905,18 +890,9 @@ static int dsa_switch_setup(struct dsa_switch *ds)
dl_priv = devlink_priv(ds->devlink); dl_priv = devlink_priv(ds->devlink);
dl_priv->ds = ds; 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); err = dsa_switch_register_notifier(ds);
if (err) if (err)
goto unregister_devlink_ports; goto devlink_free;
ds->configure_vlan_while_not_filtering = true; ds->configure_vlan_while_not_filtering = true;
...@@ -957,9 +933,7 @@ static int dsa_switch_setup(struct dsa_switch *ds) ...@@ -957,9 +933,7 @@ static int dsa_switch_setup(struct dsa_switch *ds)
ds->ops->teardown(ds); ds->ops->teardown(ds);
unregister_notifier: unregister_notifier:
dsa_switch_unregister_notifier(ds); dsa_switch_unregister_notifier(ds);
unregister_devlink_ports: devlink_free:
dsa_switch_for_each_port(dp, ds)
dsa_port_devlink_teardown(dp);
devlink_free(ds->devlink); devlink_free(ds->devlink);
ds->devlink = NULL; ds->devlink = NULL;
return err; return err;
...@@ -967,8 +941,6 @@ static int dsa_switch_setup(struct dsa_switch *ds) ...@@ -967,8 +941,6 @@ static int dsa_switch_setup(struct dsa_switch *ds)
static void dsa_switch_teardown(struct dsa_switch *ds) static void dsa_switch_teardown(struct dsa_switch *ds)
{ {
struct dsa_port *dp;
if (!ds->setup) if (!ds->setup)
return; return;
...@@ -987,8 +959,6 @@ static void dsa_switch_teardown(struct dsa_switch *ds) ...@@ -987,8 +959,6 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
dsa_switch_unregister_notifier(ds); dsa_switch_unregister_notifier(ds);
if (ds->devlink) { if (ds->devlink) {
dsa_switch_for_each_port(dp, ds)
dsa_port_devlink_teardown(dp);
devlink_free(ds->devlink); devlink_free(ds->devlink);
ds->devlink = NULL; ds->devlink = NULL;
} }
...@@ -1041,7 +1011,7 @@ static int dsa_tree_setup_ports(struct dsa_switch_tree *dst) ...@@ -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)) { if (dsa_port_is_user(dp) || dsa_port_is_unused(dp)) {
err = dsa_port_setup(dp); err = dsa_port_setup(dp);
if (err) { if (err) {
err = dsa_port_reinit_as_unused(dp); err = dsa_port_setup_as_unused(dp);
if (err) if (err)
goto teardown; goto teardown;
} }
......
...@@ -294,6 +294,7 @@ int dsa_port_mrp_add_ring_role(const struct dsa_port *dp, ...@@ -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, int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
const struct switchdev_obj_ring_role_mrp *mrp); const struct switchdev_obj_ring_role_mrp *mrp);
int dsa_port_phylink_create(struct dsa_port *dp); 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); int dsa_shared_port_link_register_of(struct dsa_port *dp);
void dsa_shared_port_link_unregister_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); 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) ...@@ -1661,6 +1661,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
phy_interface_t mode; phy_interface_t mode;
struct phylink *pl;
int err; int err;
err = of_get_phy_mode(dp->dn, &mode); err = of_get_phy_mode(dp->dn, &mode);
...@@ -1677,16 +1678,24 @@ int dsa_port_phylink_create(struct dsa_port *dp) ...@@ -1677,16 +1678,24 @@ int dsa_port_phylink_create(struct dsa_port *dp)
if (ds->ops->phylink_get_caps) if (ds->ops->phylink_get_caps)
ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config);
dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
mode, &dsa_port_phylink_mac_ops); mode, &dsa_port_phylink_mac_ops);
if (IS_ERR(dp->pl)) { if (IS_ERR(pl)) {
pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->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; 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) static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
...@@ -1781,7 +1790,7 @@ static int dsa_shared_port_phylink_register(struct dsa_port *dp) ...@@ -1781,7 +1790,7 @@ static int dsa_shared_port_phylink_register(struct dsa_port *dp)
return 0; return 0;
err_phy_connect: err_phy_connect:
phylink_destroy(dp->pl); dsa_port_phylink_destroy(dp);
return err; return err;
} }
...@@ -1983,8 +1992,7 @@ void dsa_shared_port_link_unregister_of(struct dsa_port *dp) ...@@ -1983,8 +1992,7 @@ void dsa_shared_port_link_unregister_of(struct dsa_port *dp)
rtnl_lock(); rtnl_lock();
phylink_disconnect_phy(dp->pl); phylink_disconnect_phy(dp->pl);
rtnl_unlock(); rtnl_unlock();
phylink_destroy(dp->pl); dsa_port_phylink_destroy(dp);
dp->pl = NULL;
return; return;
} }
......
...@@ -2304,7 +2304,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev) ...@@ -2304,7 +2304,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
if (ret) { if (ret) {
netdev_err(slave_dev, "failed to connect to PHY: %pe\n", netdev_err(slave_dev, "failed to connect to PHY: %pe\n",
ERR_PTR(ret)); ERR_PTR(ret));
phylink_destroy(dp->pl); dsa_port_phylink_destroy(dp);
} }
return ret; return ret;
...@@ -2476,7 +2476,7 @@ int dsa_slave_create(struct dsa_port *port) ...@@ -2476,7 +2476,7 @@ int dsa_slave_create(struct dsa_port *port)
rtnl_lock(); rtnl_lock();
phylink_disconnect_phy(p->dp->pl); phylink_disconnect_phy(p->dp->pl);
rtnl_unlock(); rtnl_unlock();
phylink_destroy(p->dp->pl); dsa_port_phylink_destroy(p->dp);
out_gcells: out_gcells:
gro_cells_destroy(&p->gcells); gro_cells_destroy(&p->gcells);
out_free: out_free:
...@@ -2499,7 +2499,7 @@ void dsa_slave_destroy(struct net_device *slave_dev) ...@@ -2499,7 +2499,7 @@ void dsa_slave_destroy(struct net_device *slave_dev)
phylink_disconnect_phy(dp->pl); phylink_disconnect_phy(dp->pl);
rtnl_unlock(); rtnl_unlock();
phylink_destroy(dp->pl); dsa_port_phylink_destroy(dp);
gro_cells_destroy(&p->gcells); gro_cells_destroy(&p->gcells);
free_percpu(slave_dev->tstats); free_percpu(slave_dev->tstats);
free_netdev(slave_dev); free_netdev(slave_dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment