From: Luiz Angelo Daros de Luca <luizluca@gmail.com>
To: netdev@vger.kernel.org
Cc: linus.walleij@linaro.org, alsi@bang-olufsen.dk, andrew@lunn.ch,
vivien.didelot@gmail.com, f.fainelli@gmail.com,
olteanv@gmail.com, davem@davemloft.net, kuba@kernel.org,
pabeni@redhat.com, robh+dt@kernel.org, krzk+dt@kernel.org,
arinc.unal@arinc9.com,
Luiz Angelo Daros de Luca <luizluca@gmail.com>
Subject: [RFC net-next 4/5] net: dsa: realtek: load switch variants on demand
Date: Sat, 11 Nov 2023 18:51:07 -0300 [thread overview]
Message-ID: <20231111215647.4966-5-luizluca@gmail.com> (raw)
In-Reply-To: <20231111215647.4966-1-luizluca@gmail.com>
realtek-common had a hard dependency on both switch variants. That way,
it was not possible to selectively load only one model at runtime. Now
variants are registered at the realtek-common module and interface
modules look for a variant using the compatible string.
Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
---
drivers/net/dsa/realtek/realtek-common.c | 125 ++++++++++++++++++++---
drivers/net/dsa/realtek/realtek-common.h | 3 +
drivers/net/dsa/realtek/realtek-mdio.c | 9 +-
drivers/net/dsa/realtek/realtek-smi.c | 9 +-
drivers/net/dsa/realtek/realtek.h | 36 ++++++-
drivers/net/dsa/realtek/rtl8365mb.c | 4 +-
drivers/net/dsa/realtek/rtl8366rb.c | 4 +-
7 files changed, 162 insertions(+), 28 deletions(-)
diff --git a/drivers/net/dsa/realtek/realtek-common.c b/drivers/net/dsa/realtek/realtek-common.c
index 36f8b60771be..e383db21c776 100644
--- a/drivers/net/dsa/realtek/realtek-common.c
+++ b/drivers/net/dsa/realtek/realtek-common.c
@@ -1,10 +1,76 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/module.h>
+#include <linux/of_device.h>
#include "realtek.h"
#include "realtek-common.h"
+static LIST_HEAD(realtek_variants_list);
+static DEFINE_MUTEX(realtek_variants_lock);
+
+void realtek_variant_register(struct realtek_variant_entry *var_ent)
+{
+ mutex_lock(&realtek_variants_lock);
+ list_add_tail(&var_ent->list, &realtek_variants_list);
+ mutex_unlock(&realtek_variants_lock);
+}
+EXPORT_SYMBOL_GPL(realtek_variant_register);
+
+void realtek_variant_unregister(struct realtek_variant_entry *var_ent)
+{
+ mutex_lock(&realtek_variants_lock);
+ list_del(&var_ent->list);
+ mutex_unlock(&realtek_variants_lock);
+}
+EXPORT_SYMBOL_GPL(realtek_variant_unregister);
+
+const struct realtek_variant *realtek_variant_get(
+ const struct of_device_id *match)
+{
+ const struct realtek_variant *var = ERR_PTR(-ENOENT);
+ struct realtek_variant_entry *var_ent;
+ const char *modname = match->data;
+
+ request_module(modname);
+
+ mutex_lock(&realtek_variants_lock);
+ list_for_each_entry(var_ent, &realtek_variants_list, list) {
+ const struct realtek_variant *tmp = var_ent->variant;
+
+ if (strcmp(match->compatible, var_ent->compatible))
+ continue;
+
+ if (!try_module_get(var_ent->owner))
+ break;
+
+ var = tmp;
+ break;
+ }
+ mutex_unlock(&realtek_variants_lock);
+
+ return var;
+}
+EXPORT_SYMBOL_GPL(realtek_variant_get);
+
+void realtek_variant_put(const struct realtek_variant *var)
+{
+ struct realtek_variant_entry *var_ent;
+
+ mutex_lock(&realtek_variants_lock);
+ list_for_each_entry(var_ent, &realtek_variants_list, list) {
+ if (var_ent->variant != var)
+ continue;
+
+ if (var_ent->owner)
+ module_put(var_ent->owner);
+
+ break;
+ }
+ mutex_unlock(&realtek_variants_lock);
+}
+EXPORT_SYMBOL_GPL(realtek_variant_put);
+
void realtek_common_lock(void *ctx)
{
struct realtek_priv *priv = ctx;
@@ -25,18 +91,30 @@ struct realtek_priv *realtek_common_probe(struct device *dev,
struct regmap_config rc, struct regmap_config rc_nolock)
{
const struct realtek_variant *var;
+ const struct of_device_id *match;
struct realtek_priv *priv;
struct device_node *np;
int ret;
- var = of_device_get_match_data(dev);
- if (!var)
+ match = of_match_device(dev->driver->of_match_table, dev);
+ if (!match || !match->data)
return ERR_PTR(-EINVAL);
+ var = realtek_variant_get(match);
+ if (IS_ERR(var)) {
+ ret = PTR_ERR(var);
+ dev_err_probe(dev, ret,
+ "failed to get module for '%s'. Is '%s' loaded?",
+ match->compatible, match->data);
+ goto err_variant_put;
+ }
+
priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz),
GFP_KERNEL);
- if (!priv)
- return ERR_PTR(-ENOMEM);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto err_variant_put;
+ }
mutex_init(&priv->map_lock);
@@ -45,14 +123,14 @@ struct realtek_priv *realtek_common_probe(struct device *dev,
if (IS_ERR(priv->map)) {
ret = PTR_ERR(priv->map);
dev_err(dev, "regmap init failed: %d\n", ret);
- return ERR_PTR(ret);
+ goto err_variant_put;
}
priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc_nolock);
if (IS_ERR(priv->map_nolock)) {
ret = PTR_ERR(priv->map_nolock);
dev_err(dev, "regmap init failed: %d\n", ret);
- return ERR_PTR(ret);
+ goto err_variant_put;
}
/* Link forward and backward */
@@ -69,23 +147,27 @@ struct realtek_priv *realtek_common_probe(struct device *dev,
/* Fetch MDIO pins */
priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW);
- if (IS_ERR(priv->mdc))
- return ERR_CAST(priv->mdc);
+
+ if (IS_ERR(priv->mdc)) {
+ ret = PTR_ERR(priv->mdc);
+ goto err_variant_put;
+ }
priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW);
- if (IS_ERR(priv->mdio))
- return ERR_CAST(priv->mdio);
+ if (IS_ERR(priv->mdio)) {
+ ret = PTR_ERR(priv->mdio);
+ goto err_variant_put;
+ }
np = dev->of_node;
-
priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds");
/* TODO: if power is software controlled, set up any regulators here */
-
priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(priv->reset)) {
+ ret = PTR_ERR(priv->reset);
dev_err(dev, "failed to get RESET GPIO\n");
- return ERR_CAST(priv->reset);
+ goto err_variant_put;
}
if (priv->reset) {
gpiod_set_value(priv->reset, 1);
@@ -97,13 +179,20 @@ struct realtek_priv *realtek_common_probe(struct device *dev,
}
priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
- if (!priv->ds)
- return ERR_PTR(-ENOMEM);
+ if (!priv->ds) {
+ ret = -ENOMEM;
+ goto err_variant_put;
+ }
priv->ds->dev = dev;
priv->ds->priv = priv;
return priv;
+
+err_variant_put:
+ realtek_variant_put(var);
+
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL(realtek_common_probe);
@@ -116,6 +205,8 @@ void realtek_common_remove(struct realtek_priv *priv)
if (priv->user_mii_bus)
of_node_put(priv->user_mii_bus->dev.of_node);
+ realtek_variant_put(priv->variant);
+
/* leave the device reset asserted */
if (priv->reset)
gpiod_set_value(priv->reset, 1);
@@ -124,10 +215,10 @@ EXPORT_SYMBOL(realtek_common_remove);
const struct of_device_id realtek_common_of_match[] = {
#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB)
- { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, },
+ { .compatible = "realtek,rtl8366rb", .data = REALTEK_RTL8366RB_MODNAME, },
#endif
#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB)
- { .compatible = "realtek,rtl8365mb", .data = &rtl8366rb_variant, },
+ { .compatible = "realtek,rtl8365mb", .data = REALTEK_RTL8365MB_MODNAME, },
#endif
{ /* sentinel */ },
};
diff --git a/drivers/net/dsa/realtek/realtek-common.h b/drivers/net/dsa/realtek/realtek-common.h
index 90a949386518..089fda2d4fa9 100644
--- a/drivers/net/dsa/realtek/realtek-common.h
+++ b/drivers/net/dsa/realtek/realtek-common.h
@@ -12,5 +12,8 @@ void realtek_common_unlock(void *ctx);
struct realtek_priv *realtek_common_probe(struct device *dev,
struct regmap_config rc, struct regmap_config rc_nolock);
void realtek_common_remove(struct realtek_priv *priv);
+const struct realtek_variant *realtek_variant_get(
+ const struct of_device_id *match);
+void realtek_variant_put(const struct realtek_variant *var);
#endif
diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c
index 6f610386c977..6d81cd88dbe6 100644
--- a/drivers/net/dsa/realtek/realtek-mdio.c
+++ b/drivers/net/dsa/realtek/realtek-mdio.c
@@ -146,7 +146,7 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev)
ret = priv->ops->detect(priv);
if (ret) {
dev_err(dev, "unable to detect switch\n");
- return ret;
+ goto err_variant_put;
}
priv->ds->num_ports = priv->num_ports;
@@ -155,10 +155,15 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev)
if (ret) {
dev_err_probe(dev, ret, "unable to register switch ret = %pe\n",
ERR_PTR(ret));
- return ret;
+ goto err_variant_put;
}
return 0;
+
+err_variant_put:
+ realtek_variant_put(priv->variant);
+
+ return ret;
}
static void realtek_mdio_remove(struct mdio_device *mdiodev)
diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c
index 0cf89f9db99e..a772bb7dbe35 100644
--- a/drivers/net/dsa/realtek/realtek-smi.c
+++ b/drivers/net/dsa/realtek/realtek-smi.c
@@ -413,7 +413,7 @@ static int realtek_smi_probe(struct platform_device *pdev)
ret = priv->ops->detect(priv);
if (ret) {
dev_err(dev, "unable to detect switch\n");
- return ret;
+ goto err_variant_put;
}
priv->ds->num_ports = priv->num_ports;
@@ -422,10 +422,15 @@ static int realtek_smi_probe(struct platform_device *pdev)
if (ret) {
dev_err_probe(dev, ret, "unable to register switch ret = %pe\n",
ERR_PTR(ret));
- return ret;
+ goto err_variant_put;
}
return 0;
+
+err_variant_put:
+ realtek_variant_put(priv->variant);
+
+ return ret;
}
static void realtek_smi_remove(struct platform_device *pdev)
diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h
index 8d9d546bf5f5..f9bd6678e3bd 100644
--- a/drivers/net/dsa/realtek/realtek.h
+++ b/drivers/net/dsa/realtek/realtek.h
@@ -16,6 +16,38 @@
#define REALTEK_HW_STOP_DELAY 25 /* msecs */
#define REALTEK_HW_START_DELAY 100 /* msecs */
+#define REALTEK_RTL8365MB_MODNAME "rtl8365mb"
+#define REALTEK_RTL8366RB_MODNAME "rtl8366"
+
+struct realtek_variant_entry {
+ const struct realtek_variant *variant;
+ const char *compatible;
+ struct module *owner;
+ struct list_head list;
+};
+
+#define module_realtek_variant(__variant, __compatible) \
+static struct realtek_variant_entry __variant ## _entry = { \
+ .compatible = __compatible, \
+ .variant = &(__variant), \
+ .owner = THIS_MODULE, \
+}; \
+static int __init realtek_variant_module_init(void) \
+{ \
+ realtek_variant_register(&__variant ## _entry); \
+ return 0; \
+} \
+module_init(realtek_variant_module_init) \
+ \
+static void __exit realtek_variant_module_exit(void) \
+{ \
+ realtek_variant_unregister(&__variant ## _entry); \
+} \
+module_exit(realtek_variant_module_exit)
+
+void realtek_variant_register(struct realtek_variant_entry *var_ent);
+void realtek_variant_unregister(struct realtek_variant_entry *var_ent);
+
struct realtek_ops;
struct dentry;
struct inode;
@@ -120,6 +152,7 @@ struct realtek_ops {
struct realtek_variant {
const struct dsa_switch_ops *ds_ops_smi;
const struct dsa_switch_ops *ds_ops_mdio;
+ const struct realtek_variant_info *info;
const struct realtek_ops *ops;
unsigned int clk_delay;
u8 cmd_read;
@@ -146,7 +179,4 @@ void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset);
void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
-extern const struct realtek_variant rtl8366rb_variant;
-extern const struct realtek_variant rtl8365mb_variant;
-
#endif /* _REALTEK_H */
diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
index 0875e4fc9f57..b5b22a4d01eb 100644
--- a/drivers/net/dsa/realtek/rtl8365mb.c
+++ b/drivers/net/dsa/realtek/rtl8365mb.c
@@ -2163,7 +2163,7 @@ static const struct realtek_ops rtl8365mb_ops = {
.phy_write = rtl8365mb_phy_write,
};
-const struct realtek_variant rtl8365mb_variant = {
+static const struct realtek_variant rtl8365mb_variant = {
.ds_ops_smi = &rtl8365mb_switch_ops_smi,
.ds_ops_mdio = &rtl8365mb_switch_ops_mdio,
.ops = &rtl8365mb_ops,
@@ -2172,7 +2172,7 @@ const struct realtek_variant rtl8365mb_variant = {
.cmd_write = 0xb8,
.chip_data_sz = sizeof(struct rtl8365mb),
};
-EXPORT_SYMBOL_GPL(rtl8365mb_variant);
+module_realtek_variant(rtl8365mb_variant, "realtek,rtl8365mb");
MODULE_AUTHOR("Alvin Šipraga <alsi@bang-olufsen.dk>");
MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch");
diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c
index b39b719a5b8f..208a8f17a089 100644
--- a/drivers/net/dsa/realtek/rtl8366rb.c
+++ b/drivers/net/dsa/realtek/rtl8366rb.c
@@ -1911,7 +1911,7 @@ static const struct realtek_ops rtl8366rb_ops = {
.phy_write = rtl8366rb_phy_write,
};
-const struct realtek_variant rtl8366rb_variant = {
+static const struct realtek_variant rtl8366rb_variant = {
.ds_ops_smi = &rtl8366rb_switch_ops_smi,
.ds_ops_mdio = &rtl8366rb_switch_ops_mdio,
.ops = &rtl8366rb_ops,
@@ -1920,7 +1920,7 @@ const struct realtek_variant rtl8366rb_variant = {
.cmd_write = 0xa8,
.chip_data_sz = sizeof(struct rtl8366rb),
};
-EXPORT_SYMBOL_GPL(rtl8366rb_variant);
+module_realtek_variant(rtl8366rb_variant, "realtek,rtl8366rb");
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch");
--
2.42.1
next prev parent reply other threads:[~2023-11-11 21:57 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-11 21:51 [RFC net-next 0/5] refactor realtek switches and add reset controller Luiz Angelo Daros de Luca
2023-11-11 21:51 ` [RFC net-next 1/5] dt-bindings: net: dsa: realtek: reset-gpios is not required Luiz Angelo Daros de Luca
2023-11-12 7:37 ` Krzysztof Kozlowski
2023-11-13 20:30 ` Luiz Angelo Daros de Luca
2023-11-13 8:31 ` Linus Walleij
2023-11-14 12:23 ` Alvin Šipraga
2023-11-11 21:51 ` [RFC net-next 2/5] dt-bindings: net: dsa: realtek: add reset controller Luiz Angelo Daros de Luca
2023-11-13 8:31 ` Linus Walleij
2023-11-14 12:23 ` Alvin Šipraga
2023-11-16 16:25 ` Rob Herring
2023-11-11 21:51 ` [RFC net-next 3/5] net: dsa: realtek: create realtek-common Luiz Angelo Daros de Luca
2023-11-12 7:39 ` Krzysztof Kozlowski
2023-11-13 8:35 ` Linus Walleij
2023-11-13 20:41 ` Luiz Angelo Daros de Luca
2023-11-13 22:01 ` Alvin Šipraga
2023-11-14 11:43 ` Alvin Šipraga
2023-11-17 23:04 ` Luiz Angelo Daros de Luca
2023-11-11 21:51 ` Luiz Angelo Daros de Luca [this message]
2023-11-12 3:54 ` [RFC net-next 4/5] net: dsa: realtek: load switch variants on demand kernel test robot
2023-11-14 12:17 ` Alvin Šipraga
2023-11-17 21:14 ` Luiz Angelo Daros de Luca
2023-11-11 21:51 ` [RFC net-next 5/5] net: dsa: realtek: support reset controller Luiz Angelo Daros de Luca
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231111215647.4966-5-luizluca@gmail.com \
--to=luizluca@gmail.com \
--cc=alsi@bang-olufsen.dk \
--cc=andrew@lunn.ch \
--cc=arinc.unal@arinc9.com \
--cc=davem@davemloft.net \
--cc=f.fainelli@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linus.walleij@linaro.org \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
--cc=robh+dt@kernel.org \
--cc=vivien.didelot@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.