[PATCH net-next v2 05/11] net: pcs: lynx: Convert to an MDIO driver
From: Sean Anderson <hidden>
Date: 2022-11-03 21:07:35
Also in:
lkml
Subsystem:
ethernet phy library, lynx pcs module, networking drivers, the rest · Maintainers:
Andrew Lunn, Heiner Kallweit, Ioana Ciornei, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
This partially converts the lynx PCS driver to a proper MDIO driver. This allows using a more conventional driver lifecycle (e.g. with a probe and remove). For compatibility with existing drivers, we retain the old lynx_pcs_create/destroy functions. This may result in two "drivers" attached to the same device (one real driver, and one attached with lynx_pcs_create). However, this should not cause problems because consumers will only use one or the other. To assist in conversion of existing drivers to the PCS API, we provide a lynx_pcs_create_on_bus function which will create an MDIO device on a bus, bind our driver, and get the PCS. This should make it easy to convert drivers which do not use devicetree. Because this driver may be a direct child of its consumers (especially when created with lynx_pcs_create_on_bus), we set suppress_bind_attrs. This prevents userspace from causing a segfault by removing the PCS before the consumer. Signed-off-by: Sean Anderson <redacted> --- Changes in v2: - Call mdio_device_register - Squash in lynx parts of "use pcs_get_by_provider to get PCS" - Rewrite probe/remove functions to use create/destroy. This lets us convert existing drivers one at a time, instead of needing a flag day. drivers/net/pcs/Kconfig | 11 +++-- drivers/net/pcs/pcs-lynx.c | 83 +++++++++++++++++++++++++++++++++++--- include/linux/pcs-lynx.h | 7 +++- 3 files changed, 91 insertions(+), 10 deletions(-)
diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig
index 8d70fc52a803..5e169e87db74 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig@@ -25,10 +25,15 @@ config PCS_XPCS controllers. config PCS_LYNX - tristate + tristate "NXP Lynx PCS driver" + depends on PCS && MDIO_DEVICE help - This module provides helpers to phylink for managing the Lynx PCS - which is part of the Layerscape and QorIQ Ethernet SERDES. + This module provides driver support for the PCSs in Lynx 10g and 28g + SerDes devices. These devices are present in NXP QorIQ SoCs, + including the Layerscape series. + + If you want to use Ethernet on a QorIQ SoC, say "Y". If compiled as a + module, it will be called "pcs-lynx". config PCS_RZN1_MIIC tristate "Renesas RZ/N1 MII converter"
diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c
index 7d5fc7f54b2f..3ea402049ef1 100644
--- a/drivers/net/pcs/pcs-lynx.c
+++ b/drivers/net/pcs/pcs-lynx.c@@ -1,11 +1,14 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -/* Copyright 2020 NXP +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2022 Sean Anderson <seanga2@gmail.com> + * Copyright 2020 NXP * Lynx PCS MDIO helpers */ #include <linux/mdio.h> -#include <linux/phylink.h> +#include <linux/of.h> +#include <linux/pcs.h> #include <linux/pcs-lynx.h> +#include <linux/phylink.h> #define SGMII_CLOCK_PERIOD_NS 8 /* PCS is clocked at 125 MHz */ #define LINK_TIMER_VAL(ns) ((u32)((ns) / SGMII_CLOCK_PERIOD_NS))
@@ -333,7 +336,26 @@ struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) return lynx_to_phylink_pcs(lynx); } -EXPORT_SYMBOL(lynx_pcs_create); +EXPORT_SYMBOL_GPL(lynx_pcs_create); + +static int lynx_pcs_probe(struct mdio_device *mdio) +{ + struct device *dev = &mdio->dev; + struct phylink_pcs *pcs; + int ret; + + pcs = lynx_pcs_create(mdio); + if (!pcs) + return -ENOMEM; + + dev_set_drvdata(dev, pcs); + pcs->dev = dev; + ret = pcs_register(pcs); + if (ret) + return dev_err_probe(dev, ret, "could not register PCS\n"); + dev_info(dev, "probed\n"); + return 0; +} void lynx_pcs_destroy(struct phylink_pcs *pcs) {
@@ -343,4 +365,55 @@ void lynx_pcs_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(lynx_pcs_destroy); -MODULE_LICENSE("Dual BSD/GPL"); +static void lynx_pcs_remove(struct mdio_device *mdio) +{ + struct phylink_pcs *pcs = dev_get_drvdata(&mdio->dev); + + pcs_unregister(pcs); + lynx_pcs_destroy(pcs); +} + +static const struct of_device_id lynx_pcs_of_match[] = { + { .compatible = "fsl,lynx-pcs" }, + { }, +}; +MODULE_DEVICE_TABLE(of, lynx_pcs_of_match); + +static struct mdio_driver lynx_pcs_driver = { + .probe = lynx_pcs_probe, + .remove = lynx_pcs_remove, + .mdiodrv.driver = { + .name = "lynx-pcs", + .of_match_table = of_match_ptr(lynx_pcs_of_match), + .suppress_bind_attrs = true, + }, +}; +mdio_module_driver(lynx_pcs_driver); + +struct phylink_pcs *lynx_pcs_create_on_bus(struct device *dev, + struct mii_bus *bus, int addr) +{ + struct mdio_device *mdio; + struct phylink_pcs *pcs; + int err; + + mdio = mdio_device_create(bus, addr); + if (IS_ERR(mdio)) + return ERR_CAST(mdio); + + mdio->bus_match = mdio_device_bus_match; + strncpy(mdio->modalias, "lynx-pcs", sizeof(mdio->modalias)); + err = mdio_device_register(mdio); + if (err) { + mdio_device_free(mdio); + return ERR_PTR(err); + } + + pcs = pcs_get_by_dev(dev, &mdio->dev); + mdio_device_free(mdio); + return pcs; +} +EXPORT_SYMBOL(lynx_pcs_create_on_bus); + +MODULE_DESCRIPTION("NXP Lynx 10G/28G PCS driver"); +MODULE_LICENSE("GPL");
diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h
index 5712cc2ce775..ef073b28fae9 100644
--- a/include/linux/pcs-lynx.h
+++ b/include/linux/pcs-lynx.h@@ -6,12 +6,15 @@ #ifndef __LINUX_PCS_LYNX_H #define __LINUX_PCS_LYNX_H -#include <linux/mdio.h> -#include <linux/phylink.h> +struct device; +struct mii_bus; +struct phylink_pcs; struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs); struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio); +struct phylink_pcs *lynx_pcs_create_on_bus(struct device *dev, + struct mii_bus *bus, int addr); void lynx_pcs_destroy(struct phylink_pcs *pcs);
--
2.35.1.1320.gc452695387.dirty