Unverified Commit 7d3135d1 authored by Suma Hegde's avatar Suma Hegde Committed by Ilpo Järvinen
Browse files

platform/x86/amd/hsmp: Create separate ACPI, plat and common drivers



Separate the probes for HSMP ACPI and platform device drivers.

Provide a Kconfig option to choose between ACPI or the platform device
based driver. The common code which is the core part of the HSMP driver
maintained at hsmp.c is guarded by AMD_HSMP config and is selected by
these two driver configs. This will be built into separate hsmp_common.ko
module and acpi as hsmp_acpi and plat as amd_hsmp respectively.

Also add "|| COMPILE_TEST" clause in Kconfig to get build coverage for
HSMP.

Signed-off-by: default avatarSuma Hegde <suma.hegde@amd.com>
Reviewed-by: default avatarNaveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
Link: https://lore.kernel.org/r/20241021111428.2676884-8-suma.hegde@amd.com


[ij: Fixed doc to use pre-formatted text for the ACPI dump.]
Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
parent 8e75dff5
Loading
Loading
Loading
Loading
+62 −5
Original line number Diff line number Diff line
@@ -4,8 +4,9 @@
AMD HSMP interface
============================================

Newer Fam19h EPYC server line of processors from AMD support system
management functionality via HSMP (Host System Management Port).
Newer Fam19h(model 0x00-0x1f, 0x30-0x3f, 0x90-0x9f, 0xa0-0xaf),
Fam1Ah(model 0x00-0x1f) EPYC server line of processors from AMD support
system management functionality via HSMP (Host System Management Port).

The Host System Management Port (HSMP) is an interface to provide
OS-level software with access to system management functions via a
@@ -16,14 +17,25 @@ More details on the interface can be found in chapter
Eg: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/55898_B1_pub_0_50.zip


HSMP interface is supported on EPYC server CPU models only.
HSMP interface is supported on EPYC line of server CPUs and MI300A (APU).


HSMP device
============================================

amd_hsmp driver under the drivers/platforms/x86/ creates miscdevice
/dev/hsmp to let user space programs run hsmp mailbox commands.
amd_hsmp driver under drivers/platforms/x86/amd/hsmp/ has separate driver files
for ACPI object based probing, platform device based probing and for the common
code for these two drivers.

Kconfig option CONFIG_AMD_HSMP_PLAT compiles plat.c and creates amd_hsmp.ko.
Kconfig option CONFIG_AMD_HSMP_ACPI compiles acpi.c and creates hsmp_acpi.ko.
Selecting any of these two configs automatically selects CONFIG_AMD_HSMP. This
compiles common code hsmp.c and creates hsmp_common.ko module.

Both the ACPI and plat drivers create the miscdevice /dev/hsmp to let
user space programs run hsmp mailbox commands.

The ACPI object format supported by the driver is defined below.

$ ls -al /dev/hsmp
crw-r--r-- 1 root root 10, 123 Jan 21 21:41 /dev/hsmp
@@ -59,6 +71,51 @@ Note: lseek() is not supported as entire metrics table is read.
Metrics table definitions will be documented as part of Public PPR.
The same is defined in the amd_hsmp.h header.

ACPI device object format
=========================
The ACPI object format expected from the amd_hsmp driver
for socket with ID00 is given below::

  Device(HSMP)
		{
			Name(_HID, "AMDI0097")
			Name(_UID, "ID00")
			Name(HSE0, 0x00000001)
			Name(RBF0, ResourceTemplate()
			{
				Memory32Fixed(ReadWrite, 0xxxxxxx, 0x00100000)
			})
			Method(_CRS, 0, NotSerialized)
			{
				Return(RBF0)
			}
			Method(_STA, 0, NotSerialized)
			{
				If(LEqual(HSE0, One))
				{
					Return(0x0F)
				}
				Else
				{
					Return(Zero)
				}
			}
			Name(_DSD, Package(2)
			{
				Buffer(0x10)
				{
					0x9D, 0x61, 0x4D, 0xB7, 0x07, 0x57, 0xBD, 0x48,
					0xA6, 0x9F, 0x4E, 0xA2, 0x87, 0x1F, 0xC2, 0xF6
				},
				Package(3)
				{
					Package(2) {"MsgIdOffset", 0x00010934},
					Package(2) {"MsgRspOffset", 0x00010980},
					Package(2) {"MsgArgOffset", 0x000109E0}
				}
			})
		}


An example
==========
+1 −1
Original line number Diff line number Diff line
@@ -5,6 +5,6 @@
#

obj-$(CONFIG_AMD_PMC)		+= pmc/
obj-y				+= hsmp/
obj-$(CONFIG_AMD_HSMP)		+= hsmp/
obj-$(CONFIG_AMD_PMF)		+= pmf/
obj-$(CONFIG_AMD_WBRF)		+= wbrf.o
+33 −3
Original line number Diff line number Diff line
@@ -4,14 +4,44 @@
#

config AMD_HSMP
	tristate "AMD HSMP Driver"
	depends on AMD_NB && X86_64 && ACPI
	tristate

menu "AMD HSMP Driver"
	depends on AMD_NB || COMPILE_TEST

config AMD_HSMP_ACPI
	tristate "AMD HSMP ACPI device driver"
	depends on ACPI
	select AMD_HSMP
	help
	  Host System Management Port (HSMP) interface is a mailbox interface
	  between the x86 core and the System Management Unit (SMU) firmware.
	  The driver provides a way for user space tools to monitor and manage
	  system management functionality on EPYC server CPUs from AMD.
	  system management functionality on EPYC and MI300A server CPUs
	  from AMD.

	  This option supports ACPI based probing.
	  You may enable this, if your platform BIOS provides an ACPI object
	  as described in amd_hsmp.rst document.

	  If you choose to compile this driver as a module the module will be
	  called hsmp_acpi.

config AMD_HSMP_PLAT
	tristate "AMD HSMP platform device driver"
	select AMD_HSMP
	help
	  Host System Management Port (HSMP) interface is a mailbox interface
	  between the x86 core and the System Management Unit (SMU) firmware.
	  The driver provides a way for user space tools to monitor and manage
	  system management functionality on EPYC and MI300A server CPUs
	  from AMD.

	  This option supports platform device based probing.
	  You may enable this, if your platform BIOS does not provide
	  HSMP ACPI object.

	  If you choose to compile this driver as a module the module will be
	  called amd_hsmp.

endmenu
+6 −2
Original line number Diff line number Diff line
@@ -4,5 +4,9 @@
# AMD HSMP Driver
#

obj-$(CONFIG_AMD_HSMP)		+= amd_hsmp.o
amd_hsmp-objs			:= hsmp.o plat.o acpi.o
obj-$(CONFIG_AMD_HSMP)			+= hsmp_common.o
hsmp_common-objs			:= hsmp.o
obj-$(CONFIG_AMD_HSMP_PLAT)		+= amd_hsmp.o
amd_hsmp-objs				:= plat.o
obj-$(CONFIG_AMD_HSMP_ACPI)		+= hsmp_acpi.o
hsmp_acpi-objs				:= acpi.o
+79 −3
Original line number Diff line number Diff line
@@ -9,11 +9,15 @@

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <asm/amd_nb.h>

#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/dev_printk.h>
#include <linux/ioport.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sysfs.h>
#include <linux/uuid.h>

@@ -21,6 +25,10 @@

#include "hsmp.h"

#define DRIVER_NAME		"amd_hsmp"
#define DRIVER_VERSION		"2.3"
#define ACPI_HSMP_DEVICE_HID	"AMDI0097"

/* These are the strings specified in ACPI table */
#define MSG_IDOFF_STR		"MsgIdOffset"
#define MSG_ARGOFF_STR		"MsgArgOffset"
@@ -200,7 +208,6 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
	sock->sock_ind		= sock_ind;
	sock->dev		= dev;
	sock->amd_hsmp_rdwr	= amd_hsmp_acpi_rdwr;
	hsmp_pdev.is_acpi_device	= true;

	sema_init(&sock->hsmp_sem, 1);

@@ -213,7 +220,7 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
	return hsmp_read_acpi_dsd(sock);
}

int hsmp_create_acpi_sysfs_if(struct device *dev)
static int hsmp_create_acpi_sysfs_if(struct device *dev)
{
	struct attribute_group *attr_grp;
	u16 sock_ind;
@@ -236,7 +243,7 @@ int hsmp_create_acpi_sysfs_if(struct device *dev)
	return devm_device_add_group(dev, attr_grp);
}

int init_acpi(struct device *dev)
static int init_acpi(struct device *dev)
{
	u16 sock_ind;
	int ret;
@@ -270,3 +277,72 @@ int init_acpi(struct device *dev)

	return ret;
}

static const struct acpi_device_id amd_hsmp_acpi_ids[] = {
	{ACPI_HSMP_DEVICE_HID, 0},
	{}
};
MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids);

static int hsmp_acpi_probe(struct platform_device *pdev)
{
	int ret;

	if (!hsmp_pdev.is_probed) {
		hsmp_pdev.num_sockets = amd_nb_num();
		if (hsmp_pdev.num_sockets == 0 || hsmp_pdev.num_sockets > MAX_AMD_SOCKETS)
			return -ENODEV;

		hsmp_pdev.sock = devm_kcalloc(&pdev->dev, hsmp_pdev.num_sockets,
					      sizeof(*hsmp_pdev.sock),
					      GFP_KERNEL);
		if (!hsmp_pdev.sock)
			return -ENOMEM;
	}

	ret = init_acpi(&pdev->dev);
	if (ret) {
		dev_err(&pdev->dev, "Failed to initialize HSMP interface.\n");
		return ret;
	}

	ret = hsmp_create_acpi_sysfs_if(&pdev->dev);
	if (ret)
		dev_err(&pdev->dev, "Failed to create HSMP sysfs interface\n");

	if (!hsmp_pdev.is_probed) {
		ret = hsmp_misc_register(&pdev->dev);
		if (ret)
			return ret;
		hsmp_pdev.is_probed = true;
	}

	return 0;
}

static void hsmp_acpi_remove(struct platform_device *pdev)
{
	/*
	 * We register only one misc_device even on multi-socket system.
	 * So, deregister should happen only once.
	 */
	if (hsmp_pdev.is_probed) {
		hsmp_misc_deregister();
		hsmp_pdev.is_probed = false;
	}
}

static struct platform_driver amd_hsmp_driver = {
	.probe		= hsmp_acpi_probe,
	.remove		= hsmp_acpi_remove,
	.driver		= {
		.name	= DRIVER_NAME,
		.acpi_match_table = amd_hsmp_acpi_ids,
	},
};

module_platform_driver(amd_hsmp_driver);

MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
Loading