All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: Muralidhara M K <muralidhara.mk@amd.com>
Cc: muthusamy.ramalingam@amd.com,
	platform-driver-x86@vger.kernel.org,
	 LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 5/7] platform/x86/amd/hsmp: Serialize the data plane against socket teardown
Date: Mon, 6 Jul 2026 14:41:03 +0300 (EEST)	[thread overview]
Message-ID: <0c56c0bc-a14d-dc75-9897-b70127c8e991@linux.intel.com> (raw)
In-Reply-To: <20260625123337.886435-6-muralidhara.mk@amd.com>

On Thu, 25 Jun 2026, Muralidhara M K wrote:

> The HSMP data plane is lock-free: open /dev/hsmp fds and hwmon sysfs
> reads call hsmp_send_message() without any coordination with driver
> teardown.  misc_deregister() does not drain already-open fds, so an
> in-flight message can race a concurrent unbind and touch a freed socket
> array or an unmapped mailbox.
> 
> Add hsmp_sock_rwsem.  hsmp_send_message() now holds it for read across
> the whole bounds-check + MMIO access, and hsmp_sock_teardown_lock()/
> hsmp_sock_teardown_unlock() let a teardown path hold it for write to
> drain any in-flight message and keep new ones out while it tears the
> socket down.
> 
> Wire the non-ACPI platform path into the drain: hsmp_pltdrv_remove()
> and the probe-failure cleanup take the write lock and drop the global
> socket pointer before devres frees the devm_kcalloc() array.  num_sockets
> is left intact so a later rebind can re-create the array.
> 
> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> ---
>  drivers/platform/x86/amd/hsmp/hsmp.c | 55 +++++++++++++++++++++++++---
>  drivers/platform/x86/amd/hsmp/hsmp.h |  2 +
>  drivers/platform/x86/amd/hsmp/plat.c | 23 ++++++++++++
>  3 files changed, 74 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
> index c3939908d95f..c15acba241c4 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.c
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.c
> @@ -15,6 +15,7 @@
>  #include <linux/io.h>
>  #include <linux/mutex.h>
>  #include <linux/nospec.h>
> +#include <linux/rwsem.h>
>  #include <linux/semaphore.h>
>  #include <linux/slab.h>
>  #include <linux/sysfs.h>
> @@ -44,6 +45,16 @@
>  
>  static struct hsmp_plat_device hsmp_pdev;
>  
> +/*
> + * Serializes the lock-free data plane (hsmp_send_message() and the per-socket
> + * MMIO access it performs) against socket teardown.  Callers of the data plane
> + * hold it for read so multiple sockets can be driven concurrently; ACPI
> + * removal holds it for write while it clears sock->dev,

I don't see acpi change in this patch (just hsmp_send_message and plat 
changes)???

> frees the socket array
> + * and unmaps the mailbox, so a reader can never observe a half-torn-down or
> + * freed socket.
> + */
> +static DECLARE_RWSEM(hsmp_sock_rwsem);
> +
>  /*
>   * Send a message to the HSMP port via PCI-e config space registers
>   * or by writing to MMIO space.
> @@ -215,8 +226,19 @@ int hsmp_send_message(struct hsmp_message *msg)
>  	if (ret)
>  		return ret;
>  
> -	if (!hsmp_pdev.sock || msg->sock_ind >= hsmp_pdev.num_sockets)
> -		return -ENODEV;
> +	/*
> +	 * Hold the teardown rwsem for read across the whole MMIO access.  ACPI
> +	 * removal takes it for write before clearing sock->dev, freeing the
> +	 * socket array and unmapping the mailbox, so the lock-free data plane
> +	 * (open /dev/hsmp fds and hwmon sysfs reads) can never dereference a
> +	 * freed socket or touch an unmapped mailbox.
> +	 */
> +	down_read(&hsmp_sock_rwsem);
> +
> +	if (!hsmp_pdev.sock || msg->sock_ind >= hsmp_pdev.num_sockets) {
> +		ret = -ENODEV;
> +		goto out_unlock;
> +	}
>  
>  	/*
>  	 * Sanitize sock_ind after the bounds check.  A mispredicted branch can
> @@ -235,18 +257,22 @@ int hsmp_send_message(struct hsmp_message *msg)
>  	 * semaphore or an unmapped mailbox.  A non-NULL dev also guarantees
>  	 * virt_base_addr, the mailbox offsets and the semaphore are visible.
>  	 */
> -	/* Pairs with smp_store_release(&sock->dev) in hsmp_parse_acpi_table(). */
> -	if (!smp_load_acquire(&sock->dev))
> -		return -ENODEV;
> +	/* Held under hsmp_sock_rwsem; pairs with smp_store_release(&sock->dev). */
> +	if (!smp_load_acquire(&sock->dev)) {
> +		ret = -ENODEV;
> +		goto out_unlock;
> +	}
>  
>  	ret = down_interruptible(&sock->hsmp_sem);
>  	if (ret < 0)
> -		return ret;
> +		goto out_unlock;
>  
>  	ret = __hsmp_send_message(sock, msg);
>  
>  	up(&sock->hsmp_sem);
>  
> +out_unlock:
> +	up_read(&hsmp_sock_rwsem);

Don't add unlock labels at the end but please use cleanup.h. It will 
simplify the patch too as you don't need to alter those direct returns.

>  	return ret;
>  }
>  EXPORT_SYMBOL_NS_GPL(hsmp_send_message, "AMD_HSMP");
> @@ -529,6 +555,23 @@ struct hsmp_plat_device *get_hsmp_pdev(void)
>  }
>  EXPORT_SYMBOL_NS_GPL(get_hsmp_pdev, "AMD_HSMP");
>  
> +/*
> + * Take the write side of the data-plane rwsem.  A caller tearing a socket down
> + * uses this to drain any in-flight hsmp_send_message() and to keep new ones out
> + * while it clears sock->dev, frees the socket array or unmaps the mailbox.
> + */
> +void hsmp_sock_teardown_lock(void)
> +{
> +	down_write(&hsmp_sock_rwsem);
> +}
> +EXPORT_SYMBOL_NS_GPL(hsmp_sock_teardown_lock, "AMD_HSMP");
> +
> +void hsmp_sock_teardown_unlock(void)
> +{
> +	up_write(&hsmp_sock_rwsem);
> +}
> +EXPORT_SYMBOL_NS_GPL(hsmp_sock_teardown_unlock, "AMD_HSMP");

Just export the lock to be taken directly in plat/acpi. It's much easier 
to follow who locks what when you don't add wrappers like this.

I don't understand why acpi doesn't use write side of this lock though 
but has it's own lock (hsmp_acpi_probe_mutex)?

>  MODULE_DESCRIPTION("AMD HSMP Common driver");
>  MODULE_VERSION(DRIVER_VERSION);
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
> index 91bc21232646..5d0a6d819865 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.h
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.h
> @@ -70,6 +70,8 @@ void hsmp_init_metric_read_locks(struct hsmp_plat_device *pdev, u16 num_sockets)
>  ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size);
>  void hsmp_destroy_metric_read_locks(struct hsmp_plat_device *pdev, u16 num_sockets);
>  struct hsmp_plat_device *get_hsmp_pdev(void);
> +void hsmp_sock_teardown_lock(void);
> +void hsmp_sock_teardown_unlock(void);
>  #if IS_ENABLED(CONFIG_HWMON)
>  int hsmp_create_sensor(struct device *dev, u16 sock_ind);
>  #else
> diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c
> index 685f2d2c574b..26c1363e79a1 100644
> --- a/drivers/platform/x86/amd/hsmp/plat.c
> +++ b/drivers/platform/x86/amd/hsmp/plat.c
> @@ -233,15 +233,38 @@ static int hsmp_pltdrv_probe(struct platform_device *pdev)
>  	 * init_platform_device() may have ioremap()ed metric tables before
>  	 * failing.  hsmp_destroy_metric_read_locks() unmaps them and tears
>  	 * down the per-socket mutexes; the socket array itself is devm-managed.
> +	 *
> +	 * init_platform_device() also runs the data plane (hsmp_test()), so
> +	 * drain it via the teardown rwsem and drop the global socket pointer
> +	 * before devres frees the array.  num_sockets is left intact: it is
> +	 * only computed once in __init (amd_num_nodes()) and is needed to
> +	 * re-create the array on a later rebind.
>  	 */
> +	hsmp_sock_teardown_lock();
>  	hsmp_destroy_metric_read_locks(hsmp_pdev, hsmp_pdev->num_sockets);
> +	hsmp_pdev->sock = NULL;
> +	hsmp_sock_teardown_unlock();
>  	return ret;
>  }
>  
>  static void hsmp_pltdrv_remove(struct platform_device *pdev)
>  {
> +	/*
> +	 * Drain the lock-free data plane and keep it out while the sockets are
> +	 * torn down.  misc_deregister() does not drain already-open /dev/hsmp
> +	 * fds and the driver permits sysfs unbind, so without this an in-flight
> +	 * hsmp_send_message() could touch the devres-freed socket array or an
> +	 * iounmap()ed metric table.  Dropping the global socket pointer makes
> +	 * later messages bail out at the first check.  num_sockets is left
> +	 * intact so an unbind/rebind cycle can re-create the array; it is only
> +	 * computed once in __init (amd_num_nodes()) and is never recomputed on
> +	 * probe.
> +	 */
> +	hsmp_sock_teardown_lock();
>  	hsmp_misc_deregister();
>  	hsmp_destroy_metric_read_locks(hsmp_pdev, hsmp_pdev->num_sockets);
> +	hsmp_pdev->sock = NULL;
> +	hsmp_sock_teardown_unlock();
>  }
>  
>  static struct platform_driver amd_hsmp_driver = {
> 

-- 
 i.


  reply	other threads:[~2026-07-06 11:41 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-25 12:33 [PATCH v2 0/7] platform/x86/amd/hsmp: ACPI/platform HSMP concurrency and lifecycle hardening Muralidhara M K
2026-06-25 12:33 ` [PATCH v2 1/7] platform/x86/amd/hsmp: Serialize ACPI HSMP is_probed with a probe mutex Muralidhara M K
2026-06-25 12:33 ` [PATCH v2 2/7] platform/x86/amd/hsmp: Validate ACPI UID and _DSD mailbox package Muralidhara M K
2026-06-26 10:03   ` Ilpo Järvinen
2026-06-25 12:33 ` [PATCH v2 3/7] platform/x86/amd/hsmp: Add explicit metric DRAM mapping and per-socket mutexes Muralidhara M K
2026-07-06 11:51   ` Ilpo Järvinen
2026-06-25 12:33 ` [PATCH v2 4/7] platform/x86/amd/hsmp: Gate the data plane on a fully initialized socket Muralidhara M K
2026-06-25 12:33 ` [PATCH v2 5/7] platform/x86/amd/hsmp: Serialize the data plane against socket teardown Muralidhara M K
2026-07-06 11:41   ` Ilpo Järvinen [this message]
2026-07-06 15:29     ` M K, Muralidhara
2026-06-25 12:33 ` [PATCH v2 6/7] platform/x86/amd/hsmp: ACPI HSMP refcounted sockets and coordinated release Muralidhara M K
2026-06-25 12:33 ` [PATCH v2 7/7] platform/x86/amd/hsmp: Drop stale metric table mapping on rebind Muralidhara M K

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=0c56c0bc-a14d-dc75-9897-b70127c8e991@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=muralidhara.mk@amd.com \
    --cc=muthusamy.ramalingam@amd.com \
    --cc=platform-driver-x86@vger.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.