All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Horman <horms@kernel.org>
To: Vincent Guittot <vincent.guittot@linaro.org>
Cc: vkoul@kernel.org, neil.armstrong@linaro.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, ciprianmarian.costea@oss.nxp.com,
	s32@nxp.com, p.zabel@pengutronix.de, linux@armlinux.org.uk,
	ghennadi.procopciuc@nxp.com, bogdan-gabriel.roman@nxp.com,
	Ionut.Vicovan@nxp.com, alexandru-catalin.ionita@nxp.com,
	linux-phy@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
	Frank.li@nxp.com
Subject: Re: [PATCH 2/4] phy: s32g: Add serdes subsystem phy
Date: Thu, 29 Jan 2026 09:54:13 +0000	[thread overview]
Message-ID: <aXsuRTZUUnw0kdzV@horms.kernel.org> (raw)
In-Reply-To: <20260126092159.815968-3-vincent.guittot@linaro.org>

On Mon, Jan 26, 2026 at 10:21:57AM +0100, Vincent Guittot wrote:

...

> diff --git a/drivers/phy/freescale/phy-nxp-s32g-serdes.c b/drivers/phy/freescale/phy-nxp-s32g-serdes.c
> new file mode 100644
> index 000000000000..8336c868c8dc
> --- /dev/null
> +++ b/drivers/phy/freescale/phy-nxp-s32g-serdes.c
> @@ -0,0 +1,569 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * SerDes driver for S32G SoCs
> + *
> + * Copyright 2021-2026 NXP
> + */
> +
> +#include <dt-bindings/phy/phy.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>

Hi Vincent, all,

I think that you also need:

#include <linux/iopoll.h>

So that read_poll_timeout() is declared.
Else this patch causes a transient build failure
(for x86_64 allmodconfig)

> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/processor.h>
> +#include <linux/reset.h>
> +#include <linux/units.h>

...

> +static int s32g_serdes_phy_set_mode_ext(struct phy *p,
> +					enum phy_mode mode, int submode)
> +{
> +	struct s32g_serdes *serdes = phy_get_drvdata(p);
> +
> +	if (mode == PHY_MODE_PCIE)
> +		return -EINVAL;

This is part of an AI Generated review.
I have looked over it and I think it warrants investigation.
For information on how to reproduce locally, as I did, please see [1].

[1] https://netdev-ai.bots.linux.dev/ai-local.html

  This returns error if mode IS PHY_MODE_PCIE, but this is a PCIe PHY!
  This looks like a typo. Should be !=.

> +
> +	if (!is_pcie_phy_mode_valid(submode))
> +		return -EINVAL;
> +
> +	/*
> +	 * Do not configure SRIS or CRSS PHY MODE in conjunction
> +	 * with any SGMII mode on the same SerDes subsystem
> +	 */
> +	if ((submode == CRSS || submode == SRIS) &&
> +	    serdes->ctrl.ss_mode != 0)
> +		return -EINVAL;
> +
> +	/*
> +	 * Internal reference clock cannot be used with either Common clock
> +	 * or Spread spectrum, leaving only SRNSS
> +	 */
> +	if (submode != SRNS &&  !serdes->ctrl.ext_clk)
> +		return -EINVAL;
> +
> +	serdes->pcie.phy_mode = submode;

The AI review also suggested that it may be unsafe
to set the submode after s32g_serdes_phy_power_on()
has been called. And that there is nothing preventing that.

TBH, I am unsure if either of those statements are true.
But it seems worth validating with you.

> +
> +	return 0;
> +}

...

> +static int s32g_serdes_get_ctrl_resources(struct platform_device *pdev, struct s32g_serdes *serdes)
> +{
> +	struct s32g_serdes_ctrl *ctrl = &serdes->ctrl;
> +	struct device *dev = &pdev->dev;
> +	int ret, idx;
> +
> +	ret = of_property_read_u32(dev->of_node, "nxp,sys-mode",
> +				   &ctrl->ss_mode);
> +	if (ret) {
> +		dev_err(dev, "Failed to get SerDes subsystem mode\n");
> +		return -EINVAL;
> +	}
> +
> +	if (ctrl->ss_mode > S32G_SERDES_MODE_MAX) {
> +		dev_err(dev, "Invalid SerDes subsystem mode %u\n",
> +			ctrl->ss_mode);
> +		return -EINVAL;
> +	}
> +
> +	ctrl->ss_base = devm_platform_ioremap_resource_byname(pdev, "ss_pcie");
> +	if (IS_ERR(ctrl->ss_base)) {
> +		dev_err(dev, "Failed to map 'ss_pcie'\n");
> +		return PTR_ERR(ctrl->ss_base);
> +	}
> +
> +	ctrl->rst = devm_reset_control_get(dev, "serdes");
> +	if (IS_ERR(ctrl->rst))
> +		return dev_err_probe(dev, PTR_ERR(ctrl->rst),
> +				     "Failed to get 'serdes' reset control\n");
> +
> +	ctrl->nclks = devm_clk_bulk_get_all(dev, &ctrl->clks);
> +	if (ctrl->nclks < 1)
> +		return dev_err_probe(dev, ctrl->nclks,
> +				     "Failed to get SerDes clocks\n");

If devm_clk_bulk_get_all returns 0 then this value will
be passed to dev_err_probe(). And 0 will, in turn be returned by
dev_err_probe() and this function. However, that will be treated
as success by the caller, even though this is an error condition.

Perhaps something like this is more appropriate if ctrl->nclks
must be greater than 0. (Completely untested!)

	if (ctrl->nclks < 1) {
		ret = ctrl->nclks ? : -EINVAL;
		return dev_err_probe(dev, ret,
				     "Failed to get SerDes clocks\n");
	}

Flagged by Smatch.

...

> +static int s32g_serdes_parse_lanes(struct device *dev, struct s32g_serdes *serdes)
> +{
> +	int ret;
> +
> +	for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> +		ret = s32g2_serdes_create_phy(serdes, of_port);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;

Perhaps it cannot occur.
But if the loop above iterates zero times,
then ret will be used uninitialised here.

Also flagged by Smatch.

> +}
> +
> +static int s32g_serdes_probe(struct platform_device *pdev)
> +{
> +	struct s32g_serdes *serdes;
> +	struct device *dev = &pdev->dev;
> +	int ret;
> +
> +	serdes = devm_kzalloc(dev, sizeof(*serdes), GFP_KERNEL);
> +	if (!serdes)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, serdes);
> +	serdes->dev = dev;
> +
> +	ret = s32g_serdes_get_ctrl_resources(pdev, serdes);
> +	if (ret)
> +		return ret;
> +
> +	ret = s32g_serdes_get_pcie_resources(pdev, serdes);
> +	if (ret)
> +		return ret;
> +
> +	ret = s32g_serdes_parse_lanes(dev, serdes);
> +	if (ret)
> +		return ret;

The I review also says:

  The probe function calls s32g_serdes_init() which enables clocks,
  configures hardware, and deasserts reset. However,
  s32g_serdes_parse_lanes() creates PHY providers via
  devm_of_phy_provider_register().

  Problem: PHY consumers can start calling PHY ops (like power_on) as soon
  as the provider is registered, but the hardware isn't initialized until
  s32g_serdes_init() runs afterward. This creates a race window.

  Recommendation: Move s32g_serdes_init() before s32g_serdes_parse_lanes().

> +
> +	ret = s32g_serdes_init(serdes);
> +
> +	return ret;

nit: This could be more succinctly written as:

	return s32g_serdes_init(serdes);

> +}

...


WARNING: multiple messages have this Message-ID (diff)
From: Simon Horman <horms@kernel.org>
To: Vincent Guittot <vincent.guittot@linaro.org>
Cc: vkoul@kernel.org, neil.armstrong@linaro.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, ciprianmarian.costea@oss.nxp.com,
	s32@nxp.com, p.zabel@pengutronix.de, linux@armlinux.org.uk,
	ghennadi.procopciuc@nxp.com, bogdan-gabriel.roman@nxp.com,
	Ionut.Vicovan@nxp.com, alexandru-catalin.ionita@nxp.com,
	linux-phy@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
	Frank.li@nxp.com
Subject: Re: [PATCH 2/4] phy: s32g: Add serdes subsystem phy
Date: Thu, 29 Jan 2026 09:54:13 +0000	[thread overview]
Message-ID: <aXsuRTZUUnw0kdzV@horms.kernel.org> (raw)
In-Reply-To: <20260126092159.815968-3-vincent.guittot@linaro.org>

On Mon, Jan 26, 2026 at 10:21:57AM +0100, Vincent Guittot wrote:

...

> diff --git a/drivers/phy/freescale/phy-nxp-s32g-serdes.c b/drivers/phy/freescale/phy-nxp-s32g-serdes.c
> new file mode 100644
> index 000000000000..8336c868c8dc
> --- /dev/null
> +++ b/drivers/phy/freescale/phy-nxp-s32g-serdes.c
> @@ -0,0 +1,569 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * SerDes driver for S32G SoCs
> + *
> + * Copyright 2021-2026 NXP
> + */
> +
> +#include <dt-bindings/phy/phy.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>

Hi Vincent, all,

I think that you also need:

#include <linux/iopoll.h>

So that read_poll_timeout() is declared.
Else this patch causes a transient build failure
(for x86_64 allmodconfig)

> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/processor.h>
> +#include <linux/reset.h>
> +#include <linux/units.h>

...

> +static int s32g_serdes_phy_set_mode_ext(struct phy *p,
> +					enum phy_mode mode, int submode)
> +{
> +	struct s32g_serdes *serdes = phy_get_drvdata(p);
> +
> +	if (mode == PHY_MODE_PCIE)
> +		return -EINVAL;

This is part of an AI Generated review.
I have looked over it and I think it warrants investigation.
For information on how to reproduce locally, as I did, please see [1].

[1] https://netdev-ai.bots.linux.dev/ai-local.html

  This returns error if mode IS PHY_MODE_PCIE, but this is a PCIe PHY!
  This looks like a typo. Should be !=.

> +
> +	if (!is_pcie_phy_mode_valid(submode))
> +		return -EINVAL;
> +
> +	/*
> +	 * Do not configure SRIS or CRSS PHY MODE in conjunction
> +	 * with any SGMII mode on the same SerDes subsystem
> +	 */
> +	if ((submode == CRSS || submode == SRIS) &&
> +	    serdes->ctrl.ss_mode != 0)
> +		return -EINVAL;
> +
> +	/*
> +	 * Internal reference clock cannot be used with either Common clock
> +	 * or Spread spectrum, leaving only SRNSS
> +	 */
> +	if (submode != SRNS &&  !serdes->ctrl.ext_clk)
> +		return -EINVAL;
> +
> +	serdes->pcie.phy_mode = submode;

The AI review also suggested that it may be unsafe
to set the submode after s32g_serdes_phy_power_on()
has been called. And that there is nothing preventing that.

TBH, I am unsure if either of those statements are true.
But it seems worth validating with you.

> +
> +	return 0;
> +}

...

> +static int s32g_serdes_get_ctrl_resources(struct platform_device *pdev, struct s32g_serdes *serdes)
> +{
> +	struct s32g_serdes_ctrl *ctrl = &serdes->ctrl;
> +	struct device *dev = &pdev->dev;
> +	int ret, idx;
> +
> +	ret = of_property_read_u32(dev->of_node, "nxp,sys-mode",
> +				   &ctrl->ss_mode);
> +	if (ret) {
> +		dev_err(dev, "Failed to get SerDes subsystem mode\n");
> +		return -EINVAL;
> +	}
> +
> +	if (ctrl->ss_mode > S32G_SERDES_MODE_MAX) {
> +		dev_err(dev, "Invalid SerDes subsystem mode %u\n",
> +			ctrl->ss_mode);
> +		return -EINVAL;
> +	}
> +
> +	ctrl->ss_base = devm_platform_ioremap_resource_byname(pdev, "ss_pcie");
> +	if (IS_ERR(ctrl->ss_base)) {
> +		dev_err(dev, "Failed to map 'ss_pcie'\n");
> +		return PTR_ERR(ctrl->ss_base);
> +	}
> +
> +	ctrl->rst = devm_reset_control_get(dev, "serdes");
> +	if (IS_ERR(ctrl->rst))
> +		return dev_err_probe(dev, PTR_ERR(ctrl->rst),
> +				     "Failed to get 'serdes' reset control\n");
> +
> +	ctrl->nclks = devm_clk_bulk_get_all(dev, &ctrl->clks);
> +	if (ctrl->nclks < 1)
> +		return dev_err_probe(dev, ctrl->nclks,
> +				     "Failed to get SerDes clocks\n");

If devm_clk_bulk_get_all returns 0 then this value will
be passed to dev_err_probe(). And 0 will, in turn be returned by
dev_err_probe() and this function. However, that will be treated
as success by the caller, even though this is an error condition.

Perhaps something like this is more appropriate if ctrl->nclks
must be greater than 0. (Completely untested!)

	if (ctrl->nclks < 1) {
		ret = ctrl->nclks ? : -EINVAL;
		return dev_err_probe(dev, ret,
				     "Failed to get SerDes clocks\n");
	}

Flagged by Smatch.

...

> +static int s32g_serdes_parse_lanes(struct device *dev, struct s32g_serdes *serdes)
> +{
> +	int ret;
> +
> +	for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> +		ret = s32g2_serdes_create_phy(serdes, of_port);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;

Perhaps it cannot occur.
But if the loop above iterates zero times,
then ret will be used uninitialised here.

Also flagged by Smatch.

> +}
> +
> +static int s32g_serdes_probe(struct platform_device *pdev)
> +{
> +	struct s32g_serdes *serdes;
> +	struct device *dev = &pdev->dev;
> +	int ret;
> +
> +	serdes = devm_kzalloc(dev, sizeof(*serdes), GFP_KERNEL);
> +	if (!serdes)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, serdes);
> +	serdes->dev = dev;
> +
> +	ret = s32g_serdes_get_ctrl_resources(pdev, serdes);
> +	if (ret)
> +		return ret;
> +
> +	ret = s32g_serdes_get_pcie_resources(pdev, serdes);
> +	if (ret)
> +		return ret;
> +
> +	ret = s32g_serdes_parse_lanes(dev, serdes);
> +	if (ret)
> +		return ret;

The I review also says:

  The probe function calls s32g_serdes_init() which enables clocks,
  configures hardware, and deasserts reset. However,
  s32g_serdes_parse_lanes() creates PHY providers via
  devm_of_phy_provider_register().

  Problem: PHY consumers can start calling PHY ops (like power_on) as soon
  as the provider is registered, but the hardware isn't initialized until
  s32g_serdes_init() runs afterward. This creates a race window.

  Recommendation: Move s32g_serdes_init() before s32g_serdes_parse_lanes().

> +
> +	ret = s32g_serdes_init(serdes);
> +
> +	return ret;

nit: This could be more succinctly written as:

	return s32g_serdes_init(serdes);

> +}

...

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

  parent reply	other threads:[~2026-01-29  9:54 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-26  9:21 [PATCH 0/4] Serdes: s32g: Add support for serdes subsystem Vincent Guittot
2026-01-26  9:21 ` Vincent Guittot
2026-01-26  9:21 ` [PATCH 1/4] dt-bindings: serdes: s32g: Add NXP " Vincent Guittot
2026-01-26  9:21   ` Vincent Guittot
2026-01-29 12:50   ` Russell King (Oracle)
2026-01-29 12:50     ` Russell King (Oracle)
2026-01-29 13:05     ` Vincent Guittot
2026-01-29 13:05       ` Vincent Guittot
2026-01-26  9:21 ` [PATCH 2/4] phy: s32g: Add serdes subsystem phy Vincent Guittot
2026-01-26  9:21   ` Vincent Guittot
2026-01-26 13:11   ` Philipp Zabel
2026-01-26 13:11     ` Philipp Zabel
2026-01-27 10:07     ` Vincent Guittot
2026-01-27 10:07       ` Vincent Guittot
2026-01-29  9:54   ` Simon Horman [this message]
2026-01-29  9:54     ` Simon Horman
2026-01-29 13:01     ` Vincent Guittot
2026-01-29 13:01       ` Vincent Guittot
2026-01-29 13:23       ` Russell King (Oracle)
2026-01-29 13:23         ` Russell King (Oracle)
2026-01-29 13:36         ` Vincent Guittot
2026-01-29 13:36           ` Vincent Guittot
2026-01-29 13:51           ` Russell King (Oracle)
2026-01-29 13:51             ` Russell King (Oracle)
2026-01-29 14:30             ` Vinod Koul
2026-01-29 14:30               ` Vinod Koul
2026-01-29 14:36               ` Russell King (Oracle)
2026-01-29 14:36                 ` Russell King (Oracle)
2026-01-30 14:50                 ` Russell King (Oracle)
2026-01-30 14:50                   ` Russell King (Oracle)
2026-01-29 11:17   ` Russell King (Oracle)
2026-01-29 11:17     ` Russell King (Oracle)
2026-01-29 13:02     ` Vincent Guittot
2026-01-29 13:02       ` Vincent Guittot
2026-01-26  9:21 ` [PATCH 3/4] phy: s32g: Add serdes xpcs subsystem Vincent Guittot
2026-01-26  9:21   ` Vincent Guittot
2026-01-29 11:59   ` Simon Horman
2026-01-29 11:59     ` Simon Horman
2026-01-29 13:24     ` Vincent Guittot
2026-01-29 13:24       ` Vincent Guittot
2026-01-29 16:20       ` Simon Horman
2026-01-29 16:20         ` Simon Horman
2026-01-29 12:30   ` Russell King (Oracle)
2026-01-29 12:30     ` Russell King (Oracle)
2026-01-29 13:45     ` Vincent Guittot
2026-01-29 13:45       ` Vincent Guittot
2026-01-26  9:21 ` [PATCH 4/4] MAINTAINERS: Add MAINTAINER for NXP S32G Serdes driver Vincent Guittot
2026-01-26  9:21   ` Vincent Guittot
2026-01-29 12:07   ` Simon Horman
2026-01-29 12:07     ` Simon Horman
2026-01-29 13:25     ` Vincent Guittot
2026-01-29 13:25       ` Vincent Guittot
2026-01-29 12:36 ` [PATCH 0/4] Serdes: s32g: Add support for serdes subsystem Russell King (Oracle)
2026-01-29 12:36   ` Russell King (Oracle)
2026-01-29 13:26   ` Vincent Guittot
2026-01-29 13:26     ` Vincent Guittot

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=aXsuRTZUUnw0kdzV@horms.kernel.org \
    --to=horms@kernel.org \
    --cc=Frank.li@nxp.com \
    --cc=Ionut.Vicovan@nxp.com \
    --cc=alexandru-catalin.ionita@nxp.com \
    --cc=bogdan-gabriel.roman@nxp.com \
    --cc=ciprianmarian.costea@oss.nxp.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=ghennadi.procopciuc@nxp.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-phy@lists.infradead.org \
    --cc=linux@armlinux.org.uk \
    --cc=neil.armstrong@linaro.org \
    --cc=netdev@vger.kernel.org \
    --cc=p.zabel@pengutronix.de \
    --cc=s32@nxp.com \
    --cc=vincent.guittot@linaro.org \
    --cc=vkoul@kernel.org \
    /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.