On Tue, 20 Aug 2024, Suma Hegde wrote: > Move ACPI related code to acpi.c from hsmp.c. > We still have one driver, the driver probe will be split in the next patch. As with 5/11, please state the overall goal here too. > Signed-off-by: Suma Hegde <suma.hegde@xxxxxxx> > Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@xxxxxxx> > --- Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx> > Changes since v3: > 1. File header content is modified. > > Changes since v2: > None > > Changes since v1: > 1. Add following headers in acpi.c > #include <linux/device.h> > #include <linux/dev_printk.h> > #include <linux/ioport.h> > #include <linux/kstrtox.h> > #include <linux/uuid.h> > #include <uapi/asm-generic/errno-base.h> > > drivers/platform/x86/amd/hsmp/Makefile | 2 +- > drivers/platform/x86/amd/hsmp/acpi.c | 272 +++++++++++++++++++++++++ > drivers/platform/x86/amd/hsmp/hsmp.c | 250 ----------------------- > drivers/platform/x86/amd/hsmp/hsmp.h | 2 + > 4 files changed, 275 insertions(+), 251 deletions(-) > create mode 100644 drivers/platform/x86/amd/hsmp/acpi.c > > diff --git a/drivers/platform/x86/amd/hsmp/Makefile b/drivers/platform/x86/amd/hsmp/Makefile > index fb8ba04b2f0d..0cc92865c0a2 100644 > --- a/drivers/platform/x86/amd/hsmp/Makefile > +++ b/drivers/platform/x86/amd/hsmp/Makefile > @@ -5,4 +5,4 @@ > # > > obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o > -amd_hsmp-objs := hsmp.o plat.o > +amd_hsmp-objs := hsmp.o plat.o acpi.o > diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c > new file mode 100644 > index 000000000000..61c072216fb7 > --- /dev/null > +++ b/drivers/platform/x86/amd/hsmp/acpi.c > @@ -0,0 +1,272 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * AMD HSMP Platform Driver > + * Copyright (c) 2024, AMD. > + * All Rights Reserved. > + * > + * This file provides an ACPI based driver implementation for HSMP interface. > + */ > + > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > + > +#include <linux/acpi.h> > +#include <linux/device.h> > +#include <linux/dev_printk.h> > +#include <linux/ioport.h> > +#include <linux/kstrtox.h> > +#include <linux/sysfs.h> > +#include <linux/uuid.h> > + > +#include <uapi/asm-generic/errno-base.h> > + > +#include "hsmp.h" > + > +/* These are the strings specified in ACPI table */ > +#define MSG_IDOFF_STR "MsgIdOffset" > +#define MSG_ARGOFF_STR "MsgArgOffset" > +#define MSG_RESPOFF_STR "MsgRspOffset" > + > +static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, > + u32 *value, bool write) > +{ > + if (write) > + iowrite32(*value, sock->virt_base_addr + offset); > + else > + *value = ioread32(sock->virt_base_addr + offset); > + > + return 0; > +} > + > +/* This is the UUID used for HSMP */ > +static const guid_t acpi_hsmp_uuid = GUID_INIT(0xb74d619d, 0x5707, 0x48bd, > + 0xa6, 0x9f, 0x4e, 0xa2, > + 0x87, 0x1f, 0xc2, 0xf6); > + > +static inline bool is_acpi_hsmp_uuid(union acpi_object *obj) > +{ > + if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == UUID_SIZE) > + return guid_equal((guid_t *)obj->buffer.pointer, &acpi_hsmp_uuid); > + > + return false; > +} > + > +static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind) > +{ > + char *uid; > + > + /* > + * UID (ID00, ID01..IDXX) is used for differentiating sockets, > + * read it and strip the "ID" part of it and convert the remaining > + * bytes to integer. > + */ > + uid = acpi_device_uid(ACPI_COMPANION(dev)); > + > + return kstrtou16(uid + 2, 10, sock_ind); > +} > + > +static acpi_status hsmp_resource(struct acpi_resource *res, void *data) > +{ > + struct hsmp_socket *sock = data; > + struct resource r; > + > + switch (res->type) { > + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: > + if (!acpi_dev_resource_memory(res, &r)) > + return AE_ERROR; > + if (!r.start || r.end < r.start || !(r.flags & IORESOURCE_MEM_WRITEABLE)) > + return AE_ERROR; > + sock->mbinfo.base_addr = r.start; > + sock->mbinfo.size = resource_size(&r); > + break; > + case ACPI_RESOURCE_TYPE_END_TAG: > + break; > + default: > + return AE_ERROR; > + } > + > + return AE_OK; > +} > + > +static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) > +{ > + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; > + union acpi_object *guid, *mailbox_package; > + union acpi_object *dsd; > + acpi_status status; > + int ret = 0; > + int j; > + > + status = acpi_evaluate_object_typed(ACPI_HANDLE(sock->dev), "_DSD", NULL, > + &buf, ACPI_TYPE_PACKAGE); > + if (ACPI_FAILURE(status)) { > + dev_err(sock->dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n", > + acpi_format_exception(status)); > + return -ENODEV; > + } > + > + dsd = buf.pointer; > + > + /* HSMP _DSD property should contain 2 objects. > + * 1. guid which is an acpi object of type ACPI_TYPE_BUFFER > + * 2. mailbox which is an acpi object of type ACPI_TYPE_PACKAGE > + * This mailbox object contains 3 more acpi objects of type > + * ACPI_TYPE_PACKAGE for holding msgid, msgresp, msgarg offsets > + * these packages inturn contain 2 acpi objects of type > + * ACPI_TYPE_STRING and ACPI_TYPE_INTEGER > + */ > + if (!dsd || dsd->type != ACPI_TYPE_PACKAGE || dsd->package.count != 2) { > + ret = -EINVAL; > + goto free_buf; > + } > + > + guid = &dsd->package.elements[0]; > + mailbox_package = &dsd->package.elements[1]; > + if (!is_acpi_hsmp_uuid(guid) || mailbox_package->type != ACPI_TYPE_PACKAGE) { > + dev_err(sock->dev, "Invalid hsmp _DSD table data\n"); > + ret = -EINVAL; > + goto free_buf; > + } > + > + for (j = 0; j < mailbox_package->package.count; j++) { > + union acpi_object *msgobj, *msgstr, *msgint; > + > + msgobj = &mailbox_package->package.elements[j]; > + msgstr = &msgobj->package.elements[0]; > + msgint = &msgobj->package.elements[1]; > + > + /* package should have 1 string and 1 integer object */ > + if (msgobj->type != ACPI_TYPE_PACKAGE || > + msgstr->type != ACPI_TYPE_STRING || > + msgint->type != ACPI_TYPE_INTEGER) { > + ret = -EINVAL; > + goto free_buf; > + } > + > + if (!strncmp(msgstr->string.pointer, MSG_IDOFF_STR, > + msgstr->string.length)) { > + sock->mbinfo.msg_id_off = msgint->integer.value; > + } else if (!strncmp(msgstr->string.pointer, MSG_RESPOFF_STR, > + msgstr->string.length)) { > + sock->mbinfo.msg_resp_off = msgint->integer.value; > + } else if (!strncmp(msgstr->string.pointer, MSG_ARGOFF_STR, > + msgstr->string.length)) { > + sock->mbinfo.msg_arg_off = msgint->integer.value; > + } else { > + ret = -ENOENT; > + goto free_buf; > + } > + } > + > + if (!sock->mbinfo.msg_id_off || !sock->mbinfo.msg_resp_off || > + !sock->mbinfo.msg_arg_off) > + ret = -EINVAL; > + > +free_buf: > + ACPI_FREE(buf.pointer); > + return ret; > +} > + > +static int hsmp_read_acpi_crs(struct hsmp_socket *sock) > +{ > + acpi_status status; > + > + status = acpi_walk_resources(ACPI_HANDLE(sock->dev), METHOD_NAME__CRS, > + hsmp_resource, sock); > + if (ACPI_FAILURE(status)) { > + dev_err(sock->dev, "Failed to look up MP1 base address from CRS method, err: %s\n", > + acpi_format_exception(status)); > + return -EINVAL; > + } > + if (!sock->mbinfo.base_addr || !sock->mbinfo.size) > + return -EINVAL; > + > + /* The mapped region should be un-cached */ > + sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr, > + sock->mbinfo.size); > + if (!sock->virt_base_addr) { > + dev_err(sock->dev, "Failed to ioremap MP1 base address\n"); > + return -ENOMEM; > + } > + > + return 0; > +} > + > +/* Parse the ACPI table to read the data */ > +static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) > +{ > + struct hsmp_socket *sock = &plat_dev.sock[sock_ind]; > + int ret; > + > + sock->sock_ind = sock_ind; > + sock->dev = dev; > + sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr; > + plat_dev.is_acpi_device = true; > + > + sema_init(&sock->hsmp_sem, 1); > + > + /* Read MP1 base address from CRS method */ > + ret = hsmp_read_acpi_crs(sock); > + if (ret) > + return ret; > + > + /* Read mailbox offsets from DSD table */ > + return hsmp_read_acpi_dsd(sock); > +} > + > +int hsmp_create_acpi_sysfs_if(struct device *dev) > +{ > + struct attribute_group *attr_grp; > + u16 sock_ind; > + int ret; > + > + attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL); > + if (!attr_grp) > + return -ENOMEM; > + > + attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; > + > + ret = hsmp_get_uid(dev, &sock_ind); > + if (ret) > + return ret; > + > + ret = hsmp_create_attr_list(attr_grp, dev, sock_ind); > + if (ret) > + return ret; > + > + return devm_device_add_group(dev, attr_grp); > +} > + > +int init_acpi(struct device *dev) > +{ > + u16 sock_ind; > + int ret; > + > + ret = hsmp_get_uid(dev, &sock_ind); > + if (ret) > + return ret; > + if (sock_ind >= plat_dev.num_sockets) > + return -EINVAL; > + > + ret = hsmp_parse_acpi_table(dev, sock_ind); > + if (ret) { > + dev_err(dev, "Failed to parse ACPI table\n"); > + return ret; > + } > + > + /* Test the hsmp interface */ > + ret = hsmp_test(sock_ind, 0xDEADBEEF); > + if (ret) { > + dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n", > + boot_cpu_data.x86, boot_cpu_data.x86_model); > + dev_err(dev, "Is HSMP disabled in BIOS ?\n"); > + return ret; > + } > + > + ret = hsmp_cache_proto_ver(sock_ind); > + if (ret) { > + dev_err(dev, "Failed to read HSMP protocol version\n"); > + return ret; > + } > + > + return ret; > +} > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c > index 6da7c6189020..573867c17fd5 100644 > --- a/drivers/platform/x86/amd/hsmp/hsmp.c > +++ b/drivers/platform/x86/amd/hsmp/hsmp.c > @@ -39,24 +39,8 @@ > #define HSMP_WR true > #define HSMP_RD false > > -/* These are the strings specified in ACPI table */ > -#define MSG_IDOFF_STR "MsgIdOffset" > -#define MSG_ARGOFF_STR "MsgArgOffset" > -#define MSG_RESPOFF_STR "MsgRspOffset" > - > struct hsmp_plat_device plat_dev; > > -static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, > - u32 *value, bool write) > -{ > - if (write) > - iowrite32(*value, sock->virt_base_addr + offset); > - else > - *value = ioread32(sock->virt_base_addr + offset); > - > - return 0; > -} > - > /* > * Send a message to the HSMP port via PCI-e config space registers > * or by writing to MMIO space. > @@ -306,182 +290,6 @@ static const struct file_operations hsmp_fops = { > .compat_ioctl = hsmp_ioctl, > }; > > -/* This is the UUID used for HSMP */ > -static const guid_t acpi_hsmp_uuid = GUID_INIT(0xb74d619d, 0x5707, 0x48bd, > - 0xa6, 0x9f, 0x4e, 0xa2, > - 0x87, 0x1f, 0xc2, 0xf6); > - > -static inline bool is_acpi_hsmp_uuid(union acpi_object *obj) > -{ > - if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == UUID_SIZE) > - return guid_equal((guid_t *)obj->buffer.pointer, &acpi_hsmp_uuid); > - > - return false; > -} > - > -static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind) > -{ > - char *uid; > - > - /* > - * UID (ID00, ID01..IDXX) is used for differentiating sockets, > - * read it and strip the "ID" part of it and convert the remaining > - * bytes to integer. > - */ > - uid = acpi_device_uid(ACPI_COMPANION(dev)); > - > - return kstrtou16(uid + 2, 10, sock_ind); > -} > - > -static acpi_status hsmp_resource(struct acpi_resource *res, void *data) > -{ > - struct hsmp_socket *sock = data; > - struct resource r; > - > - switch (res->type) { > - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: > - if (!acpi_dev_resource_memory(res, &r)) > - return AE_ERROR; > - if (!r.start || r.end < r.start || !(r.flags & IORESOURCE_MEM_WRITEABLE)) > - return AE_ERROR; > - sock->mbinfo.base_addr = r.start; > - sock->mbinfo.size = resource_size(&r); > - break; > - case ACPI_RESOURCE_TYPE_END_TAG: > - break; > - default: > - return AE_ERROR; > - } > - > - return AE_OK; > -} > - > -static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) > -{ > - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; > - union acpi_object *guid, *mailbox_package; > - union acpi_object *dsd; > - acpi_status status; > - int ret = 0; > - int j; > - > - status = acpi_evaluate_object_typed(ACPI_HANDLE(sock->dev), "_DSD", NULL, > - &buf, ACPI_TYPE_PACKAGE); > - if (ACPI_FAILURE(status)) { > - dev_err(sock->dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n", > - acpi_format_exception(status)); > - return -ENODEV; > - } > - > - dsd = buf.pointer; > - > - /* HSMP _DSD property should contain 2 objects. > - * 1. guid which is an acpi object of type ACPI_TYPE_BUFFER > - * 2. mailbox which is an acpi object of type ACPI_TYPE_PACKAGE > - * This mailbox object contains 3 more acpi objects of type > - * ACPI_TYPE_PACKAGE for holding msgid, msgresp, msgarg offsets > - * these packages inturn contain 2 acpi objects of type > - * ACPI_TYPE_STRING and ACPI_TYPE_INTEGER > - */ > - if (!dsd || dsd->type != ACPI_TYPE_PACKAGE || dsd->package.count != 2) { > - ret = -EINVAL; > - goto free_buf; > - } > - > - guid = &dsd->package.elements[0]; > - mailbox_package = &dsd->package.elements[1]; > - if (!is_acpi_hsmp_uuid(guid) || mailbox_package->type != ACPI_TYPE_PACKAGE) { > - dev_err(sock->dev, "Invalid hsmp _DSD table data\n"); > - ret = -EINVAL; > - goto free_buf; > - } > - > - for (j = 0; j < mailbox_package->package.count; j++) { > - union acpi_object *msgobj, *msgstr, *msgint; > - > - msgobj = &mailbox_package->package.elements[j]; > - msgstr = &msgobj->package.elements[0]; > - msgint = &msgobj->package.elements[1]; > - > - /* package should have 1 string and 1 integer object */ > - if (msgobj->type != ACPI_TYPE_PACKAGE || > - msgstr->type != ACPI_TYPE_STRING || > - msgint->type != ACPI_TYPE_INTEGER) { > - ret = -EINVAL; > - goto free_buf; > - } > - > - if (!strncmp(msgstr->string.pointer, MSG_IDOFF_STR, > - msgstr->string.length)) { > - sock->mbinfo.msg_id_off = msgint->integer.value; > - } else if (!strncmp(msgstr->string.pointer, MSG_RESPOFF_STR, > - msgstr->string.length)) { > - sock->mbinfo.msg_resp_off = msgint->integer.value; > - } else if (!strncmp(msgstr->string.pointer, MSG_ARGOFF_STR, > - msgstr->string.length)) { > - sock->mbinfo.msg_arg_off = msgint->integer.value; > - } else { > - ret = -ENOENT; > - goto free_buf; > - } > - } > - > - if (!sock->mbinfo.msg_id_off || !sock->mbinfo.msg_resp_off || > - !sock->mbinfo.msg_arg_off) > - ret = -EINVAL; > - > -free_buf: > - ACPI_FREE(buf.pointer); > - return ret; > -} > - > -static int hsmp_read_acpi_crs(struct hsmp_socket *sock) > -{ > - acpi_status status; > - > - status = acpi_walk_resources(ACPI_HANDLE(sock->dev), METHOD_NAME__CRS, > - hsmp_resource, sock); > - if (ACPI_FAILURE(status)) { > - dev_err(sock->dev, "Failed to look up MP1 base address from CRS method, err: %s\n", > - acpi_format_exception(status)); > - return -EINVAL; > - } > - if (!sock->mbinfo.base_addr || !sock->mbinfo.size) > - return -EINVAL; > - > - /* The mapped region should be un cached */ > - sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr, > - sock->mbinfo.size); > - if (!sock->virt_base_addr) { > - dev_err(sock->dev, "Failed to ioremap MP1 base address\n"); > - return -ENOMEM; > - } > - > - return 0; > -} > - > -/* Parse the ACPI table to read the data */ > -static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) > -{ > - struct hsmp_socket *sock = &plat_dev.sock[sock_ind]; > - int ret; > - > - sock->sock_ind = sock_ind; > - sock->dev = dev; > - sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr; > - plat_dev.is_acpi_device = true; > - > - sema_init(&sock->hsmp_sem, 1); > - > - /* Read MP1 base address from CRS method */ > - ret = hsmp_read_acpi_crs(sock); > - if (ret) > - return ret; > - > - /* Read mailbox offsets from DSD table */ > - return hsmp_read_acpi_dsd(sock); > -} > - > ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, > struct bin_attribute *bin_attr, char *buf, > loff_t off, size_t count) > @@ -590,29 +398,6 @@ int hsmp_create_attr_list(struct attribute_group *attr_grp, > return hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, sock_ind); > } > > -static int hsmp_create_acpi_sysfs_if(struct device *dev) > -{ > - struct attribute_group *attr_grp; > - u16 sock_ind; > - int ret; > - > - attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL); > - if (!attr_grp) > - return -ENOMEM; > - > - attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; > - > - ret = hsmp_get_uid(dev, &sock_ind); > - if (ret) > - return ret; > - > - ret = hsmp_create_attr_list(attr_grp, dev, sock_ind); > - if (ret) > - return ret; > - > - return devm_device_add_group(dev, attr_grp); > -} > - > int hsmp_cache_proto_ver(u16 sock_ind) > { > struct hsmp_message msg = { 0 }; > @@ -645,41 +430,6 @@ static bool check_acpi_support(struct device *dev) > return false; > } > > -static int init_acpi(struct device *dev) > -{ > - u16 sock_ind; > - int ret; > - > - ret = hsmp_get_uid(dev, &sock_ind); > - if (ret) > - return ret; > - if (sock_ind >= plat_dev.num_sockets) > - return -EINVAL; > - > - ret = hsmp_parse_acpi_table(dev, sock_ind); > - if (ret) { > - dev_err(dev, "Failed to parse ACPI table\n"); > - return ret; > - } > - > - /* Test the hsmp interface */ > - ret = hsmp_test(sock_ind, 0xDEADBEEF); > - if (ret) { > - dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n", > - boot_cpu_data.x86, boot_cpu_data.x86_model); > - dev_err(dev, "Is HSMP disabled in BIOS ?\n"); > - return ret; > - } > - > - ret = hsmp_cache_proto_ver(sock_ind); > - if (ret) { > - dev_err(dev, "Failed to read HSMP protocol version\n"); > - return ret; > - } > - > - return ret; > -} > - > static int hsmp_pltdrv_probe(struct platform_device *pdev) > { > int ret; > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h > index d59a9efb4799..f465600cb843 100644 > --- a/drivers/platform/x86/amd/hsmp/hsmp.h > +++ b/drivers/platform/x86/amd/hsmp/hsmp.h > @@ -62,6 +62,7 @@ ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, > struct bin_attribute *bin_attr, char *buf, > loff_t off, size_t count); > int hsmp_create_non_acpi_sysfs_if(struct device *dev); > +int hsmp_create_acpi_sysfs_if(struct device *dev); > int hsmp_cache_proto_ver(u16 sock_ind); > umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, > struct bin_attribute *battr, int id); > @@ -69,4 +70,5 @@ int hsmp_create_attr_list(struct attribute_group *attr_grp, > struct device *dev, u16 sock_ind); > int hsmp_test(u16 sock_ind, u32 value); > int init_platform_device(struct device *dev); > +int init_acpi(struct device *dev); > #endif /* HSMP_H */ > -- i.