From: Jakub Kicinski <kuba@kernel.org>
To: xuanqiang.luo@linux.dev
Cc: andrew@lunn.ch, richardcochran@gmail.com, hkallweit1@gmail.com,
linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com,
pabeni@redhat.com, maxime.chevallier@bootlin.com,
netdev@vger.kernel.org, Xuanqiang Luo <luoxuanqiang@kylinos.cn>
Subject: Re: [PATCH net v2] net: phy: dp83640: fix per-bus clock lifetime
Date: Mon, 3 Aug 2026 19:00:44 -0700 [thread overview]
Message-ID: <20260803190044.274355ea@kernel.org> (raw)
In-Reply-To: <20260730064451.32261-1-xuanqiang.luo@linux.dev>
On Thu, 30 Jul 2026 14:44:51 +0800 xuanqiang.luo@linux.dev wrote:
> From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
>
> Commit 42e2a9e11a1d ("net: phy: dp83640: improve phydev and driver
> removal handling") moved per-bus clock cleanup from module exit to the
> remove path. This leaves two lifetime problems.
>
> dp83640_clock_get_bus() publishes a newly allocated clock before the
> driver allocates its per-PHY data and registers the PTP clock. If either
> operation fails, no PHY is bound and the remove callback cannot release
> the clock, leaking the clock, its pin configuration, and the MII bus
> device reference.
>
> The remove path can also free a clock after dropping clock_lock. A
> concurrent probe may already have found the clock under
> phyter_clocks_lock and be waiting for clock_lock, allowing it to acquire
> a freed mutex and access the freed clock.
>
> Use the PHY package infrastructure for the per-bus clock. The package
> table is scoped to each MII bus and holds the shared object until the
> last joined PHY leaves. Serialize the one-time clock initialization with
> the bus shared lock because phy_package_probe_once() elects an
> initializer but does not wait for initialization to finish.
>
> Manage both the package reference and the per-PHY state with devres.
> This is needed because dp83640_probe() may succeed before later PHY core
> initialization fails, and the driver remove callback is not called for
> that failure. Register the per-PHY cleanup action after the package
> reference so probe unwinding first unregisters the PTP clock or removes
> the PHY from the clock list, then releases the shared clock. Release the
> same action from the normal remove path.
>
> Embed the pin configuration in the package private data so the final
> package leave releases all clock storage.
>
> Fixes: 42e2a9e11a1d ("net: phy: dp83640: improve phydev and driver removal handling")
> Suggested-by: Jakub Kicinski <kuba@kernel.org>
No need to add Suggested-by tags for review comments.
Only if the v1 was suggested by the person.
> +static int dp83640_probe(struct phy_device *phydev)
> +{
> struct dp83640_private *dp83640;
> + struct dp83640_clock *clock;
> int err = -ENOMEM, i;
>
> if (phydev->mdio.addr == BROADCAST_ADDR)
> return 0;
>
> - clock = dp83640_clock_get_bus(phydev->mdio.bus);
> - if (!clock)
> + err = devm_phy_package_join(&phydev->mdio.dev, phydev,
> + BROADCAST_ADDR, sizeof(*clock));
> + if (err)
> goto no_clock;
>
> + clock = phy_package_get_priv(phydev);
> + /* Ensure other PHY probes wait for shared clock initialization. */
> + mutex_lock(&phydev->mdio.bus->shared_lock);
> + if (phy_package_probe_once(phydev))
> + dp83640_clock_init(clock);
> + mutex_unlock(&phydev->mdio.bus->shared_lock);
> +
> + mutex_lock(&clock->clock_lock);
> +
> dp83640 = kzalloc_obj(struct dp83640_private);
> if (!dp83640)
AI reviewer points out that this error path is now missing setting
the err variable. Please clean this up as part of your change.
Remove the init to -ENOMEM and have every goto x; path set err
if it needs to
> goto no_memory;
> @@ -1450,24 +1432,31 @@ static int dp83640_probe(struct phy_device *phydev)
> } else
> list_add_tail(&dp83640->list, &clock->phylist);
>
> - dp83640_clock_put(clock);
> + mutex_unlock(&clock->clock_lock);
> +
> + err = devm_add_action_or_reset(&phydev->mdio.dev,
> + dp83640_phy_release, dp83640);
> + if (err)
> + return err;
> +
> return 0;
>
> no_register:
> clock->chosen = NULL;
> + clock->ptp_clock = NULL;
> + phydev->default_timestamp = false;
> + phydev->mii_ts = NULL;
> + phydev->priv = NULL;
> kfree(dp83640);
> no_memory:
> - dp83640_clock_put(clock);
> + mutex_unlock(&clock->clock_lock);
> no_clock:
> return err;
> }
>
> static void dp83640_remove(struct phy_device *phydev)
> {
> - struct dp83640_clock *clock;
> - struct list_head *this, *next;
> - struct dp83640_private *tmp, *dp83640 = phydev->priv;
> - bool remove_clock = false;
> + struct dp83640_private *dp83640 = phydev->priv;
>
> if (phydev->mdio.addr == BROADCAST_ADDR)
> return;
> @@ -1475,43 +1464,8 @@ static void dp83640_remove(struct phy_device *phydev)
> phydev->mii_ts = NULL;
>
> enable_status_frames(phydev, false);
> - cancel_delayed_work_sync(&dp83640->ts_work);
> -
> - skb_queue_purge(&dp83640->rx_queue);
> - skb_queue_purge(&dp83640->tx_queue);
> -
> - clock = dp83640_clock_get(dp83640->clock);
>
> - if (dp83640 == clock->chosen) {
> - ptp_clock_unregister(clock->ptp_clock);
> - clock->chosen = NULL;
> - } else {
> - list_for_each_safe(this, next, &clock->phylist) {
> - tmp = list_entry(this, struct dp83640_private, list);
> - if (tmp == dp83640) {
> - list_del_init(&tmp->list);
> - break;
> - }
> - }
> - }
> -
> - if (!clock->chosen && list_empty(&clock->phylist))
> - remove_clock = true;
> -
> - dp83640_clock_put(clock);
> - kfree(dp83640);
> -
> - if (remove_clock) {
> - mutex_lock(&phyter_clocks_lock);
> - list_del(&clock->list);
> - mutex_unlock(&phyter_clocks_lock);
> -
> - mutex_destroy(&clock->extreg_lock);
> - mutex_destroy(&clock->clock_lock);
> - put_device(&clock->bus->dev);
> - kfree(clock->caps.pin_config);
> - kfree(clock);
> - }
> + devm_release_action(&phydev->mdio.dev, dp83640_phy_release, dp83640);
Why the explicit call? if you're using devm_ you should let it handle
the unwind.. If you want to have an explicit call, don't use dev_ APIs.
--
pw-bot: cr
next prev parent reply other threads:[~2026-08-04 2:00 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 6:44 [PATCH net v2] net: phy: dp83640: fix per-bus clock lifetime xuanqiang.luo
2026-08-04 2:00 ` Jakub Kicinski [this message]
2026-08-04 8:33 ` luoxuanqiang
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=20260803190044.274355ea@kernel.org \
--to=kuba@kernel.org \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=linux@armlinux.org.uk \
--cc=luoxuanqiang@kylinos.cn \
--cc=maxime.chevallier@bootlin.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
--cc=xuanqiang.luo@linux.dev \
/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