net: dsa: autoload tag driver module on tagging protocol change
authorVladimir Oltean <vladimir.oltean@nxp.com>
Tue, 15 Nov 2022 01:18:47 +0000 (03:18 +0200)
committerJakub Kicinski <kuba@kernel.org>
Fri, 18 Nov 2022 05:16:42 +0000 (21:16 -0800)
Issue a request_module() call when an attempt to change the tagging
protocol is made, either by sysfs or by device tree. In the case of
ocelot (the only driver for which the default and the alternative
tagging protocol are compiled as different modules), the user is now no
longer required to insert tag_ocelot_8021q.ko manually.

In the particular case of ocelot, this solves a problem where
tag_ocelot_8021q.ko is built as module, and this is present in the
device tree:

&mscc_felix_port4 {
dsa-tag-protocol = "ocelot-8021q";
};

&mscc_felix_port5 {
dsa-tag-protocol = "ocelot-8021q";
};

Because no one attempts to load the module into the kernel at boot time,
the switch driver will fail to probe (actually forever defer) until
someone manually inserts tag_ocelot_8021q.ko. This is now no longer
necessary and happens automatically.

Rename dsa_find_tagger_by_name() to denote the change in functionality:
there is now feature parity with dsa_tag_driver_get_by_id(), i.o.w. we
also load the module if it's missing.

Link: https://lore.kernel.org/lkml/20221027113248.420216-1-michael@walle.cc/
Suggested-by: Michael Walle <michael@walle.cc>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Michael Walle <michael@walle.cc> # on kontron-sl28 w/ ocelot_8021q
Tested-by: Michael Walle <michael@walle.cc>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/dsa/dsa.c
net/dsa/dsa2.c
net/dsa/dsa_priv.h
net/dsa/master.c

index 577765cfa9864ae7911c42a840036d64c3b512d8..4afd3edbd64d018b340ae588d34c225d6c852fb9 100644 (file)
@@ -79,11 +79,13 @@ const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops)
 /* Function takes a reference on the module owning the tagger,
  * so dsa_tag_driver_put must be called afterwards.
  */
-const struct dsa_device_ops *dsa_find_tagger_by_name(const char *name)
+const struct dsa_device_ops *dsa_tag_driver_get_by_name(const char *name)
 {
        const struct dsa_device_ops *ops = ERR_PTR(-ENOPROTOOPT);
        struct dsa_tag_driver *dsa_tag_driver;
 
+       request_module("%s%s", DSA_TAG_DRIVER_ALIAS, name);
+
        mutex_lock(&dsa_tag_drivers_lock);
        list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) {
                const struct dsa_device_ops *tmp = dsa_tag_driver->ops;
index 4b31b025887083f7fa2ae50b88d6d5a98bc8ba17..f8df55e2e23ad3f34f63883fe1b1963407f58870 100644 (file)
@@ -1431,7 +1431,7 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master,
                        return -EINVAL;
                }
 
-               tag_ops = dsa_find_tagger_by_name(user_protocol);
+               tag_ops = dsa_tag_driver_get_by_name(user_protocol);
                if (IS_ERR(tag_ops)) {
                        dev_warn(ds->dev,
                                 "Failed to find a tagging driver for protocol %s, using default\n",
index 0d33a22e3087c99e7734397d742008305c16ddf9..24e0ea218a35a3784f4d0c2230eba950347b48d4 100644 (file)
@@ -244,8 +244,8 @@ struct dsa_slave_priv {
 
 /* dsa.c */
 const struct dsa_device_ops *dsa_tag_driver_get_by_id(int tag_protocol);
+const struct dsa_device_ops *dsa_tag_driver_get_by_name(const char *name);
 void dsa_tag_driver_put(const struct dsa_device_ops *ops);
-const struct dsa_device_ops *dsa_find_tagger_by_name(const char *name);
 
 bool dsa_db_equal(const struct dsa_db *a, const struct dsa_db *b);
 
index f443bf4a3c8c110668a376b93d7a0b34da934055..e24f02743c2119f8fa0aed14b59db1a6298b3fec 100644 (file)
@@ -314,9 +314,9 @@ static ssize_t tagging_store(struct device *d, struct device_attribute *attr,
                return -ENOMEM;
 
        old_tag_ops = cpu_dp->tag_ops;
-       new_tag_ops = dsa_find_tagger_by_name(name);
+       new_tag_ops = dsa_tag_driver_get_by_name(name);
        kfree(name);
-       /* Bad tagger name, or module is not loaded? */
+       /* Bad tagger name? */
        if (IS_ERR(new_tag_ops))
                return PTR_ERR(new_tag_ops);