Message ID | 20240820102941.1813163-6-suma.hegde@amd.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | [v4,01/11] platform/x86/amd/hsmp: Create hsmp/ directory | expand |
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@amd.com> > Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com> > --- Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > 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 */ >
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 */