From: Carlo Szelinsky <github@szelinsky.de>
To: Oleksij Rempel <o.rempel@pengutronix.de>,
Kory Maincent <kory.maincent@bootlin.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Corey Leavitt <corey@leavitt.info>,
Jonas Jelonek <jelonek.jonas@gmail.com>,
Simon Horman <horms@kernel.org>,
Aleksander Jan Bajkowski <olek2@wp.pl>,
Mark Brown <broonie@kernel.org>,
Liam Girdwood <lgirdwood@gmail.com>,
netdev-bot+sashiko@kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org,
Carlo Szelinsky <github@szelinsky.de>
Subject: [PATCH net-next v7 4/5] net: pse-pd: check the PI vpwr supply before registering the controller
Date: Sun, 27 Sep 2026 21:18:49 +0200 [thread overview]
Message-ID: <20260927191850.1370515-5-github@szelinsky.de> (raw)
In-Reply-To: <20260927191850.1370515-1-github@szelinsky.de>
Each PSE PI regulator is registered with a "vpwr" supply, which the
bindings expect the board to provide via vpwr-supply in the PI node. The
regulator core deliberately treats an unresolved supply at registration
time as non-fatal: it logs, registers a bus device so the supply can be
picked up later, and lets registration succeed.
That leaves pse_controller_register() completing for a controller whose
PIs cannot be handed out. regulator_get_exclusive() in
pse_control_get_internal() resolves the supply itself and returns
-EPROBE_DEFER until the provider appears, so of_pse_control_get() keeps
failing for this PI even though the controller is registered and
discoverable. A consumer that only retries on controller registration -
as the phy layer does after the next patch - then never gets its PI.
Check every PI's supply first, before any regulator of ours is
registered, so the error surfaces in the PSE driver's own probe and
deferred probe retries it there. The check skips exactly the PIs the
registration loop skips, so a controller with no pse-pis node - where
every PI has a NULL np but a regulator is still created for it - is
covered too, through the controller device rather than a PI node.
The check follows both stages regulator_resolve_supply() uses: the PI's
own node, then the controller device. Both are needed. of_get_regulator()
reads the node it is handed and otherwise walks that device's children,
so a vpwr-supply written once on the controller node - covering every PI
- is invisible from the PI node, while the core finds it at stage two.
Checking only the PI node would let exactly the case this patch exists
to prevent slip through unreported.
It is still not a full replica. The core also falls back to a dummy
under have_full_constraints(), which does not matter here because it
bails on an explicit -EPROBE_DEFER first, and it defers when the
provider's parent is not yet bound, which regulator_get_optional() does
not check. So a PSE probe interleaving with the provider's own probe can
still pass the check and resolve late. That window is narrower than the
one being closed - a provider that has not registered at all - and
closing it properly means asking the core about rdev->supply after
registration, which the unwind constraints above do not allow.
Doing all the checks before the registration loop also keeps the common
deferral on the unwind path that can release the PI array: a controller
can describe its PIs on different providers - ti,tps23881.yaml puts
pse-pi@0 on vpwr1 and pse-pi@1 on vpwr2 - so "one PI resolves, the next
defers" is the ordinary case, and checking inside the registration loop
would leave registered regulators behind on every retry.
This widens what a missing provider costs. Before, only the PI on that
supply failed, and only when a consumer asked for it; now the controller
itself defers, so a board whose PIs sit on different providers loses PSE
on all of them until the last one appears. That is the normal contract
for a regulator consumer, and the alternative - a controller that
advertises PIs it cannot hand out - is the bug being fixed. A provider
that never appears leaves the controller unbound rather than half
working, which deferred probe reports in the usual way.
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
drivers/net/pse-pd/pse_core.c | 72 +++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 16d75b4babf3..457eef5784f8 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/pse-pd/pse.h>
+#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/rtnetlink.h>
@@ -860,6 +861,67 @@ static const struct regulator_ops pse_pi_ops = {
.set_current_limit = pse_pi_set_current_limit,
};
+/* The regulator core treats an unresolved "vpwr" supply as non-fatal and
+ * retries it on its own later, which would leave this controller able to
+ * register while of_pse_control_get() still fails with -EPROBE_DEFER for
+ * this PI, and nothing to retry the consumer's attach. Check the supply
+ * up front so the PSE driver's own probe defers instead.
+ *
+ * of_regulator_get_optional() reports a PI with no vpwr-supply described
+ * as -ENODEV rather than falling back to the dummy regulator, and has a
+ * stub for CONFIG_OF=n. Those PIs keep their existing behaviour: the
+ * regulator core resolves them to the dummy when the PI regulator is
+ * registered.
+ */
+static int pse_pi_check_supply(struct pse_controller_dev *pcdev, int id)
+{
+ struct regulator *supply;
+ int ret;
+
+ /* Skip exactly the PIs the registration loop below skips, so every
+ * regulator that will be created is covered.
+ */
+ if (!pcdev->no_of_pse_pi && !pcdev->pi[id].np)
+ return 0;
+
+ /* Follow both stages regulator_resolve_supply() will use for the
+ * regulator about to be registered: the PI's own node first, then
+ * the controller device. Only -ENODEV moves on to the second stage;
+ * a provider that has not registered yet gives -EPROBE_DEFER, which
+ * is the case worth catching here.
+ */
+ if (pcdev->pi[id].np) {
+ supply = of_regulator_get_optional(pcdev->dev,
+ pcdev->pi[id].np, "vpwr");
+ if (!IS_ERR(supply)) {
+ regulator_put(supply);
+ return 0;
+ }
+
+ ret = PTR_ERR(supply);
+ if (ret != -ENODEV)
+ return dev_err_probe(pcdev->dev, ret,
+ "PI %d: failed to get vpwr supply\n",
+ id);
+ }
+
+ /* A vpwr-supply on the controller node covers every PI, and is
+ * where a PI without a node of its own resolves too.
+ */
+ supply = regulator_get_optional(pcdev->dev, "vpwr");
+ if (!IS_ERR(supply)) {
+ regulator_put(supply);
+ return 0;
+ }
+
+ ret = PTR_ERR(supply);
+ if (ret == -ENODEV)
+ return 0;
+
+ return dev_err_probe(pcdev->dev, ret,
+ "PI %d: failed to get vpwr supply\n", id);
+}
+
static int
devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
char *name, int id)
@@ -1111,6 +1173,16 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
*/
reg_name_len = strlen(dev_name(pcdev->dev)) + 18;
+ /* Check every PI supply before registering any regulator: a provider
+ * that has not probed yet is the ordinary -EPROBE_DEFER case, and
+ * unwinding it must not leave PI regulators behind.
+ */
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ ret = pse_pi_check_supply(pcdev, i);
+ if (ret)
+ goto release_pis;
+ }
+
/* Register PI regulators. Once one of these exists, pse_pi_ops index
* pcdev->pi[] and nothing here can unregister it again, so the array
* must outlive this function. Failures below therefore unwind to
--
2.43.0
next prev parent reply other threads:[~2026-09-27 19:19 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 19:18 [PATCH net-next v7 0/5] net: pse-pd: decouple controller lookup from MDIO probe Carlo Szelinsky
2026-09-27 19:18 ` [PATCH net-next v7 1/5] net: pse-pd: add notifier chain for controller lifecycle events Carlo Szelinsky
2026-09-27 19:18 ` [PATCH net-next v7 2/5] net: pse-pd: fire lifecycle events on controller register/unregister Carlo Szelinsky
2026-09-30 0:19 ` netdev-bot+sashiko
2026-09-27 19:18 ` [PATCH net-next v7 3/5] net: pse-pd: unwind allocations when controller registration fails Carlo Szelinsky
2026-09-30 0:19 ` netdev-bot+sashiko
2026-09-27 19:18 ` Carlo Szelinsky [this message]
2026-09-30 0:19 ` [PATCH net-next v7 4/5] net: pse-pd: check the PI vpwr supply before registering the controller netdev-bot+sashiko
2026-09-27 19:18 ` [PATCH net-next v7 5/5] net: phy: own phydev->psec via PSE notifier and remove fwnode_mdio hook Carlo Szelinsky
2026-09-30 0:19 ` netdev-bot+sashiko
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=20260927191850.1370515-5-github@szelinsky.de \
--to=github@szelinsky.de \
--cc=andrew+netdev@lunn.ch \
--cc=broonie@kernel.org \
--cc=corey@leavitt.info \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=horms@kernel.org \
--cc=jelonek.jonas@gmail.com \
--cc=kory.maincent@bootlin.com \
--cc=kuba@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev-bot+sashiko@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=o.rempel@pengutronix.de \
--cc=olek2@wp.pl \
--cc=pabeni@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®