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 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.