[net-next,v2] net: stmmac: don't create a MDIO bus if unnecessary

Message ID 20231206-stmmac-no-mdio-node-v2-1-333cae49b1ca@redhat.com
State New
Headers
Series [net-next,v2] net: stmmac: don't create a MDIO bus if unnecessary |

Commit Message

Andrew Halaney Dec. 6, 2023, 11:46 p.m. UTC
  The stmmac_dt_phy() function, which parses the devicetree node of the
MAC and ultimately causes MDIO bus allocation, misinterprets what
fixed-link means in relation to the MAC's MDIO bus. This results in
a MDIO bus being created in situations it need not be.

Currently a MDIO bus is created if the description is either:

    1. Not fixed-link
    2. fixed-link but contains a MDIO bus as well

The "1" case above isn't always accurate. If there's a phy-handle,
it could be referencing a phy on another MDIO controller's bus[1]. In
this case currently the MAC will make a MDIO bus and scan it all
anyways unnecessarily.

There's also a lot of upstream devicetrees[2] that expect a MDIO bus to
be created and scanned for a phy. This case can also be inferred from
the platform description by not having a phy-handle && not being
fixed-link. This hits case "1" in the current driver's logic.

Let's improve the logic to create a MDIO bus if either:

    - Devicetree contains a MDIO bus
    - !fixed-link && !phy-handle (legacy handling)

Below upstream devicetree snippets can be found that explain some of
the cases above more concretely.

Here's[0] a devicetree example where the MAC is both fixed-link and
driving a switch on MDIO (case "2" above). This needs a MDIO bus to
be created:

    &fec1 {
            phy-mode = "rmii";

            fixed-link {
                    speed = <100>;
                    full-duplex;
            };

            mdio1: mdio {
                    switch0: switch0@0 {
                            compatible = "marvell,mv88e6190";
                            pinctrl-0 = <&pinctrl_gpio_switch0>;
                    };
            };
    };

Here's[1] an example where there is no MDIO bus or fixed-link for
the ethernet1 MAC, so no MDIO bus should be created since ethernet0
is the MDIO master for ethernet1's phy:

    &ethernet0 {
            phy-mode = "sgmii";
            phy-handle = <&sgmii_phy0>;

            mdio {
                    compatible = "snps,dwmac-mdio";
                    sgmii_phy0: phy@8 {
                            compatible = "ethernet-phy-id0141.0dd4";
                            reg = <0x8>;
                            device_type = "ethernet-phy";
                    };

                    sgmii_phy1: phy@a {
                            compatible = "ethernet-phy-id0141.0dd4";
                            reg = <0xa>;
                            device_type = "ethernet-phy";
                    };
            };
    };

    &ethernet1 {
            phy-mode = "sgmii";
            phy-handle = <&sgmii_phy1>;
    };

Finally there's descriptions like this[2] which don't describe the
MDIO bus but expect it to be created and the whole address space
scanned for a phy since there's no phy-handle or fixed-link described:

    &gmac {
            phy-supply = <&vcc_lan>;
            phy-mode = "rmii";
            snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
            snps,reset-active-low;
            snps,reset-delays-us = <0 10000 1000000>;
    };

[0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
[1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
[2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164

Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
---
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 85 ++++++++++------------
 1 file changed, 37 insertions(+), 48 deletions(-)


---
base-commit: fd8a79b63710acb84321be3ce74be23c876873fb
change-id: 20231127-stmmac-no-mdio-node-1db9da8a25d9

Best regards,
  

Comments

Andrew Halaney Dec. 6, 2023, 11:58 p.m. UTC | #1
On Wed, Dec 06, 2023 at 05:46:09PM -0600, Andrew Halaney wrote:
> The stmmac_dt_phy() function, which parses the devicetree node of the
> MAC and ultimately causes MDIO bus allocation, misinterprets what
> fixed-link means in relation to the MAC's MDIO bus. This results in
> a MDIO bus being created in situations it need not be.
> 
> Currently a MDIO bus is created if the description is either:
> 
>     1. Not fixed-link
>     2. fixed-link but contains a MDIO bus as well
> 
> The "1" case above isn't always accurate. If there's a phy-handle,
> it could be referencing a phy on another MDIO controller's bus[1]. In
> this case currently the MAC will make a MDIO bus and scan it all
> anyways unnecessarily.
> 
> There's also a lot of upstream devicetrees[2] that expect a MDIO bus to
> be created and scanned for a phy. This case can also be inferred from
> the platform description by not having a phy-handle && not being
> fixed-link. This hits case "1" in the current driver's logic.
> 
> Let's improve the logic to create a MDIO bus if either:
> 
>     - Devicetree contains a MDIO bus
>     - !fixed-link && !phy-handle (legacy handling)
> 
> Below upstream devicetree snippets can be found that explain some of
> the cases above more concretely.
> 
> Here's[0] a devicetree example where the MAC is both fixed-link and
> driving a switch on MDIO (case "2" above). This needs a MDIO bus to
> be created:
> 
>     &fec1 {
>             phy-mode = "rmii";
> 
>             fixed-link {
>                     speed = <100>;
>                     full-duplex;
>             };
> 
>             mdio1: mdio {
>                     switch0: switch0@0 {
>                             compatible = "marvell,mv88e6190";
>                             pinctrl-0 = <&pinctrl_gpio_switch0>;
>                     };
>             };
>     };
> 
> Here's[1] an example where there is no MDIO bus or fixed-link for
> the ethernet1 MAC, so no MDIO bus should be created since ethernet0
> is the MDIO master for ethernet1's phy:
> 
>     &ethernet0 {
>             phy-mode = "sgmii";
>             phy-handle = <&sgmii_phy0>;
> 
>             mdio {
>                     compatible = "snps,dwmac-mdio";
>                     sgmii_phy0: phy@8 {
>                             compatible = "ethernet-phy-id0141.0dd4";
>                             reg = <0x8>;
>                             device_type = "ethernet-phy";
>                     };
> 
>                     sgmii_phy1: phy@a {
>                             compatible = "ethernet-phy-id0141.0dd4";
>                             reg = <0xa>;
>                             device_type = "ethernet-phy";
>                     };
>             };
>     };
> 
>     &ethernet1 {
>             phy-mode = "sgmii";
>             phy-handle = <&sgmii_phy1>;
>     };
> 
> Finally there's descriptions like this[2] which don't describe the
> MDIO bus but expect it to be created and the whole address space
> scanned for a phy since there's no phy-handle or fixed-link described:
> 
>     &gmac {
>             phy-supply = <&vcc_lan>;
>             phy-mode = "rmii";
>             snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
>             snps,reset-active-low;
>             snps,reset-delays-us = <0 10000 1000000>;
>     };
> 
> [0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
> [1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
> [2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
> 
> Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
> ---

Gah, I failed to describe my changes since Bart's v1 when picking this
up with b4 to make v2. Whoops!

Changes since v1:
    - Handle the fixed-link + mdio case (Andrew Lunn)
    - Reworded commit message
    - Handle the "legacy" case still mentioned in the commit
    - Bit further refactoring of the function
  
Serge Semin Dec. 7, 2023, 11:56 a.m. UTC | #2
Hi Andrew

On Wed, Dec 06, 2023 at 05:46:09PM -0600, Andrew Halaney wrote:
> The stmmac_dt_phy() function, which parses the devicetree node of the
> MAC and ultimately causes MDIO bus allocation, misinterprets what
> fixed-link means in relation to the MAC's MDIO bus. This results in
> a MDIO bus being created in situations it need not be.
> 
> Currently a MDIO bus is created if the description is either:
> 
>     1. Not fixed-link
>     2. fixed-link but contains a MDIO bus as well
> 
> The "1" case above isn't always accurate. If there's a phy-handle,
> it could be referencing a phy on another MDIO controller's bus[1]. In
> this case currently the MAC will make a MDIO bus and scan it all
> anyways unnecessarily.
> 
> There's also a lot of upstream devicetrees[2] that expect a MDIO bus to
> be created and scanned for a phy. This case can also be inferred from
> the platform description by not having a phy-handle && not being
> fixed-link. This hits case "1" in the current driver's logic.
> 
> Let's improve the logic to create a MDIO bus if either:
> 
>     - Devicetree contains a MDIO bus
>     - !fixed-link && !phy-handle (legacy handling)
> 
> Below upstream devicetree snippets can be found that explain some of
> the cases above more concretely.
> 
> Here's[0] a devicetree example where the MAC is both fixed-link and
> driving a switch on MDIO (case "2" above). This needs a MDIO bus to
> be created:
> 
>     &fec1 {
>             phy-mode = "rmii";
> 
>             fixed-link {
>                     speed = <100>;
>                     full-duplex;
>             };
> 
>             mdio1: mdio {
>                     switch0: switch0@0 {
>                             compatible = "marvell,mv88e6190";
>                             pinctrl-0 = <&pinctrl_gpio_switch0>;
>                     };
>             };
>     };
> 
> Here's[1] an example where there is no MDIO bus or fixed-link for
> the ethernet1 MAC, so no MDIO bus should be created since ethernet0
> is the MDIO master for ethernet1's phy:
> 
>     &ethernet0 {
>             phy-mode = "sgmii";
>             phy-handle = <&sgmii_phy0>;
> 
>             mdio {
>                     compatible = "snps,dwmac-mdio";
>                     sgmii_phy0: phy@8 {
>                             compatible = "ethernet-phy-id0141.0dd4";
>                             reg = <0x8>;
>                             device_type = "ethernet-phy";
>                     };
> 
>                     sgmii_phy1: phy@a {
>                             compatible = "ethernet-phy-id0141.0dd4";
>                             reg = <0xa>;
>                             device_type = "ethernet-phy";
>                     };
>             };
>     };
> 
>     &ethernet1 {
>             phy-mode = "sgmii";
>             phy-handle = <&sgmii_phy1>;
>     };
> 
> Finally there's descriptions like this[2] which don't describe the
> MDIO bus but expect it to be created and the whole address space
> scanned for a phy since there's no phy-handle or fixed-link described:
> 
>     &gmac {
>             phy-supply = <&vcc_lan>;
>             phy-mode = "rmii";
>             snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
>             snps,reset-active-low;
>             snps,reset-delays-us = <0 10000 1000000>;
>     };
> 
> [0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
> [1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
> [2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164

Thank you for the patch. Please find a comment below.

> 
> Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
> ---
>  .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 85 ++++++++++------------
>  1 file changed, 37 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> index 1ffde555da47..7da461fe93f6 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> @@ -296,69 +296,39 @@ static int stmmac_mtl_setup(struct platform_device *pdev,
>  }
>  
>  /**
> - * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
> - * @plat: driver data platform structure
> - * @np: device tree node
> - * @dev: device pointer
> - * Description:
> - * The mdio bus will be allocated in case of a phy transceiver is on board;
> - * it will be NULL if the fixed-link is configured.
> - * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
> - * in any case (for DSA, mdio must be registered even if fixed-link).
> - * The table below sums the supported configurations:
> - *	-------------------------------
> - *	snps,phy-addr	|     Y
> - *	-------------------------------
> - *	phy-handle	|     Y
> - *	-------------------------------
> - *	fixed-link	|     N
> - *	-------------------------------
> - *	snps,dwmac-mdio	|
> - *	  even if	|     Y
> - *	fixed-link	|
> - *	-------------------------------
> + * stmmac_of_get_mdio() - Gets the MDIO bus from the devicetree
> + * @np: devicetree node
>   *
> - * It returns 0 in case of success otherwise -ENODEV.
> + * The MDIO bus will be searched for in the following ways:
> + * 1. The compatible is "snps,dwc-qos-ethernet-4.10" && a "mdio" named
> + *    child node exists
> + * 2. A child node with the "snps,dwmac-mdio" compatible is present
> + *
> + * Return: The MDIO node if present otherwise NULL
>   */
> -static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
> -			 struct device_node *np, struct device *dev)
> +static struct device_node *stmmac_of_get_mdio(struct device_node *np)
>  {
> -	bool mdio = !of_phy_is_fixed_link(np);
>  	static const struct of_device_id need_mdio_ids[] = {
>  		{ .compatible = "snps,dwc-qos-ethernet-4.10" },
>  		{},
>  	};
> +	struct device_node *mdio_node = NULL;
>  
>  	if (of_match_node(need_mdio_ids, np)) {
> -		plat->mdio_node = of_get_child_by_name(np, "mdio");
> +		mdio_node = of_get_child_by_name(np, "mdio");
>  	} else {
>  		/**
>  		 * If snps,dwmac-mdio is passed from DT, always register
>  		 * the MDIO
>  		 */
> -		for_each_child_of_node(np, plat->mdio_node) {
> -			if (of_device_is_compatible(plat->mdio_node,
> +		for_each_child_of_node(np, mdio_node) {
> +			if (of_device_is_compatible(mdio_node,
>  						    "snps,dwmac-mdio"))
>  				break;
>  		}
>  	}
>  
> -	if (plat->mdio_node) {
> -		dev_dbg(dev, "Found MDIO subnode\n");
> -		mdio = true;
> -	}
> -
> -	if (mdio) {
> -		plat->mdio_bus_data =
> -			devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
> -				     GFP_KERNEL);
> -		if (!plat->mdio_bus_data)
> -			return -ENOMEM;
> -
> -		plat->mdio_bus_data->needs_reset = true;
> -	}
> -
> -	return 0;
> +	return mdio_node;
>  }
>  
>  /**
> @@ -417,6 +387,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
>  	struct device_node *np = pdev->dev.of_node;
>  	struct plat_stmmacenet_data *plat;
>  	struct stmmac_dma_cfg *dma_cfg;
> +	bool legacy_mdio;
>  	int phy_mode;
>  	void *ret;
>  	int rc;
> @@ -471,10 +442,28 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
>  	if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
>  		dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
>  
> -	/* To Configure PHY by using all device-tree supported properties */
> -	rc = stmmac_dt_phy(plat, np, &pdev->dev);
> -	if (rc)
> -		return ERR_PTR(rc);
> +	plat->mdio_node = stmmac_of_get_mdio(np);
> +	if (plat->mdio_node)
> +		dev_dbg(&pdev->dev, "Found MDIO subnode\n");
> +

> +	/* Legacy devicetrees allowed for no MDIO bus description and expect
> +	 * the bus to be scanned for devices. If there's no phy or fixed-link
> +	 * described assume this is the case since there must be something
> +	 * connected to the MAC.
> +	 */
> +	legacy_mdio = !of_phy_is_fixed_link(np) && !plat->phy_node;
> +	if (legacy_mdio)
> +		dev_info(&pdev->dev, "Deprecated MDIO bus assumption used\n");
> +
> +	if (plat->mdio_node || legacy_mdio) {
> +		plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
> +						   sizeof(struct stmmac_mdio_bus_data),
> +						   GFP_KERNEL);
> +		if (!plat->mdio_bus_data)
> +			return ERR_PTR(-ENOMEM);
> +
> +		plat->mdio_bus_data->needs_reset = true;
> +	}

Why did you decide to move this out of the dedicated function?
stmmac_probe_config_dt() is already overwhelmed with various
non-coherent actions. The method has already got to being too long to
follow the kernel coding style limit (I have got a not submitted yet
cleanup patchset which step-by-step fixes that). Could you please get
the chunk above back to the respective function and, for instance,
just change it's name to something like stmmac_mdio_setup()? (I prefer
having "_setup" suffix because some of the locally defined static
methods already use it: stmmac_axi_setup(), stmmac_mtl_setup().)

-Serge(y)

>  
>  	of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
>  
> 
> ---
> base-commit: fd8a79b63710acb84321be3ce74be23c876873fb
> change-id: 20231127-stmmac-no-mdio-node-1db9da8a25d9
> 
> Best regards,
> -- 
> Andrew Halaney <ahalaney@redhat.com>
> 
>
  
Andrew Halaney Dec. 7, 2023, 1:32 p.m. UTC | #3
On Thu, Dec 07, 2023 at 02:56:25PM +0300, Serge Semin wrote:
> Hi Andrew
> 
> On Wed, Dec 06, 2023 at 05:46:09PM -0600, Andrew Halaney wrote:
> > The stmmac_dt_phy() function, which parses the devicetree node of the
> > MAC and ultimately causes MDIO bus allocation, misinterprets what
> > fixed-link means in relation to the MAC's MDIO bus. This results in
> > a MDIO bus being created in situations it need not be.
> > 
> > Currently a MDIO bus is created if the description is either:
> > 
> >     1. Not fixed-link
> >     2. fixed-link but contains a MDIO bus as well
> > 
> > The "1" case above isn't always accurate. If there's a phy-handle,
> > it could be referencing a phy on another MDIO controller's bus[1]. In
> > this case currently the MAC will make a MDIO bus and scan it all
> > anyways unnecessarily.
> > 
> > There's also a lot of upstream devicetrees[2] that expect a MDIO bus to
> > be created and scanned for a phy. This case can also be inferred from
> > the platform description by not having a phy-handle && not being
> > fixed-link. This hits case "1" in the current driver's logic.
> > 
> > Let's improve the logic to create a MDIO bus if either:
> > 
> >     - Devicetree contains a MDIO bus
> >     - !fixed-link && !phy-handle (legacy handling)
> > 
> > Below upstream devicetree snippets can be found that explain some of
> > the cases above more concretely.
> > 
> > Here's[0] a devicetree example where the MAC is both fixed-link and
> > driving a switch on MDIO (case "2" above). This needs a MDIO bus to
> > be created:
> > 
> >     &fec1 {
> >             phy-mode = "rmii";
> > 
> >             fixed-link {
> >                     speed = <100>;
> >                     full-duplex;
> >             };
> > 
> >             mdio1: mdio {
> >                     switch0: switch0@0 {
> >                             compatible = "marvell,mv88e6190";
> >                             pinctrl-0 = <&pinctrl_gpio_switch0>;
> >                     };
> >             };
> >     };
> > 
> > Here's[1] an example where there is no MDIO bus or fixed-link for
> > the ethernet1 MAC, so no MDIO bus should be created since ethernet0
> > is the MDIO master for ethernet1's phy:
> > 
> >     &ethernet0 {
> >             phy-mode = "sgmii";
> >             phy-handle = <&sgmii_phy0>;
> > 
> >             mdio {
> >                     compatible = "snps,dwmac-mdio";
> >                     sgmii_phy0: phy@8 {
> >                             compatible = "ethernet-phy-id0141.0dd4";
> >                             reg = <0x8>;
> >                             device_type = "ethernet-phy";
> >                     };
> > 
> >                     sgmii_phy1: phy@a {
> >                             compatible = "ethernet-phy-id0141.0dd4";
> >                             reg = <0xa>;
> >                             device_type = "ethernet-phy";
> >                     };
> >             };
> >     };
> > 
> >     &ethernet1 {
> >             phy-mode = "sgmii";
> >             phy-handle = <&sgmii_phy1>;
> >     };
> > 
> > Finally there's descriptions like this[2] which don't describe the
> > MDIO bus but expect it to be created and the whole address space
> > scanned for a phy since there's no phy-handle or fixed-link described:
> > 
> >     &gmac {
> >             phy-supply = <&vcc_lan>;
> >             phy-mode = "rmii";
> >             snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
> >             snps,reset-active-low;
> >             snps,reset-delays-us = <0 10000 1000000>;
> >     };
> > 
> > [0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
> > [1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
> > [2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
> 
> Thank you for the patch. Please find a comment below.
> 
> > 
> > Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
> > ---
> >  .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 85 ++++++++++------------
> >  1 file changed, 37 insertions(+), 48 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> > index 1ffde555da47..7da461fe93f6 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> > @@ -296,69 +296,39 @@ static int stmmac_mtl_setup(struct platform_device *pdev,
> >  }
> >  
> >  /**
> > - * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
> > - * @plat: driver data platform structure
> > - * @np: device tree node
> > - * @dev: device pointer
> > - * Description:
> > - * The mdio bus will be allocated in case of a phy transceiver is on board;
> > - * it will be NULL if the fixed-link is configured.
> > - * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
> > - * in any case (for DSA, mdio must be registered even if fixed-link).
> > - * The table below sums the supported configurations:
> > - *	-------------------------------
> > - *	snps,phy-addr	|     Y
> > - *	-------------------------------
> > - *	phy-handle	|     Y
> > - *	-------------------------------
> > - *	fixed-link	|     N
> > - *	-------------------------------
> > - *	snps,dwmac-mdio	|
> > - *	  even if	|     Y
> > - *	fixed-link	|
> > - *	-------------------------------
> > + * stmmac_of_get_mdio() - Gets the MDIO bus from the devicetree
> > + * @np: devicetree node
> >   *
> > - * It returns 0 in case of success otherwise -ENODEV.
> > + * The MDIO bus will be searched for in the following ways:
> > + * 1. The compatible is "snps,dwc-qos-ethernet-4.10" && a "mdio" named
> > + *    child node exists
> > + * 2. A child node with the "snps,dwmac-mdio" compatible is present
> > + *
> > + * Return: The MDIO node if present otherwise NULL
> >   */
> > -static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
> > -			 struct device_node *np, struct device *dev)
> > +static struct device_node *stmmac_of_get_mdio(struct device_node *np)
> >  {
> > -	bool mdio = !of_phy_is_fixed_link(np);
> >  	static const struct of_device_id need_mdio_ids[] = {
> >  		{ .compatible = "snps,dwc-qos-ethernet-4.10" },
> >  		{},
> >  	};
> > +	struct device_node *mdio_node = NULL;
> >  
> >  	if (of_match_node(need_mdio_ids, np)) {
> > -		plat->mdio_node = of_get_child_by_name(np, "mdio");
> > +		mdio_node = of_get_child_by_name(np, "mdio");
> >  	} else {
> >  		/**
> >  		 * If snps,dwmac-mdio is passed from DT, always register
> >  		 * the MDIO
> >  		 */
> > -		for_each_child_of_node(np, plat->mdio_node) {
> > -			if (of_device_is_compatible(plat->mdio_node,
> > +		for_each_child_of_node(np, mdio_node) {
> > +			if (of_device_is_compatible(mdio_node,
> >  						    "snps,dwmac-mdio"))
> >  				break;
> >  		}
> >  	}
> >  
> > -	if (plat->mdio_node) {
> > -		dev_dbg(dev, "Found MDIO subnode\n");
> > -		mdio = true;
> > -	}
> > -
> > -	if (mdio) {
> > -		plat->mdio_bus_data =
> > -			devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
> > -				     GFP_KERNEL);
> > -		if (!plat->mdio_bus_data)
> > -			return -ENOMEM;
> > -
> > -		plat->mdio_bus_data->needs_reset = true;
> > -	}
> > -
> > -	return 0;
> > +	return mdio_node;
> >  }
> >  
> >  /**
> > @@ -417,6 +387,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
> >  	struct device_node *np = pdev->dev.of_node;
> >  	struct plat_stmmacenet_data *plat;
> >  	struct stmmac_dma_cfg *dma_cfg;
> > +	bool legacy_mdio;
> >  	int phy_mode;
> >  	void *ret;
> >  	int rc;
> > @@ -471,10 +442,28 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
> >  	if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
> >  		dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
> >  
> > -	/* To Configure PHY by using all device-tree supported properties */
> > -	rc = stmmac_dt_phy(plat, np, &pdev->dev);
> > -	if (rc)
> > -		return ERR_PTR(rc);
> > +	plat->mdio_node = stmmac_of_get_mdio(np);
> > +	if (plat->mdio_node)
> > +		dev_dbg(&pdev->dev, "Found MDIO subnode\n");
> > +
> 
> > +	/* Legacy devicetrees allowed for no MDIO bus description and expect
> > +	 * the bus to be scanned for devices. If there's no phy or fixed-link
> > +	 * described assume this is the case since there must be something
> > +	 * connected to the MAC.
> > +	 */
> > +	legacy_mdio = !of_phy_is_fixed_link(np) && !plat->phy_node;
> > +	if (legacy_mdio)
> > +		dev_info(&pdev->dev, "Deprecated MDIO bus assumption used\n");
> > +
> > +	if (plat->mdio_node || legacy_mdio) {
> > +		plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
> > +						   sizeof(struct stmmac_mdio_bus_data),
> > +						   GFP_KERNEL);
> > +		if (!plat->mdio_bus_data)
> > +			return ERR_PTR(-ENOMEM);
> > +
> > +		plat->mdio_bus_data->needs_reset = true;
> > +	}
> 
> Why did you decide to move this out of the dedicated function?
> stmmac_probe_config_dt() is already overwhelmed with various
> non-coherent actions. The method has already got to being too long to
> follow the kernel coding style limit (I have got a not submitted yet
> cleanup patchset which step-by-step fixes that). Could you please get
> the chunk above back to the respective function and, for instance,
> just change it's name to something like stmmac_mdio_setup()? (I prefer
> having "_setup" suffix because some of the locally defined static
> methods already use it: stmmac_axi_setup(), stmmac_mtl_setup().)

Sure, I can put it back in. I'll probably keep stmmac_of_get_mdio()
(which is named in the style I see in the current file -- although as
you highlight that shouldn't be taken as the best example of clean),
and have stmmac_mdio_setup() call that and and mimic the inputs/outputs
of the current function (moving the rest of the added code from
stmmac_probe_config_dt() back into that function).

Thanks for the feedback, let me know if you still think that abstraction
isn't ideal (or wait till I post it :P) and I'll go with exactly as you
said. I'm not _too_ opinionated on it, but thought stmmac_dt_phy()
didn't explain much and stmmac_of_get_mdio() was self-explanatory enough
that it helped readability.

> 
> -Serge(y)
> 
> >  
> >  	of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
> >  
> > 
> > ---
> > base-commit: fd8a79b63710acb84321be3ce74be23c876873fb
> > change-id: 20231127-stmmac-no-mdio-node-1db9da8a25d9
> > 
> > Best regards,
> > -- 
> > Andrew Halaney <ahalaney@redhat.com>
> > 
> > 
>
  
Serge Semin Dec. 7, 2023, 1:55 p.m. UTC | #4
On Thu, Dec 07, 2023 at 07:32:29AM -0600, Andrew Halaney wrote:
> On Thu, Dec 07, 2023 at 02:56:25PM +0300, Serge Semin wrote:
> > Hi Andrew
> > 
> > On Wed, Dec 06, 2023 at 05:46:09PM -0600, Andrew Halaney wrote:
> > > The stmmac_dt_phy() function, which parses the devicetree node of the
> > > MAC and ultimately causes MDIO bus allocation, misinterprets what
> > > fixed-link means in relation to the MAC's MDIO bus. This results in
> > > a MDIO bus being created in situations it need not be.
> > > 
> > > Currently a MDIO bus is created if the description is either:
> > > 
> > >     1. Not fixed-link
> > >     2. fixed-link but contains a MDIO bus as well
> > > 
> > > The "1" case above isn't always accurate. If there's a phy-handle,
> > > it could be referencing a phy on another MDIO controller's bus[1]. In
> > > this case currently the MAC will make a MDIO bus and scan it all
> > > anyways unnecessarily.
> > > 
> > > There's also a lot of upstream devicetrees[2] that expect a MDIO bus to
> > > be created and scanned for a phy. This case can also be inferred from
> > > the platform description by not having a phy-handle && not being
> > > fixed-link. This hits case "1" in the current driver's logic.
> > > 
> > > Let's improve the logic to create a MDIO bus if either:
> > > 
> > >     - Devicetree contains a MDIO bus
> > >     - !fixed-link && !phy-handle (legacy handling)
> > > 
> > > Below upstream devicetree snippets can be found that explain some of
> > > the cases above more concretely.
> > > 
> > > Here's[0] a devicetree example where the MAC is both fixed-link and
> > > driving a switch on MDIO (case "2" above). This needs a MDIO bus to
> > > be created:
> > > 
> > >     &fec1 {
> > >             phy-mode = "rmii";
> > > 
> > >             fixed-link {
> > >                     speed = <100>;
> > >                     full-duplex;
> > >             };
> > > 
> > >             mdio1: mdio {
> > >                     switch0: switch0@0 {
> > >                             compatible = "marvell,mv88e6190";
> > >                             pinctrl-0 = <&pinctrl_gpio_switch0>;
> > >                     };
> > >             };
> > >     };
> > > 
> > > Here's[1] an example where there is no MDIO bus or fixed-link for
> > > the ethernet1 MAC, so no MDIO bus should be created since ethernet0
> > > is the MDIO master for ethernet1's phy:
> > > 
> > >     &ethernet0 {
> > >             phy-mode = "sgmii";
> > >             phy-handle = <&sgmii_phy0>;
> > > 
> > >             mdio {
> > >                     compatible = "snps,dwmac-mdio";
> > >                     sgmii_phy0: phy@8 {
> > >                             compatible = "ethernet-phy-id0141.0dd4";
> > >                             reg = <0x8>;
> > >                             device_type = "ethernet-phy";
> > >                     };
> > > 
> > >                     sgmii_phy1: phy@a {
> > >                             compatible = "ethernet-phy-id0141.0dd4";
> > >                             reg = <0xa>;
> > >                             device_type = "ethernet-phy";
> > >                     };
> > >             };
> > >     };
> > > 
> > >     &ethernet1 {
> > >             phy-mode = "sgmii";
> > >             phy-handle = <&sgmii_phy1>;
> > >     };
> > > 
> > > Finally there's descriptions like this[2] which don't describe the
> > > MDIO bus but expect it to be created and the whole address space
> > > scanned for a phy since there's no phy-handle or fixed-link described:
> > > 
> > >     &gmac {
> > >             phy-supply = <&vcc_lan>;
> > >             phy-mode = "rmii";
> > >             snps,reset-gpio = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
> > >             snps,reset-active-low;
> > >             snps,reset-delays-us = <0 10000 1000000>;
> > >     };
> > > 
> > > [0] https://elixir.bootlin.com/linux/v6.5-rc5/source/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts
> > > [1] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/qcom/sa8775p-ride.dts
> > > [2] https://elixir.bootlin.com/linux/v6.6-rc5/source/arch/arm64/boot/dts/rockchip/rk3368-r88.dts#L164
> > 
> > Thank you for the patch. Please find a comment below.
> > 
> > > 
> > > Co-developed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > > Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
> > > ---
> > >  .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 85 ++++++++++------------
> > >  1 file changed, 37 insertions(+), 48 deletions(-)
> > > 
> > > diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> > > index 1ffde555da47..7da461fe93f6 100644
> > > --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> > > +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
> > > @@ -296,69 +296,39 @@ static int stmmac_mtl_setup(struct platform_device *pdev,
> > >  }
> > >  
> > >  /**
> > > - * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
> > > - * @plat: driver data platform structure
> > > - * @np: device tree node
> > > - * @dev: device pointer
> > > - * Description:
> > > - * The mdio bus will be allocated in case of a phy transceiver is on board;
> > > - * it will be NULL if the fixed-link is configured.
> > > - * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
> > > - * in any case (for DSA, mdio must be registered even if fixed-link).
> > > - * The table below sums the supported configurations:
> > > - *	-------------------------------
> > > - *	snps,phy-addr	|     Y
> > > - *	-------------------------------
> > > - *	phy-handle	|     Y
> > > - *	-------------------------------
> > > - *	fixed-link	|     N
> > > - *	-------------------------------
> > > - *	snps,dwmac-mdio	|
> > > - *	  even if	|     Y
> > > - *	fixed-link	|
> > > - *	-------------------------------
> > > + * stmmac_of_get_mdio() - Gets the MDIO bus from the devicetree
> > > + * @np: devicetree node
> > >   *
> > > - * It returns 0 in case of success otherwise -ENODEV.
> > > + * The MDIO bus will be searched for in the following ways:
> > > + * 1. The compatible is "snps,dwc-qos-ethernet-4.10" && a "mdio" named
> > > + *    child node exists
> > > + * 2. A child node with the "snps,dwmac-mdio" compatible is present
> > > + *
> > > + * Return: The MDIO node if present otherwise NULL
> > >   */
> > > -static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
> > > -			 struct device_node *np, struct device *dev)
> > > +static struct device_node *stmmac_of_get_mdio(struct device_node *np)
> > >  {
> > > -	bool mdio = !of_phy_is_fixed_link(np);
> > >  	static const struct of_device_id need_mdio_ids[] = {
> > >  		{ .compatible = "snps,dwc-qos-ethernet-4.10" },
> > >  		{},
> > >  	};
> > > +	struct device_node *mdio_node = NULL;
> > >  
> > >  	if (of_match_node(need_mdio_ids, np)) {
> > > -		plat->mdio_node = of_get_child_by_name(np, "mdio");
> > > +		mdio_node = of_get_child_by_name(np, "mdio");
> > >  	} else {
> > >  		/**
> > >  		 * If snps,dwmac-mdio is passed from DT, always register
> > >  		 * the MDIO
> > >  		 */
> > > -		for_each_child_of_node(np, plat->mdio_node) {
> > > -			if (of_device_is_compatible(plat->mdio_node,
> > > +		for_each_child_of_node(np, mdio_node) {
> > > +			if (of_device_is_compatible(mdio_node,
> > >  						    "snps,dwmac-mdio"))
> > >  				break;
> > >  		}
> > >  	}
> > >  
> > > -	if (plat->mdio_node) {
> > > -		dev_dbg(dev, "Found MDIO subnode\n");
> > > -		mdio = true;
> > > -	}
> > > -
> > > -	if (mdio) {
> > > -		plat->mdio_bus_data =
> > > -			devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
> > > -				     GFP_KERNEL);
> > > -		if (!plat->mdio_bus_data)
> > > -			return -ENOMEM;
> > > -
> > > -		plat->mdio_bus_data->needs_reset = true;
> > > -	}
> > > -
> > > -	return 0;
> > > +	return mdio_node;
> > >  }
> > >  
> > >  /**
> > > @@ -417,6 +387,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
> > >  	struct device_node *np = pdev->dev.of_node;
> > >  	struct plat_stmmacenet_data *plat;
> > >  	struct stmmac_dma_cfg *dma_cfg;
> > > +	bool legacy_mdio;
> > >  	int phy_mode;
> > >  	void *ret;
> > >  	int rc;
> > > @@ -471,10 +442,28 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
> > >  	if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
> > >  		dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
> > >  
> > > -	/* To Configure PHY by using all device-tree supported properties */
> > > -	rc = stmmac_dt_phy(plat, np, &pdev->dev);
> > > -	if (rc)
> > > -		return ERR_PTR(rc);
> > > +	plat->mdio_node = stmmac_of_get_mdio(np);
> > > +	if (plat->mdio_node)
> > > +		dev_dbg(&pdev->dev, "Found MDIO subnode\n");
> > > +
> > 
> > > +	/* Legacy devicetrees allowed for no MDIO bus description and expect
> > > +	 * the bus to be scanned for devices. If there's no phy or fixed-link
> > > +	 * described assume this is the case since there must be something
> > > +	 * connected to the MAC.
> > > +	 */
> > > +	legacy_mdio = !of_phy_is_fixed_link(np) && !plat->phy_node;
> > > +	if (legacy_mdio)
> > > +		dev_info(&pdev->dev, "Deprecated MDIO bus assumption used\n");
> > > +
> > > +	if (plat->mdio_node || legacy_mdio) {
> > > +		plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
> > > +						   sizeof(struct stmmac_mdio_bus_data),
> > > +						   GFP_KERNEL);
> > > +		if (!plat->mdio_bus_data)
> > > +			return ERR_PTR(-ENOMEM);
> > > +
> > > +		plat->mdio_bus_data->needs_reset = true;
> > > +	}
> > 
> > Why did you decide to move this out of the dedicated function?
> > stmmac_probe_config_dt() is already overwhelmed with various
> > non-coherent actions. The method has already got to being too long to
> > follow the kernel coding style limit (I have got a not submitted yet
> > cleanup patchset which step-by-step fixes that). Could you please get
> > the chunk above back to the respective function and, for instance,
> > just change it's name to something like stmmac_mdio_setup()? (I prefer
> > having "_setup" suffix because some of the locally defined static
> > methods already use it: stmmac_axi_setup(), stmmac_mtl_setup().)
> 

> Sure, I can put it back in. I'll probably keep stmmac_of_get_mdio()
> (which is named in the style I see in the current file -- although as
> you highlight that shouldn't be taken as the best example of clean),
> and have stmmac_mdio_setup() call that and and mimic the inputs/outputs
> of the current function (moving the rest of the added code from
> stmmac_probe_config_dt() back into that function).
> 
> Thanks for the feedback, let me know if you still think that abstraction
> isn't ideal (or wait till I post it :P) and I'll go with exactly as you
> said.

Sounds good. Thanks for taking my comment into account.

> I'm not _too_ opinionated on it, but thought stmmac_dt_phy()
> didn't explain much and stmmac_of_get_mdio() was self-explanatory enough
> that it helped readability.

You were right. stmmac_dt_phy() hasn't been explicitly doing
PHY-related things since commit 74371272f97f ("net: stmmac: Convert to
phylink and remove phylib logic"), but has been left with the MDIO
stuff only. The function name wasn't that well chosen either.  It
didn't indicate what the function actually did, like "init", "get",
"setup", etc. From that perspective your naming is much better - short
and self-explanatory indeed.

-Serge(y)

> 
> > 
> > -Serge(y)
> > 
> > >  
> > >  	of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
> > >  
> > > 
> > > ---
> > > base-commit: fd8a79b63710acb84321be3ce74be23c876873fb
> > > change-id: 20231127-stmmac-no-mdio-node-1db9da8a25d9
> > > 
> > > Best regards,
> > > -- 
> > > Andrew Halaney <ahalaney@redhat.com>
> > > 
> > > 
> > 
>
  
Andrew Lunn Dec. 7, 2023, 9:30 p.m. UTC | #5
On Wed, Dec 06, 2023 at 05:46:09PM -0600, Andrew Halaney wrote:
> The stmmac_dt_phy() function, which parses the devicetree node of the
> MAC and ultimately causes MDIO bus allocation, misinterprets what
> fixed-link means in relation to the MAC's MDIO bus. This results in
> a MDIO bus being created in situations it need not be.

Please extend that with something like....

This is bad, because ....

Most 'clean' driver unconditionally create the MDIO bus. But stmmac is
not that clean, and has to keep backwards compatibility to some old
usage. I'm just wondering what this patch actually brings us, and is
it worth it. Is it fixing a real bug, or just an optimisation?

   Andrew
  
Andrew Halaney Dec. 7, 2023, 11 p.m. UTC | #6
On Thu, Dec 07, 2023 at 10:30:23PM +0100, Andrew Lunn wrote:
> On Wed, Dec 06, 2023 at 05:46:09PM -0600, Andrew Halaney wrote:
> > The stmmac_dt_phy() function, which parses the devicetree node of the
> > MAC and ultimately causes MDIO bus allocation, misinterprets what
> > fixed-link means in relation to the MAC's MDIO bus. This results in
> > a MDIO bus being created in situations it need not be.
>
> Please extend that with something like....
>
> This is bad, because ....
>
> Most 'clean' driver unconditionally create the MDIO bus. But stmmac is
> not that clean, and has to keep backwards compatibility to some old
> usage. I'm just wondering what this patch actually brings us, and is
> it worth it. Is it fixing a real bug, or just an optimisation?
>
>    Andrew
>

It is an optimization for speeding up time to link up. I already sent
out v3 moments before this arrived, I'll be sure to capture that more
clearly in v4 (and wait a little longer before respinning it).

I'm trying to optimize this device configuration (as shown in the commit):
"""
    Here's[1] an example where there is no MDIO bus or fixed-link for
    the ethernet1 MAC, so no MDIO bus should be created since ethernet0
    is the MDIO master for ethernet1's phy:

        &ethernet0 {
                phy-mode = "sgmii";
                phy-handle = <&sgmii_phy0>;

                mdio {
                        compatible = "snps,dwmac-mdio";
                        sgmii_phy0: phy@8 {
                                compatible = "ethernet-phy-id0141.0dd4";
                                reg = <0x8>;
                                device_type = "ethernet-phy";
                        };

                        sgmii_phy1: phy@a {
                                compatible = "ethernet-phy-id0141.0dd4";
                                reg = <0xa>;
                                device_type = "ethernet-phy";
                        };
                };
        };

        &ethernet1 {
                phy-mode = "sgmii";
                phy-handle = <&sgmii_phy1>;
        };
"""

I'm seeing that ethernet1 scans the whole MDIO bus created for it, and
finds nothing, wasting time in the process. Since there's no mdio bus
described (since it's vacant) you get something like this call order:

    stmmac_mdio_register()
    of_mdiobus_register(new_bus, mdio_node) // mdio_node is NULL in this case
    __of_mdiobus_register(mdio, np, owner)  // this doesn't set phy_mask since np == NULL
    __mdiobus_register(mdio, owner)
    mdiobus_scan_bus_c22(bus)
    mdiobus_scan_c22()                      // Called PHY_MAX_ADDR times, probing an empty bus

Which is causing a good bit of delay in the time to link up, each
attempted probe is taking about 5 ms and that's just benchmarking the
get_phy_c22_id() calls, if you look at the whole loop it's greater (but I
am unsure if that's just scheduling contention or something else going
on, once I realized we were doing this work unnecessarily I decided to
try and remove it)

I know you said the standard is to make the MDIO bus unconditionally, but
to me that feels like a waste, and describing say an empty MDIO bus
(which would set the phy_mask for us eventually and not scan a
bunch of phys, untested but I think that would work) seems like a bad
description in the devicetree (I could definitely see describing an
empty MDIO bus getting NACKed, but that's a guess).

Please let me know if you disagree with that logic and have some
alternative solutions for optimizing. In either case I think this code
needs some cleaning so I'll carry this through. It also seems that
unconditional creation of the MDIO bus is something that's biting some
stmmac variants that lack an MDIO controller based on Serge's latest
comments on v3:

    https://lore.kernel.org/netdev/jz6ot44fjkbmwcezi3fkgqd54nurglblbemrchfgxgq6udlhqz@ntepnnzzelta/

Thanks,
Andrew
  
Andrew Lunn Dec. 8, 2023, 1:14 p.m. UTC | #7
> I know you said the standard is to make the MDIO bus unconditionally, but
> to me that feels like a waste, and describing say an empty MDIO bus
> (which would set the phy_mask for us eventually and not scan a
> bunch of phys, untested but I think that would work) seems like a bad
> description in the devicetree (I could definitely see describing an
> empty MDIO bus getting NACKed, but that's a guess).

DT describes the hardware. The MDIO bus master exists. So typically
the SoC .dtsi file would include it in the Ethernet node. At the SoC
level it is empty, unless there is an integrated PHY in the SoC. The
board .dts file then adds any PHYs to the node which the board
actually has.

So i doubt adding an empty MDIO node to the SoC .dtsi file will get
NACKed, it correctly describes the hardware.

	Andrew
  
Andrew Halaney Dec. 8, 2023, 4:33 p.m. UTC | #8
On Fri, Dec 08, 2023 at 02:14:41PM +0100, Andrew Lunn wrote:
> > I know you said the standard is to make the MDIO bus unconditionally, but
> > to me that feels like a waste, and describing say an empty MDIO bus
> > (which would set the phy_mask for us eventually and not scan a
> > bunch of phys, untested but I think that would work) seems like a bad
> > description in the devicetree (I could definitely see describing an
> > empty MDIO bus getting NACKed, but that's a guess).
> 
> DT describes the hardware. The MDIO bus master exists. So typically
> the SoC .dtsi file would include it in the Ethernet node. At the SoC
> level it is empty, unless there is an integrated PHY in the SoC. The
> board .dts file then adds any PHYs to the node which the board
> actually has.
> 
> So i doubt adding an empty MDIO node to the SoC .dtsi file will get
> NACKed, it correctly describes the hardware.

Agreed, thanks for helping me consider all the cases. In my particular
example it would make sense to have SoC dtsi describe the mdio bus,
leave it disabled, and boards enable it and describe components as
necessary.

So you have let's say these 8 abbreviated cases:

Case 1 (MDIO bus used with phy on bus connected to MAC):

	ethernet {
		status = "okay";
		phy-handle = <&phy0>;
		phy-mode = "rgmii";

		mdio {
			status = "okay";

			phy0: phy@0 {
			};
		};
	};

Case 2 (MDIO bus used but MAC's connect fixed-link):

	ethernet {
		status = "okay";
		phy-mode = "rgmii";

		fixed-link {
		};

		mdio {
			status = "okay";

			switch/unrelated-phy {
			};
		};
	};

Case 3 (MDIO bus used but MAC's connected to another bus's phy):

	ethernet {
		status = "okay";
		phy-handle = <&phy1>;
		phy-mode = "rgmii";

		mdio {
			status = "okay";

			switch/unrelated-phy {
			};
		};
	};

Case 4 (MDIO bus disabled/unused, connected fixed-link):

	ethernet {
		status = "okay";
		phy-mode = "rgmii";

		fixed-link {
		};

		mdio {
			status = "disabled";
		};
	};

Case 5 (MDIO bus disabled/unused, connected to another bus's phy):

	ethernet {
		status = "okay";
		phy-handle = <&phy1>;
		phy-mode = "rgmii";

		mdio {
			status = "disabled";
		};
	};

Case 6 (MDIO bus not described, connected fixed-link):

	ethernet {
		status = "okay";
		phy-mode = "rgmii";

		fixed-link {
		};
	};

Case 7 (MDIO bus not described, connected to a different bus's phy):

	ethernet {
		status = "okay";
		phy-handle = <&phy1>;
		phy-mode = "rgmii";
	};

Case 8 (MDIO bus not described, but phy on MDIO bus is connected to MAC,
        legacy description[2] in my commit message):

	ethernet {
		status = "okay";
	};


If we look at the logic in stmmac today about how to handle the MDIO
bus, you've got basically:

	if !fixed-link || mdio_node_present()
		of_mdiobus_register(np)

Applying current stmmac logic to our cases...

Case 1 (MDIO bus used with phy on bus connected to MAC):
    MDIO bus made, no unnecessary scanning

Case 2 (MDIO bus used but MAC's fixed-link):
    MDIO bus made, no unnecessary scanning

Case 3 (MDIO bus used but MAC's connected to another bus's phy):
    MDIO bus made, no unnecessary scanning

Case 4 (MDIO bus disabled/unused, connected fixed-link):
    MDIO bus attempted to be made, fails -ENODEV due to disabled
    and stmmac returns -ENODEV from probe too

Case 5 (MDIO bus disabled/unused, connected to another bus's phy):
    MDIO bus attempted to be made, fails -ENODEV due to disabled
    and stmmac returns -ENODEV from probe too

Case 6 (MDIO bus not described, connected fixed-link):
    MDIO bus not created

Case 7 (MDIO bus not described, connected to a different bus's phy):
    MDIO bus created, but the whole bus is scanned

Case 8 (MDIO bus not described, but phy on MDIO bus is connected to MAC,
        legacy description[2] in my commit message):
    MDIO bus created, the whole bus is scanned and the undescribed but
    necessary phy is found


The things I note of interest are cases 4, 5, 7, 8. Cases 4/5 are a bug in
stmmac IMO, which breaks the devicetree description you mentioned as
ideal in my case. Case 7 is the one I'm currently working with, and the
devicetree can be updated to match case 5, but right now case 7 makes a
bus and scans it needlessly which isn't great. It _sounds_ like to me
Serge knows of stmmac variants that also *do not* have an MDIO controller,
so they'd fall in this case too and really shouldn't create a bus. Case 8
is the legacy one that I wish didn't exist, but it does, and for that
reason we should continue to make a bus and scan the whole thing if we can't
figure out what the MAC's connected to.

So in my opinion there's 3 changes I want to make based on all the
use cases I could think of:

    1. This patch, which improves the stmmac logic and stops making
       a bus for case 7
    2. A new patch to gracefully handle cases 4/5, where currently if the
       MDIO bus is disabled in the devicetree, as it should be,
       stmmac handles -ENODEV from of_mdiobus_register() as a failure
       instead of gracefully continuing knowing this is fine and dandy.
    3. Clean up the sa8775p dts to have the MDIO bus described in the
       SoC dtsi and left disabled instead of undescribed (a more
       accurate hardware description).

Please let me know if you see any holes in my logic, hopefully the
wall of text is useful in explaining how I got here.

Thanks,
Andrew
  

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 1ffde555da47..7da461fe93f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -296,69 +296,39 @@  static int stmmac_mtl_setup(struct platform_device *pdev,
 }
 
 /**
- * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
- * @plat: driver data platform structure
- * @np: device tree node
- * @dev: device pointer
- * Description:
- * The mdio bus will be allocated in case of a phy transceiver is on board;
- * it will be NULL if the fixed-link is configured.
- * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
- * in any case (for DSA, mdio must be registered even if fixed-link).
- * The table below sums the supported configurations:
- *	-------------------------------
- *	snps,phy-addr	|     Y
- *	-------------------------------
- *	phy-handle	|     Y
- *	-------------------------------
- *	fixed-link	|     N
- *	-------------------------------
- *	snps,dwmac-mdio	|
- *	  even if	|     Y
- *	fixed-link	|
- *	-------------------------------
+ * stmmac_of_get_mdio() - Gets the MDIO bus from the devicetree
+ * @np: devicetree node
  *
- * It returns 0 in case of success otherwise -ENODEV.
+ * The MDIO bus will be searched for in the following ways:
+ * 1. The compatible is "snps,dwc-qos-ethernet-4.10" && a "mdio" named
+ *    child node exists
+ * 2. A child node with the "snps,dwmac-mdio" compatible is present
+ *
+ * Return: The MDIO node if present otherwise NULL
  */
-static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
-			 struct device_node *np, struct device *dev)
+static struct device_node *stmmac_of_get_mdio(struct device_node *np)
 {
-	bool mdio = !of_phy_is_fixed_link(np);
 	static const struct of_device_id need_mdio_ids[] = {
 		{ .compatible = "snps,dwc-qos-ethernet-4.10" },
 		{},
 	};
+	struct device_node *mdio_node = NULL;
 
 	if (of_match_node(need_mdio_ids, np)) {
-		plat->mdio_node = of_get_child_by_name(np, "mdio");
+		mdio_node = of_get_child_by_name(np, "mdio");
 	} else {
 		/**
 		 * If snps,dwmac-mdio is passed from DT, always register
 		 * the MDIO
 		 */
-		for_each_child_of_node(np, plat->mdio_node) {
-			if (of_device_is_compatible(plat->mdio_node,
+		for_each_child_of_node(np, mdio_node) {
+			if (of_device_is_compatible(mdio_node,
 						    "snps,dwmac-mdio"))
 				break;
 		}
 	}
 
-	if (plat->mdio_node) {
-		dev_dbg(dev, "Found MDIO subnode\n");
-		mdio = true;
-	}
-
-	if (mdio) {
-		plat->mdio_bus_data =
-			devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
-				     GFP_KERNEL);
-		if (!plat->mdio_bus_data)
-			return -ENOMEM;
-
-		plat->mdio_bus_data->needs_reset = true;
-	}
-
-	return 0;
+	return mdio_node;
 }
 
 /**
@@ -417,6 +387,7 @@  stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
 	struct device_node *np = pdev->dev.of_node;
 	struct plat_stmmacenet_data *plat;
 	struct stmmac_dma_cfg *dma_cfg;
+	bool legacy_mdio;
 	int phy_mode;
 	void *ret;
 	int rc;
@@ -471,10 +442,28 @@  stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
 	if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
 		dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
 
-	/* To Configure PHY by using all device-tree supported properties */
-	rc = stmmac_dt_phy(plat, np, &pdev->dev);
-	if (rc)
-		return ERR_PTR(rc);
+	plat->mdio_node = stmmac_of_get_mdio(np);
+	if (plat->mdio_node)
+		dev_dbg(&pdev->dev, "Found MDIO subnode\n");
+
+	/* Legacy devicetrees allowed for no MDIO bus description and expect
+	 * the bus to be scanned for devices. If there's no phy or fixed-link
+	 * described assume this is the case since there must be something
+	 * connected to the MAC.
+	 */
+	legacy_mdio = !of_phy_is_fixed_link(np) && !plat->phy_node;
+	if (legacy_mdio)
+		dev_info(&pdev->dev, "Deprecated MDIO bus assumption used\n");
+
+	if (plat->mdio_node || legacy_mdio) {
+		plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
+						   sizeof(struct stmmac_mdio_bus_data),
+						   GFP_KERNEL);
+		if (!plat->mdio_bus_data)
+			return ERR_PTR(-ENOMEM);
+
+		plat->mdio_bus_data->needs_reset = true;
+	}
 
 	of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);