diff options
42 files changed, 1537 insertions, 316 deletions
diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst index e27a1c3f634e..98d304010170 100644 --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst @@ -53,6 +53,7 @@ detailed description): - Lap mode sensor - Setting keyboard language - WWAN Antenna type + - Auxmac A compatibility table by model and feature is maintained on the web site, http://ibm-acpi.sf.net/. I appreciate any success or failure @@ -1511,6 +1512,25 @@ Currently 2 antenna types are supported as mentioned below: The property is read-only. If the platform doesn't have support the sysfs class is not created. +Auxmac +------ + +sysfs: auxmac + +Some newer Thinkpads have a feature called MAC Address Pass-through. This +feature is implemented by the system firmware to provide a system unique MAC, +that can override a dock or USB ethernet dongle MAC, when connected to a +network. This property enables user-space to easily determine the MAC address +if the feature is enabled. + +The values of this auxiliary MAC are: + + cat /sys/devices/platform/thinkpad_acpi/auxmac + +If the feature is disabled, the value will be 'disabled'. + +This property is read-only. + Adaptive keyboard ----------------- diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst index 440e4b645a1c..c92bfd55359f 100644 --- a/Documentation/arch/x86/amd_hsmp.rst +++ b/Documentation/arch/x86/amd_hsmp.rst @@ -41,6 +41,24 @@ In-kernel integration: * Locking across callers is taken care by the driver. +HSMP sysfs interface +==================== + +1. Metrics table binary sysfs + +AMD MI300A MCM provides GET_METRICS_TABLE message to retrieve +most of the system management information from SMU in one go. + +The metrics table is made available as hexadecimal sysfs binary file +under per socket sysfs directory created at +/sys/devices/platform/amd_hsmp/socket%d/metrics_bin + +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. + + An example ========== diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 1d111350197f..838e5a013a07 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -222,6 +222,7 @@ #define MSR_INTEGRITY_CAPS_ARRAY_BIST BIT(MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT) #define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4 #define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT) +#define MSR_INTEGRITY_CAPS_SAF_GEN_MASK GENMASK_ULL(10, 9) #define MSR_LBR_NHM_FROM 0x00000680 #define MSR_LBR_NHM_TO 0x000006c0 diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index 769b939444ae..fce22686c834 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -47,6 +47,9 @@ enum hsmp_message_ids { HSMP_SET_PCI_RATE, /* 20h Control link rate on PCIe devices */ HSMP_SET_POWER_MODE, /* 21h Select power efficiency profile policy */ HSMP_SET_PSTATE_MAX_MIN, /* 22h Set the max and min DF P-State */ + HSMP_GET_METRIC_TABLE_VER, /* 23h Get metrics table version */ + HSMP_GET_METRIC_TABLE, /* 24h Get metrics table */ + HSMP_GET_METRIC_TABLE_DRAM_ADDR,/* 25h Get metrics table dram address */ HSMP_MSG_ID_MAX, }; @@ -64,6 +67,14 @@ enum hsmp_msg_type { HSMP_GET = 1, }; +enum hsmp_proto_versions { + HSMP_PROTO_VER2 = 2, + HSMP_PROTO_VER3, + HSMP_PROTO_VER4, + HSMP_PROTO_VER5, + HSMP_PROTO_VER6 +}; + struct hsmp_msg_desc { int num_args; int response_sz; @@ -295,6 +306,104 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] = { * input: args[0] = min df pstate[15:8] + max df pstate[7:0] */ {1, 0, HSMP_SET}, + + /* + * HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1 + * output: args[0] = metrics table version + */ + {0, 1, HSMP_GET}, + + /* + * HSMP_GET_METRIC_TABLE, num_args = 0, response_sz = 0 + */ + {0, 0, HSMP_GET}, + + /* + * HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 2 + * output: args[0] = lower 32 bits of the address + * output: args[1] = upper 32 bits of the address + */ + {0, 2, HSMP_GET}, +}; + +/* Metrics table (supported only with proto version 6) */ +struct hsmp_metric_table { + __u32 accumulation_counter; + + /* TEMPERATURE */ + __u32 max_socket_temperature; + __u32 max_vr_temperature; + __u32 max_hbm_temperature; + __u64 max_socket_temperature_acc; + __u64 max_vr_temperature_acc; + __u64 max_hbm_temperature_acc; + + /* POWER */ + __u32 socket_power_limit; + __u32 max_socket_power_limit; + __u32 socket_power; + + /* ENERGY */ + __u64 timestamp; + __u64 socket_energy_acc; + __u64 ccd_energy_acc; + __u64 xcd_energy_acc; + __u64 aid_energy_acc; + __u64 hbm_energy_acc; + + /* FREQUENCY */ + __u32 cclk_frequency_limit; + __u32 gfxclk_frequency_limit; + __u32 fclk_frequency; + __u32 uclk_frequency; + __u32 socclk_frequency[4]; + __u32 vclk_frequency[4]; + __u32 dclk_frequency[4]; + __u32 lclk_frequency[4]; + __u64 gfxclk_frequency_acc[8]; + __u64 cclk_frequency_acc[96]; + + /* FREQUENCY RANGE */ + __u32 max_cclk_frequency; + __u32 min_cclk_frequency; + __u32 max_gfxclk_frequency; + __u32 min_gfxclk_frequency; + __u32 fclk_frequency_table[4]; + __u32 uclk_frequency_table[4]; + __u32 socclk_frequency_table[4]; + __u32 vclk_frequency_table[4]; + __u32 dclk_frequency_table[4]; + __u32 lclk_frequency_table[4]; + __u32 max_lclk_dpm_range; + __u32 min_lclk_dpm_range; + + /* XGMI */ + __u32 xgmi_width; + __u32 xgmi_bitrate; + __u64 xgmi_read_bandwidth_acc[8]; + __u64 xgmi_write_bandwidth_acc[8]; + + /* ACTIVITY */ + __u32 socket_c0_residency; + __u32 socket_gfx_busy; + __u32 dram_bandwidth_utilization; + __u64 socket_c0_residency_acc; + __u64 socket_gfx_busy_acc; + __u64 dram_bandwidth_acc; + __u32 max_dram_bandwidth; + __u64 dram_bandwidth_utilization_acc; + __u64 pcie_bandwidth_acc[4]; + + /* THROTTLERS */ + __u32 prochot_residency_acc; + __u32 ppt_residency_acc; + __u32 socket_thm_residency_acc; + __u32 vr_thm_residency_acc; + __u32 hbm_thm_residency_acc; + __u32 spare; + + /* New items at the end to maintain driver compatibility */ + __u32 gfxclk_frequency[8]; }; /* Reset to default packing */ diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c index 4ee7bb431b7c..1ac7dab22c63 100644 --- a/drivers/platform/mellanox/mlxbf-bootctl.c +++ b/drivers/platform/mellanox/mlxbf-bootctl.c @@ -1028,17 +1028,15 @@ static int mlxbf_bootctl_probe(struct platform_device *pdev) return ret; } -static int mlxbf_bootctl_remove(struct platform_device *pdev) +static void mlxbf_bootctl_remove(struct platform_device *pdev) { sysfs_remove_bin_file(&pdev->dev.kobj, &mlxbf_bootctl_bootfifo_sysfs_attr); - - return 0; } static struct platform_driver mlxbf_bootctl_driver = { .probe = mlxbf_bootctl_probe, - .remove = mlxbf_bootctl_remove, + .remove_new = mlxbf_bootctl_remove, .driver = { .name = "mlxbf-bootctl", .dev_groups = mlxbf_bootctl_groups, diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index f3696a54a2bd..69729ba8f505 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -1361,13 +1361,11 @@ fail: } /* Device remove function. */ -static int mlxbf_tmfifo_remove(struct platform_device *pdev) +static void mlxbf_tmfifo_remove(struct platform_device *pdev) { struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev); mlxbf_tmfifo_cleanup(fifo); - - return 0; } static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = { @@ -1378,7 +1376,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match); static struct platform_driver mlxbf_tmfifo_driver = { .probe = mlxbf_tmfifo_probe, - .remove = mlxbf_tmfifo_remove, + .remove_new = mlxbf_tmfifo_remove, .driver = { .name = "bf-tmfifo", .acpi_match_table = mlxbf_tmfifo_acpi_match, diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index eb5ad35274dd..5c022b258f91 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -786,15 +786,13 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) return 0; } -static int mlxreg_hotplug_remove(struct platform_device *pdev) +static void mlxreg_hotplug_remove(struct platform_device *pdev) { struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); /* Clean interrupts setup. */ mlxreg_hotplug_unset_irq(priv); devm_free_irq(&pdev->dev, priv->irq, priv); - - return 0; } static struct platform_driver mlxreg_hotplug_driver = { @@ -802,7 +800,7 @@ static struct platform_driver mlxreg_hotplug_driver = { .name = "mlxreg-hotplug", }, .probe = mlxreg_hotplug_probe, - .remove = mlxreg_hotplug_remove, + .remove_new = mlxreg_hotplug_remove, }; module_platform_driver(mlxreg_hotplug_driver); diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index 83ba037408cd..ee7bd623ba44 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -263,13 +263,11 @@ static int mlxreg_io_probe(struct platform_device *pdev) return 0; } -static int mlxreg_io_remove(struct platform_device *pdev) +static void mlxreg_io_remove(struct platform_device *pdev) { struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev); mutex_destroy(&priv->io_lock); - - return 0; } static struct platform_driver mlxreg_io_driver = { @@ -277,7 +275,7 @@ static struct platform_driver mlxreg_io_driver = { .name = "mlxreg-io", }, .probe = mlxreg_io_probe, - .remove = mlxreg_io_remove, + .remove_new = mlxreg_io_remove, }; module_platform_driver(mlxreg_io_driver); diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 8d833836a6d3..43d119e3a473 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -907,7 +907,7 @@ i2c_get_adapter_fail: return err; } -static int mlxreg_lc_remove(struct platform_device *pdev) +static void mlxreg_lc_remove(struct platform_device *pdev) { struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev); @@ -921,7 +921,7 @@ static int mlxreg_lc_remove(struct platform_device *pdev) * is nothing to remove. */ if (!data->notifier || !data->notifier->handle) - return 0; + return; /* Clear event notification callback and handle. */ data->notifier->user_handler = NULL; @@ -940,13 +940,11 @@ static int mlxreg_lc_remove(struct platform_device *pdev) i2c_put_adapter(data->hpdev.adapter); data->hpdev.adapter = NULL; } - - return 0; } static struct platform_driver mlxreg_lc_driver = { .probe = mlxreg_lc_probe, - .remove = mlxreg_lc_remove, + .remove_new = mlxreg_lc_remove, .driver = { .name = "mlxreg-lc", }, diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c index 75b699676ca6..3ef655591424 100644 --- a/drivers/platform/mellanox/nvsw-sn2201.c +++ b/drivers/platform/mellanox/nvsw-sn2201.c @@ -1217,7 +1217,7 @@ static int nvsw_sn2201_probe(struct platform_device *pdev) return nvsw_sn2201_config_pre_init(nvsw_sn2201); } -static int nvsw_sn2201_remove(struct platform_device *pdev) +static void nvsw_sn2201_remove(struct platform_device *pdev) { struct nvsw_sn2201 *nvsw_sn2201 = platform_get_drvdata(pdev); @@ -1239,8 +1239,6 @@ static int nvsw_sn2201_remove(struct platform_device *pdev) /* Unregister I2C controller. */ if (nvsw_sn2201->pdev_i2c) platform_device_unregister(nvsw_sn2201->pdev_i2c); - - return 0; } static const struct acpi_device_id nvsw_sn2201_acpi_ids[] = { @@ -1252,7 +1250,7 @@ MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids); static struct platform_driver nvsw_sn2201_driver = { .probe = nvsw_sn2201_probe, - .remove = nvsw_sn2201_remove, + .remove_new = nvsw_sn2201_remove, .driver = { .name = "nvsw-sn2201", .acpi_match_table = nvsw_sn2201_acpi_ids, diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 377a0becd1a1..0e472aa9bf41 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1922,7 +1922,6 @@ static void acer_rfkill_exit(void) rfkill_unregister(threeg_rfkill); rfkill_destroy(threeg_rfkill); } - return; } static void acer_wmi_notify(u32 value, void *context) @@ -2517,7 +2516,6 @@ static void __exit acer_wmi_exit(void) platform_driver_unregister(&acer_platform_driver); pr_info("Acer Laptop WMI Extras unloaded\n"); - return; } module_init(acer_wmi_init); diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c index 31382ef52efb..b056a5c8654a 100644 --- a/drivers/platform/x86/amd/hsmp.c +++ b/drivers/platform/x86/amd/hsmp.c @@ -20,7 +20,7 @@ #include <linux/semaphore.h> #define DRIVER_NAME "amd_hsmp" -#define DRIVER_VERSION "1.0" +#define DRIVER_VERSION "2.0" /* HSMP Status / Error codes */ #define HSMP_STATUS_NOT_READY 0x00 @@ -47,9 +47,29 @@ #define HSMP_INDEX_REG 0xc4 #define HSMP_DATA_REG 0xc8 -static struct semaphore *hsmp_sem; +#define HSMP_CDEV_NAME "hsmp_cdev" +#define HSMP_DEVNODE_NAME "hsmp" +#define HSMP_METRICS_TABLE_NAME "metrics_bin" -static struct miscdevice hsmp_device; +#define HSMP_ATTR_GRP_NAME_SIZE 10 + +struct hsmp_socket { + struct bin_attribute hsmp_attr; + void __iomem *metric_tbl_addr; + struct semaphore hsmp_sem; + char name[HSMP_ATTR_GRP_NAME_SIZE]; + u16 sock_ind; +}; + +struct hsmp_plat_device { + struct miscdevice hsmp_device; + struct hsmp_socket *sock; + struct device *dev; + u32 proto_ver; + u16 num_sockets; +}; + +static struct hsmp_plat_device plat_dev; static int amd_hsmp_rdwr(struct pci_dev *root, u32 address, u32 *value, bool write) @@ -188,6 +208,7 @@ static int validate_message(struct hsmp_message *msg) int hsmp_send_message(struct hsmp_message *msg) { + struct hsmp_socket *sock = &plat_dev.sock[msg->sock_ind]; struct amd_northbridge *nb; int ret; @@ -208,14 +229,13 @@ int hsmp_send_message(struct hsmp_message *msg) * In SMP system timeout of 100 millisecs should * be enough for the previous thread to finish the operation */ - ret = down_timeout(&hsmp_sem[msg->sock_ind], - msecs_to_jiffies(HSMP_MSG_TIMEOUT)); + ret = down_timeout(&sock->hsmp_sem, msecs_to_jiffies(HSMP_MSG_TIMEOUT)); if (ret < 0) return ret; ret = __hsmp_send_message(nb->root, msg); - up(&hsmp_sem[msg->sock_ind]); + up(&sock->hsmp_sem); return ret; } @@ -317,32 +337,198 @@ static const struct file_operations hsmp_fops = { .compat_ioctl = hsmp_ioctl, }; +static 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) +{ + struct hsmp_socket *sock = bin_attr->private; + struct hsmp_message msg = { 0 }; + int ret; + + /* Do not support lseek(), reads entire metric table */ + if (count < bin_attr->size) { + dev_err(plat_dev.dev, "Wrong buffer size\n"); + return -EINVAL; + } + + if (!sock) { + dev_err(plat_dev.dev, "Failed to read attribute private data\n"); + return -EINVAL; + } + + msg.msg_id = HSMP_GET_METRIC_TABLE; + msg.sock_ind = sock->sock_ind; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + memcpy(buf, sock->metric_tbl_addr, bin_attr->size); + + return bin_attr->size; +} + +static int hsmp_get_tbl_dram_base(u16 sock_ind) +{ + struct hsmp_socket *sock = &plat_dev.sock[sock_ind]; + struct hsmp_message msg = { 0 }; + phys_addr_t dram_addr; + int ret; + + msg.sock_ind = sock_ind; + msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz; + msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + + /* + * calculate the metric table DRAM address from lower and upper 32 bits + * sent from SMU and ioremap it to virtual address. + */ + dram_addr = msg.args[0] | ((u64)(msg.args[1]) << 32); + if (!dram_addr) { + dev_err(plat_dev.dev, "Invalid DRAM address for metric table\n"); + return -ENOMEM; + } + sock->metric_tbl_addr = devm_ioremap(plat_dev.dev, dram_addr, + sizeof(struct hsmp_metric_table)); + if (!sock->metric_tbl_addr) { + dev_err(plat_dev.dev, "Failed to ioremap metric table addr\n"); + return -ENOMEM; + } + return 0; +} + +static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, + struct bin_attribute *battr, int id) +{ + if (plat_dev.proto_ver == HSMP_PROTO_VER6) + return battr->attr.mode; + else + return 0; +} + +static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind) +{ + struct bin_attribute *hattr = &plat_dev.sock[sock_ind].hsmp_attr; + + sysfs_bin_attr_init(hattr); + hattr->attr.name = HSMP_METRICS_TABLE_NAME; + hattr->attr.mode = 0444; + hattr->read = hsmp_metric_tbl_read; + hattr->size = sizeof(struct hsmp_metric_table); + hattr->private = &plat_dev.sock[sock_ind]; + hattrs[0] = hattr; + + if (plat_dev.proto_ver == HSMP_PROTO_VER6) + return (hsmp_get_tbl_dram_base(sock_ind)); + else + return 0; +} + +/* One bin sysfs for metrics table*/ +#define NUM_HSMP_ATTRS 1 + +static int hsmp_create_sysfs_interface(void) +{ + const struct attribute_group **hsmp_attr_grps; + struct bin_attribute **hsmp_bin_attrs; + struct attribute_group *attr_grp; + int ret; + u16 i; + + /* String formatting is currently limited to u8 sockets */ + if (WARN_ON(plat_dev.num_sockets > U8_MAX)) + return -ERANGE; + + hsmp_attr_grps = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group *) * + (plat_dev.num_sockets + 1), GFP_KERNEL); + if (!hsmp_attr_grps) + return -ENOMEM; + + /* Create a sysfs directory for each socket */ + for (i = 0; i < plat_dev.num_sockets; i++) { + attr_grp = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group), GFP_KERNEL); + if (!attr_grp) + return -ENOMEM; + + snprintf(plat_dev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i); + attr_grp->name = plat_dev.sock[i].name; + + /* Null terminated list of attributes */ + hsmp_bin_attrs = devm_kzalloc(plat_dev.dev, sizeof(struct bin_attribute *) * + (NUM_HSMP_ATTRS + 1), GFP_KERNEL); + if (!hsmp_bin_attrs) + return -ENOMEM; + + attr_grp->bin_attrs = hsmp_bin_attrs; + attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; + hsmp_attr_grps[i] = attr_grp; + + /* Now create the leaf nodes */ + ret = hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, i); + if (ret) + return ret; + } + return devm_device_add_groups(plat_dev.dev, hsmp_attr_grps); +} + +static int hsmp_cache_proto_ver(void) +{ + struct hsmp_message msg = { 0 }; + int ret; + + msg.msg_id = HSMP_GET_PROTO_VER; + msg.sock_ind = 0; + msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; + + ret = hsmp_send_message(&msg); + if (!ret) + plat_dev.proto_ver = msg.args[0]; + + return ret; +} + static int hsmp_pltdrv_probe(struct platform_device *pdev) { - int i; + int ret, i; - hsmp_sem = devm_kzalloc(&pdev->dev, - (amd_nb_num() * sizeof(struct semaphore)), - GFP_KERNEL); - if (!hsmp_sem) + plat_dev.sock = devm_kzalloc(&pdev->dev, + (plat_dev.num_sockets * sizeof(struct hsmp_socket)), + GFP_KERNEL); + if (!plat_dev.sock) return -ENOMEM; + plat_dev.dev = &pdev->dev; + + for (i = 0; i < plat_dev.num_sockets; i++) { + sema_init(&plat_dev.sock[i].hsmp_sem, 1); + plat_dev.sock[i].sock_ind = i; + } - for (i = 0; i < amd_nb_num(); i++) - sema_init(&hsmp_sem[i], 1); + plat_dev.hsmp_device.name = HSMP_CDEV_NAME; + plat_dev.hsmp_device.minor = MISC_DYNAMIC_MINOR; + plat_dev.hsmp_device.fops = &hsmp_fops; + plat_dev.hsmp_device.parent = &pdev->dev; + plat_dev.hsmp_device.nodename = HSMP_DEVNODE_NAME; + plat_dev.hsmp_device.mode = 0644; + + ret = hsmp_cache_proto_ver(); + if (ret) { + dev_err(plat_dev.dev, "Failed to read HSMP protocol version\n"); + return ret; + } - hsmp_device.name = "hsmp_cdev"; - hsmp_device.minor = MISC_DYNAMIC_MINOR; - hsmp_device.fops = &hsmp_fops; - hsmp_device.parent = &pdev->dev; - hsmp_device.nodename = "hsmp"; - hsmp_device.mode = 0644; + ret = hsmp_create_sysfs_interface(); + if (ret) + dev_err(plat_dev.dev, "Failed to create HSMP sysfs interface\n"); - return misc_register(&hsmp_device); + return misc_register(&plat_dev.hsmp_device); } static void hsmp_pltdrv_remove(struct platform_device *pdev) { - misc_deregister(&hsmp_device); + misc_deregister(&plat_dev.hsmp_device); } static struct platform_driver amd_hsmp_driver = { @@ -358,7 +544,6 @@ static struct platform_device *amd_hsmp_platdev; static int __init hsmp_plt_init(void) { int ret = -ENODEV; - u16 num_sockets; int i; if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD || boot_cpu_data.x86 < 0x19) { @@ -371,18 +556,18 @@ static int __init hsmp_plt_init(void) * amd_nb_num() returns number of SMN/DF interfaces present in the system * if we have N SMN/DF interfaces that ideally means N sockets */ - num_sockets = amd_nb_num(); - if (num_sockets == 0) + plat_dev.num_sockets = amd_nb_num(); + if (plat_dev.num_sockets == 0) return ret; /* Test the hsmp interface on each socket */ - for (i = 0; i < num_sockets; i++) { + for (i = 0; i < plat_dev.num_sockets; i++) { ret = hsmp_test(i, 0xDEADBEEF); if (ret) { - pr_err("HSMP is not supported on Fam:%x model:%x\n", + pr_err("HSMP test message failed on Fam:%x model:%x\n", boot_cpu_data.x86, boot_cpu_data.x86_model); - pr_err("Or Is HSMP disabled in BIOS ?\n"); - return -EOPNOTSUPP; + pr_err("Is HSMP disabled in BIOS ?\n"); + return ret; } } diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index c1e788b67a74..cd6ac04c1468 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -52,9 +52,13 @@ #define AMD_S2D_REGISTER_ARGUMENT 0xA88 /* STB Spill to DRAM Parameters */ -#define S2D_TELEMETRY_BYTES_MAX 0x100000 +#define S2D_TELEMETRY_BYTES_MAX 0x100000U +#define S2D_RSVD_RAM_SPACE 0x100000 #define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 +/* STB Spill to DRAM Message Definition */ +#define STB_FORCE_FLUSH_DATA 0xCF + /* Base address of SMU for mapping physical address to virtual address */ #define AMD_PMC_MAPPING_SIZE 0x01000 #define AMD_PMC_BASE_ADDR_OFFSET 0x10000 @@ -119,6 +123,11 @@ enum s2d_arg { S2D_DRAM_SIZE, }; +struct amd_pmc_stb_v2_data { + size_t size; + u8 data[] __counted_by(size); +}; + struct amd_pmc_bit_map { const char *name; u32 bit_mask; @@ -157,6 +166,10 @@ static bool disable_workarounds; module_param(disable_workarounds, bool, 0644); MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs"); +static bool dump_custom_stb; +module_param(dump_custom_stb, bool, 0644); +MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer"); + static struct amd_pmc_dev pmc; static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf); @@ -233,10 +246,30 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = { .release = amd_pmc_stb_debugfs_release, }; +/* Enhanced STB Firmware Reporting Mechanism */ +static int amd_pmc_stb_handle_efr(struct file *filp) +{ + struct amd_pmc_dev *dev = filp->f_inode->i_private; + struct amd_pmc_stb_v2_data *stb_data_arr; + u32 fsize; + + fsize = dev->dram_size - S2D_RSVD_RAM_SPACE; + stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); + if (!stb_data_arr) + return -ENOMEM; + + stb_data_arr->size = fsize; + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); + filp->private_data = stb_data_arr; + + return 0; +} + static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) { struct amd_pmc_dev *dev = filp->f_inode->i_private; - u32 *buf, fsize, num_samples, stb_rdptr_offset = 0; + u32 fsize, num_samples, val, stb_rdptr_offset = 0; + struct amd_pmc_stb_v2_data *stb_data_arr; int ret; /* Write dummy postcode while reading the STB buffer */ @@ -244,34 +277,55 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) if (ret) dev_err(dev->dev, "error writing to STB: %d\n", ret); - buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL); - if (!buf) - return -ENOMEM; - /* Spill to DRAM num_samples uses separate SMU message port */ dev->msg_port = 1; + ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1); + if (ret) + dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret); + + /* + * We have a custom stb size and the PMFW is supposed to give + * the enhanced dram size. Note that we land here only for the + * platforms that support enhanced dram size reporting. + */ + if (dump_custom_stb) + return amd_pmc_stb_handle_efr(filp); + /* Get the num_samples to calculate the last push location */ ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true); /* Clear msg_port for other SMU operation */ dev->msg_port = 0; if (ret) { dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); - kfree(buf); return ret; } - /* Start capturing data from the last push location */ + fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX); + stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); + if (!stb_data_arr) + return -ENOMEM; + + stb_data_arr->size = fsize; + + /* + * Start capturing data from the last push location. + * This is for general cases, where the stb limits + * are meant for standard usage. + */ if (num_samples > S2D_TELEMETRY_BYTES_MAX) { - fsize = S2D_TELEMETRY_BYTES_MAX; - stb_rdptr_offset = num_samples - fsize; + /* First read oldest data starting 1 behind last write till end of ringbuffer */ + stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX; + fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset; + + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); + /* Second copy the newer samples from offset 0 - last write */ + memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset); } else { - fsize = num_samples; - stb_rdptr_offset = 0; + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); } - memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize); - filp->private_data = buf; + filp->private_data = stb_data_arr; return 0; } @@ -279,11 +333,9 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size, loff_t *pos) { - if (!filp->private_data) - return -EINVAL; + struct amd_pmc_stb_v2_data *data = filp->private_data; - return simple_read_from_buffer(buf, size, pos, filp->private_data, - S2D_TELEMETRY_BYTES_MAX); + return simple_read_from_buffer(buf, size, pos, data->data, data->size); } static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index abf01e00b799..41227bf95878 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -148,16 +148,12 @@ static int asus_wireless_add(struct acpi_device *adev) if (err) return err; - for (id = device_ids; id->id[0]; id++) { - if (!strcmp((char *) id->id, acpi_device_hid(adev))) { - data->hswc_params = - (const struct hswc_params *)id->driver_data; - break; - } - } - if (!data->hswc_params) + id = acpi_match_acpi_device(device_ids, adev); + if (!id) return 0; + data->hswc_params = (const struct hswc_params *)id->driver_data; + data->wq = create_singlethread_workqueue("asus_wireless_workqueue"); if (!data->wq) return -ENOMEM; diff --git a/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c b/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c index dea54f35b8b5..4da99cb7218d 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c +++ b/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c @@ -19,7 +19,7 @@ struct bios_args { u32 command; u32 commandtype; u32 datasize; - u8 data[]; + u8 data[] __counted_by(datasize); }; /** diff --git a/drivers/platform/x86/intel/bytcrc_pwrsrc.c b/drivers/platform/x86/intel/bytcrc_pwrsrc.c index 8a022b90d12d..418b71af27ff 100644 --- a/drivers/platform/x86/intel/bytcrc_pwrsrc.c +++ b/drivers/platform/x86/intel/bytcrc_pwrsrc.c @@ -158,17 +158,16 @@ static int crc_pwrsrc_probe(struct platform_device *pdev) return 0; } -static int crc_pwrsrc_remove(struct platform_device *pdev) +static void crc_pwrsrc_remove(struct platform_device *pdev) { struct crc_pwrsrc_data *data = platform_get_drvdata(pdev); debugfs_remove_recursive(data->debug_dentry); - return 0; } static struct platform_driver crc_pwrsrc_driver = { .probe = crc_pwrsrc_probe, - .remove = crc_pwrsrc_remove, + .remove_new = crc_pwrsrc_remove, .driver = { .name = "crystal_cove_pwrsrc", }, diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index 306f886b52d2..7b11198d85a1 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2022 Intel Corporation. */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/kdev_t.h> #include <linux/semaphore.h> @@ -10,13 +11,16 @@ #include "ifs.h" -#define X86_MATCH(model) \ +#define X86_MATCH(model, array_gen) \ X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ - INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL) + INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, array_gen) static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { - X86_MATCH(SAPPHIRERAPIDS_X), - X86_MATCH(EMERALDRAPIDS_X), + X86_MATCH(SAPPHIRERAPIDS_X, ARRAY_GEN0), + X86_MATCH(EMERALDRAPIDS_X, ARRAY_GEN0), + X86_MATCH(GRANITERAPIDS_X, ARRAY_GEN0), + X86_MATCH(GRANITERAPIDS_D, ARRAY_GEN0), + X86_MATCH(ATOM_CRESTMONT_X, ARRAY_GEN1), {} }; MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); @@ -94,6 +98,9 @@ static int __init ifs_init(void) for (i = 0; i < IFS_NUMTESTS; i++) { if (!(msrval & BIT(ifs_devices[i].test_caps->integrity_cap_bit))) continue; + ifs_devices[i].rw_data.generation = FIELD_GET(MSR_INTEGRITY_CAPS_SAF_GEN_MASK, + msrval); + ifs_devices[i].rw_data.array_gen = (u32)m->driver_data; ret = misc_register(&ifs_devices[i].misc); if (ret) goto err_exit; diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index 93191855890f..56b9f3e3cf76 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -137,6 +137,10 @@ #define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5 #define MSR_ACTIVATE_SCAN 0x000002c6 #define MSR_SCAN_STATUS 0x000002c7 +#define MSR_ARRAY_TRIGGER 0x000002d6 +#define MSR_ARRAY_STATUS 0x000002d7 +#define MSR_SAF_CTRL 0x000004f0 + #define SCAN_NOT_TESTED 0 #define SCAN_TEST_PASS 1 #define SCAN_TEST_FAIL 2 @@ -144,6 +148,9 @@ #define IFS_TYPE_SAF 0 #define IFS_TYPE_ARRAY_BIST 1 +#define ARRAY_GEN0 0 +#define ARRAY_GEN1 1 + /* MSR_SCAN_HASHES_STATUS bit fields */ union ifs_scan_hashes_status { u64 data; @@ -158,6 +165,19 @@ union ifs_scan_hashes_status { }; }; +union ifs_scan_hashes_status_gen2 { + u64 data; + struct { + u16 chunk_size; + u16 num_chunks; + u32 error_code :8; + u32 chunks_in_stride :9; + u32 rsvd :2; + u32 max_core_limit :12; + u32 valid :1; + }; +}; + /* MSR_CHUNKS_AUTH_STATUS bit fields */ union ifs_chunks_auth_status { u64 data; @@ -170,13 +190,31 @@ union ifs_chunks_auth_status { }; }; +union ifs_chunks_auth_status_gen2 { + u64 data; + struct { + u16 valid_chunks; + u16 total_chunks; + u32 error_code :8; + u32 rsvd2 :24; + }; +}; + /* MSR_ACTIVATE_SCAN bit fields */ union ifs_scan { u64 data; struct { - u32 start :8; - u32 stop :8; - u32 rsvd :16; + union { + struct { + u8 start; + u8 stop; + u16 rsvd; + } gen0; + struct { + u16 start; + u16 stop; + } gen2; + }; u32 delay :31; u32 sigmce :1; }; @@ -186,9 +224,17 @@ union ifs_scan { union ifs_status { u64 data; struct { - u32 chunk_num :8; - u32 chunk_stop_index :8; - u32 rsvd1 :16; + union { + struct { + u8 chunk_num; + u8 chunk_stop_index; + u16 rsvd1; + } gen0; + struct { + u16 chunk_num; + u16 chunk_stop_index; + } gen2; + }; u32 error_code :8; u32 rsvd2 :22; u32 control_error :1; @@ -229,6 +275,9 @@ struct ifs_test_caps { * @status: it holds simple status pass/fail/untested * @scan_details: opaque scan status code from h/w * @cur_batch: number indicating the currently loaded test file + * @generation: IFS test generation enumerated by hardware + * @chunk_size: size of a test chunk + * @array_gen: test generation of array test */ struct ifs_data { int loaded_version; @@ -238,6 +287,9 @@ struct ifs_data { int status; u64 scan_details; u32 cur_batch; + u32 generation; + u32 chunk_size; + u32 array_gen; }; struct ifs_work { diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index cefd0d886cfd..959b1878cae6 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -2,6 +2,7 @@ /* Copyright(c) 2022 Intel Corporation. */ #include <linux/firmware.h> +#include <linux/sizes.h> #include <asm/cpu.h> #include <asm/microcode.h> @@ -26,6 +27,11 @@ union meta_data { #define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel)) #define META_TYPE_IFS 1 +#define INVALIDATE_STRIDE 0x1UL +#define IFS_GEN_STRIDE_AWARE 2 +#define AUTH_INTERRUPTED_ERROR 5 +#define IFS_AUTH_RETRY_CT 10 + static struct microcode_header_intel *ifs_header_ptr; /* pointer to the ifs image header */ static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */ static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */ @@ -44,7 +50,10 @@ static const char * const scan_hash_status[] = { static const char * const scan_authentication_status[] = { [0] = "No error reported", [1] = "Attempt to authenticate a chunk which is already marked as authentic", - [2] = "Chunk authentication error. The hash of chunk did not match expected value" + [2] = "Chunk authentication error. The hash of chunk did not match expected value", + [3] = "Reserved", + [4] = "Chunk outside the current stride", + [5] = "Authentication flow interrupted", }; #define MC_HEADER_META_TYPE_END (0) @@ -80,6 +89,23 @@ static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_typ return NULL; } +static void hashcopy_err_message(struct device *dev, u32 err_code) +{ + if (err_code >= ARRAY_SIZE(scan_hash_status)) + dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); + else + dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]); +} + +static void auth_err_message(struct device *dev, u32 err_code) +{ + if (err_code >= ARRAY_SIZE(scan_authentication_status)) + dev_err(dev, "invalid error code 0x%x for authentication\n", err_code); + else + dev_err(dev, "Chunk authentication error : %s\n", + scan_authentication_status[err_code]); +} + /* * To copy scan hashes and authenticate test chunks, the initiating cpu must point * to the EDX:EAX to the test image in linear address. @@ -109,11 +135,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work) if (!hashes_status.valid) { ifsd->loading_error = true; - if (err_code >= ARRAY_SIZE(scan_hash_status)) { - dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); - goto done; - } - dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]); + hashcopy_err_message(dev, err_code); goto done; } @@ -133,13 +155,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work) if (err_code) { ifsd->loading_error = true; - if (err_code >= ARRAY_SIZE(scan_authentication_status)) { - dev_err(dev, - "invalid error code 0x%x for authentication\n", err_code); - goto done; - } - dev_err(dev, "Chunk authentication error %s\n", - scan_authentication_status[err_code]); + auth_err_message(dev, err_code); goto done; } } @@ -147,6 +163,102 @@ done: complete(&ifs_done); } +static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status) +{ + return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks; +} + +static bool need_copy_scan_hashes(struct ifs_data *ifsd) +{ + return !ifsd->loaded || + ifsd->generation < IFS_GEN_STRIDE_AWARE || + ifsd->loaded_version != ifs_header_ptr->rev; +} + +static int copy_hashes_authenticate_chunks_gen2(struct device *dev) +{ + union ifs_scan_hashes_status_gen2 hashes_status; + union ifs_chunks_auth_status_gen2 chunk_status; + u32 err_code, valid_chunks, total_chunks; + int i, num_chunks, chunk_size; + union meta_data *ifs_meta; + int starting_chunk_nr; + struct ifs_data *ifsd; + u64 linear_addr, base; + u64 chunk_table[2]; + int retry_count; + + ifsd = ifs_get_data(dev); + + if (need_copy_scan_hashes(ifsd)) { + wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr); + rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data); + + /* enumerate the scan image information */ + chunk_size = hashes_status.chunk_size * SZ_1K; + err_code = hashes_status.error_code; + + num_chunks = get_num_chunks(ifsd->generation, hashes_status); + + if (!hashes_status.valid) { + hashcopy_err_message(dev, err_code); + return -EIO; + } + ifsd->loaded_version = ifs_header_ptr->rev; + ifsd->chunk_size = chunk_size; + } else { + num_chunks = ifsd->valid_chunks; + chunk_size = ifsd->chunk_size; + } + + if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) { + wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE); + rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); + if (chunk_status.valid_chunks != 0) { + dev_err(dev, "Couldn't invalidate installed stride - %d\n", + chunk_status.valid_chunks); + return -EIO; + } + } + + base = ifs_test_image_ptr; + ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS); + starting_chunk_nr = ifs_meta->starting_chunk; + + /* scan data authentication and copy chunks to secured memory */ + for (i = 0; i < num_chunks; i++) { + retry_count = IFS_AUTH_RETRY_CT; + linear_addr = base + i * chunk_size; + + chunk_table[0] = starting_chunk_nr + i; + chunk_table[1] = linear_addr; + do { + wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table); + rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); + err_code = chunk_status.error_code; + } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count); + + if (err_code) { + ifsd->loading_error = true; + auth_err_message(dev, err_code); + return -EIO; + } + } + + valid_chunks = chunk_status.valid_chunks; + total_chunks = chunk_status.total_chunks; + + if (valid_chunks != total_chunks) { + ifsd->loading_error = true; + dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n", + valid_chunks, total_chunks); + return -EIO; + } + ifsd->valid_chunks = valid_chunks; + + return 0; +} + static int validate_ifs_metadata(struct device *dev) { struct ifs_data *ifsd = ifs_get_data(dev); @@ -179,6 +291,13 @@ static int validate_ifs_metadata(struct device *dev) return ret; } + if (ifs_meta->chunks_per_stride && + (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) { + dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n", + ifs_meta->starting_chunk, ifs_meta->chunks_per_stride); + return ret; + } + return 0; } @@ -199,7 +318,9 @@ static int scan_chunks_sanity_check(struct device *dev) return ret; ifsd->loading_error = false; - ifsd->loaded_version = ifs_header_ptr->rev; + + if (ifsd->generation > 0) + return copy_hashes_authenticate_chunks_gen2(dev); /* copy the scan hash and authenticate per package */ cpus_read_lock(); @@ -219,6 +340,7 @@ static int scan_chunks_sanity_check(struct device *dev) ifs_pkg_auth[curr_pkg] = 1; } ret = 0; + ifsd->loaded_version = ifs_header_ptr->rev; out: cpus_read_unlock(); @@ -260,6 +382,7 @@ int ifs_load_firmware(struct device *dev) { const struct ifs_test_caps *test = ifs_get_test_caps(dev); struct ifs_data *ifsd = ifs_get_data(dev); + unsigned int expected_size; const struct firmware *fw; char scan_path[64]; int ret = -EINVAL; @@ -274,6 +397,13 @@ int ifs_load_firmware(struct device *dev) goto done; } + expected_size = ((struct microcode_header_intel *)fw->data)->totalsize; + if (fw->size != expected_size) { + dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n", + expected_size, fw->size); + return -EINVAL; + } + ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data); if (ret) goto release; diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 1061eb7ec399..9c1a027bc591 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -40,6 +40,8 @@ enum ifs_status_err_code { IFS_UNASSIGNED_ERROR_CODE = 7, IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8, IFS_INTERRUPTED_DURING_EXECUTION = 9, + IFS_UNASSIGNED_ERROR_CODE_0xA = 0xA, + IFS_CORRUPTED_CHUNK = 0xB, }; static const char * const scan_test_status[] = { @@ -55,6 +57,8 @@ static const char * const scan_test_status[] = { [IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] = "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently", [IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start", + [IFS_UNASSIGNED_ERROR_CODE_0xA] = "Unassigned error code 0xA", + [IFS_CORRUPTED_CHUNK] = "Scan operation aborted due to corrupted image. Try reloading", }; static void message_not_tested(struct device *dev, int cpu, union ifs_status status) @@ -123,6 +127,8 @@ static bool can_restart(union ifs_status status) case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS: case IFS_CORE_NOT_CAPABLE_CURRENTLY: case IFS_UNASSIGNED_ERROR_CODE: + case IFS_UNASSIGNED_ERROR_CODE_0xA: + case IFS_CORRUPTED_CHUNK: break; } return false; @@ -171,21 +177,31 @@ static void ifs_test_core(int cpu, struct device *dev) union ifs_status status; unsigned long timeout; struct ifs_data *ifsd; + int to_start, to_stop; + int status_chunk; u64 msrvals[2]; int retries; ifsd = ifs_get_data(dev); - activate.rsvd = 0; + activate.gen0.rsvd = 0; activate.delay = IFS_THREAD_WAIT; activate.sigmce = 0; - activate.start = 0; - activate.stop = ifsd->valid_chunks - 1; + to_start = 0; + to_stop = ifsd->valid_chunks - 1; + + if (ifsd->generation) { + activate.gen2.start = to_start; + activate.gen2.stop = to_stop; + } else { + activate.gen0.start = to_start; + activate.gen0.stop = to_stop; + } timeout = jiffies + HZ / 2; retries = MAX_IFS_RETRIES; - while (activate.start <= activate.stop) { + while (to_start <= to_stop) { if (time_after(jiffies, timeout)) { status.error_code = IFS_SW_TIMEOUT; break; @@ -196,13 +212,14 @@ static void ifs_test_core(int cpu, struct device *dev) status.data = msrvals[1]; - trace_ifs_status(cpu, activate, status); + trace_ifs_status(cpu, to_start, to_stop, status.data); /* Some cases can be retried, give up for others */ if (!can_restart(status)) break; - if (status.chunk_num == activate.start) { + status_chunk = ifsd->generation ? status.gen2.chunk_num : status.gen0.chunk_num; + if (status_chunk == to_start) { /* Check for forward progress */ if (--retries == 0) { if (status.error_code == IFS_NO_ERROR) @@ -211,7 +228,11 @@ static void ifs_test_core(int cpu, struct device *dev) } } else { retries = MAX_IFS_RETRIES; - activate.start = status.chunk_num; + if (ifsd->generation) + activate.gen2.start = status_chunk; + else + activate.gen0.start = status_chunk; + to_start = status_chunk; } } @@ -308,6 +329,38 @@ static void ifs_array_test_core(int cpu, struct device *dev) ifsd->status = SCAN_TEST_PASS; } +#define ARRAY_GEN1_TEST_ALL_ARRAYS 0x0ULL +#define ARRAY_GEN1_STATUS_FAIL 0x1ULL + +static int do_array_test_gen1(void *status) +{ + int cpu = smp_processor_id(); + int first; + + first = cpumask_first(cpu_smt_mask(cpu)); + + if (cpu == first) { + wrmsrl(MSR_ARRAY_TRIGGER, ARRAY_GEN1_TEST_ALL_ARRAYS); + rdmsrl(MSR_ARRAY_STATUS, *((u64 *)status)); + } + + return 0; +} + +static void ifs_array_test_gen1(int cpu, struct device *dev) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + u64 status = 0; + + stop_core_cpuslocked(cpu, do_array_test_gen1, &status); + ifsd->scan_details = status; + + if (status & ARRAY_GEN1_STATUS_FAIL) + ifsd->status = SCAN_TEST_FAIL; + else + ifsd->status = SCAN_TEST_PASS; +} + /* * Initiate per core test. It wakes up work queue threads on the target cpu and * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and @@ -335,7 +388,10 @@ int do_core_test(int cpu, struct device *dev) ifs_test_core(cpu, dev); break; case IFS_TYPE_ARRAY_BIST: - ifs_array_test_core(cpu, dev); + if (ifsd->array_gen == ARRAY_GEN0) + ifs_array_test_core(cpu, dev); + else + ifs_array_test_gen1(cpu, dev); break; default: return -EINVAL; diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c index ef4b3141efcd..16e36ac0a7b4 100644 --- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c +++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c @@ -162,9 +162,8 @@ out_free_init_name: } int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, u32 polarity) + struct gpio_desc *gpio) { - char *path = agpio->resource_source.string_ptr; struct clk_init_data init = { .ops = &skl_int3472_clock_ops, .flags = CLK_GET_RATE_NOCACHE, @@ -174,26 +173,12 @@ int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472, if (int3472->clock.cl) return -EBUSY; - int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0], - "int3472,clk-enable"); - if (IS_ERR(int3472->clock.ena_gpio)) { - ret = PTR_ERR(int3472->clock.ena_gpio); - int3472->clock.ena_gpio = NULL; - return dev_err_probe(int3472->dev, ret, "getting clk-enable GPIO\n"); - } - - if (polarity == GPIO_ACTIVE_LOW) - gpiod_toggle_active_low(int3472->clock.ena_gpio); - - /* Ensure the pin is in output mode and non-active state */ - gpiod_direction_output(int3472->clock.ena_gpio, 0); + int3472->clock.ena_gpio = gpio; init.name = kasprintf(GFP_KERNEL, "%s-clk", acpi_dev_name(int3472->adev)); - if (!init.name) { - ret = -ENOMEM; - goto out_put_gpio; - } + if (!init.name) + return -ENOMEM; int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472); @@ -219,8 +204,6 @@ err_unregister_clk: clk_unregister(int3472->clock.clk); out_free_init_name: kfree(init.name); -out_put_gpio: - gpiod_put(int3472->clock.ena_gpio); return ret; } @@ -232,7 +215,6 @@ void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472) clkdev_drop(int3472->clock.cl); clk_unregister(int3472->clock.clk); - gpiod_put(int3472->clock.ena_gpio); } /* @@ -273,14 +255,13 @@ static const struct dmi_system_id skl_int3472_regulator_second_sensor[] = { }; int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio) + struct gpio_desc *gpio) { - char *path = agpio->resource_source.string_ptr; struct regulator_init_data init_data = { }; struct regulator_config cfg = { }; const char *second_sensor = NULL; const struct dmi_system_id *id; - int i, j, ret; + int i, j; id = dmi_first_match(skl_int3472_regulator_second_sensor); if (id) @@ -314,16 +295,7 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, int3472->regulator.supply_name, &int3472_gpio_regulator_ops); - int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0], - "int3472,regulator"); - if (IS_ERR(int3472->regulator.gpio)) { - ret = PTR_ERR(int3472->regulator.gpio); - int3472->regulator.gpio = NULL; - return dev_err_probe(int3472->dev, ret, "getting regulator GPIO\n"); - } - - /* Ensure the pin is in output mode and non-active state */ - gpiod_direction_output(int3472->regulator.gpio, 0); + int3472->regulator.gpio = gpio; cfg.dev = &int3472->adev->dev; cfg.init_data = &init_data; @@ -332,21 +304,11 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, int3472->regulator.rdev = regulator_register(int3472->dev, &int3472->regulator.rdesc, &cfg); - if (IS_ERR(int3472->regulator.rdev)) { - ret = PTR_ERR(int3472->regulator.rdev); - goto err_free_gpio; - } - return 0; - -err_free_gpio: - gpiod_put(int3472->regulator.gpio); - - return ret; + return PTR_ERR_OR_ZERO(int3472->regulator.rdev); } void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472) { regulator_unregister(int3472->regulator.rdev); - gpiod_put(int3472->regulator.gpio); } diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h index 9f29baa13860..145dec66df64 100644 --- a/drivers/platform/x86/intel/int3472/common.h +++ b/drivers/platform/x86/intel/int3472/common.h @@ -117,16 +117,15 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev, const char **name_ret); int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, u32 polarity); + struct gpio_desc *gpio); int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472); void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472); int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio); + struct gpio_desc *gpio); void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472); -int skl_int3472_register_pled(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, u32 polarity); +int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio); void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472); #endif diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index e33c2d75975c..07b302e09340 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -52,21 +52,15 @@ static void skl_int3472_log_sensor_module_name(struct int3472_discrete_device *i } } -static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, - const char *func, u32 polarity) +static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry, + struct acpi_resource_gpio *agpio, + const char *func, u32 polarity) { char *path = agpio->resource_source.string_ptr; - struct gpiod_lookup *table_entry; struct acpi_device *adev; acpi_handle handle; acpi_status status; - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(int3472->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) return -EINVAL; @@ -75,18 +69,62 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 if (!adev) return -ENODEV; - table_entry = &int3472->gpios.table[int3472->n_sensor_gpios]; table_entry->key = acpi_dev_name(adev); table_entry->chip_hwnum = agpio->pin_table[0]; table_entry->con_id = func; table_entry->idx = 0; table_entry->flags = polarity; + return 0; +} + +static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio, + const char *func, u32 polarity) +{ + int ret; + + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } + + ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios], + agpio, func, polarity); + if (ret) + return ret; + int3472->n_sensor_gpios++; return 0; } +/* This should *really* only be used when there's no other way... */ +static struct gpio_desc * +skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio, + const char *func, u32 polarity) +{ + struct gpio_desc *desc; + int ret; + + struct gpiod_lookup_table *lookup __free(kfree) = + kzalloc(struct_size(lookup, table, 2), GFP_KERNEL); + if (!lookup) + return ERR_PTR(-ENOMEM); + + lookup->dev_id = dev_name(int3472->dev); + ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, polarity); + if (ret) + return ERR_PTR(ret); + + gpiod_add_lookup_table(lookup); + desc = devm_gpiod_get(int3472->dev, func, GPIOD_OUT_LOW); + gpiod_remove_lookup_table(lookup); + + return desc; +} + static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity) { switch (type) { @@ -156,6 +194,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, struct acpi_resource_gpio *agpio; u8 active_value, pin, type; union acpi_object *obj; + struct gpio_desc *gpio; const char *err_msg; const char *func; u32 polarity; @@ -206,22 +245,38 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_CLK_ENABLE: - ret = skl_int3472_register_gpio_clock(int3472, agpio, polarity); - if (ret) - err_msg = "Failed to register clock\n"; - - break; case INT3472_GPIO_TYPE_PRIVACY_LED: - ret = skl_int3472_register_pled(int3472, agpio, polarity); - if (ret) - err_msg = "Failed to register LED\n"; - - break; case INT3472_GPIO_TYPE_POWER_ENABLE: - ret = skl_int3472_register_regulator(int3472, agpio); - if (ret) - err_msg = "Failed to map regulator to sensor\n"; - + gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, polarity); + if (IS_ERR(gpio)) { + ret = PTR_ERR(gpio); + err_msg = "Failed to get GPIO\n"; + break; + } + + switch (type) { + case INT3472_GPIO_TYPE_CLK_ENABLE: + ret = skl_int3472_register_gpio_clock(int3472, gpio); + if (ret) + err_msg = "Failed to register clock\n"; + + break; + case INT3472_GPIO_TYPE_PRIVACY_LED: + ret = skl_int3472_register_pled(int3472, gpio); + if (ret) + err_msg = "Failed to register LED\n"; + + break; + case INT3472_GPIO_TYPE_POWER_ENABLE: + ret = skl_int3472_register_regulator(int3472, gpio); + if (ret) + err_msg = "Failed to map regulator to sensor\n"; + + break; + default: /* Never reached */ + ret = -EINVAL; + break; + } break; default: dev_warn(int3472->dev, diff --git a/drivers/platform/x86/intel/int3472/led.c b/drivers/platform/x86/intel/int3472/led.c index bca1ce7d0d0c..9cbed694e2ca 100644 --- a/drivers/platform/x86/intel/int3472/led.c +++ b/drivers/platform/x86/intel/int3472/led.c @@ -16,26 +16,15 @@ static int int3472_pled_set(struct led_classdev *led_cdev, return 0; } -int skl_int3472_register_pled(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, u32 polarity) +int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio) { - char *p, *path = agpio->resource_source.string_ptr; + char *p; int ret; if (int3472->pled.classdev.dev) return -EBUSY; - int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0], - "int3472,privacy-led"); - if (IS_ERR(int3472->pled.gpio)) - return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio), - "getting privacy LED GPIO\n"); - - if (polarity == GPIO_ACTIVE_LOW) - gpiod_toggle_active_low(int3472->pled.gpio); - - /* Ensure the pin is in output mode and non-active state */ - gpiod_direction_output(int3472->pled.gpio, 0); + int3472->pled.gpio = gpio; /* Generate the name, replacing the ':' in the ACPI devname with '_' */ snprintf(int3472->pled.name, sizeof(int3472->pled.name), @@ -50,7 +39,7 @@ int skl_int3472_register_pled(struct int3472_discrete_device *int3472, ret = led_classdev_register(int3472->dev, &int3472->pled.classdev); if (ret) - goto err_free_gpio; + return ret; int3472->pled.lookup.provider = int3472->pled.name; int3472->pled.lookup.dev_id = int3472->sensor_name; @@ -58,10 +47,6 @@ int skl_int3472_register_pled(struct int3472_discrete_device *int3472, led_add_lookup(&int3472->pled.lookup); return 0; - -err_free_gpio: - gpiod_put(int3472->pled.gpio); - return ret; } void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472) @@ -71,5 +56,4 @@ void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472) led_remove_lookup(&int3472->pled.lookup); led_classdev_unregister(&int3472->pled.classdev); - gpiod_put(int3472->pled.gpio); } diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c index ff49025ec085..3f4343147dad 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c @@ -18,16 +18,17 @@ struct isst_mmio_range { int beg; int end; + int size; }; static struct isst_mmio_range mmio_range_devid_0[] = { - {0x04, 0x14}, - {0x20, 0xD0}, + {0x04, 0x14, 0x18}, + {0x20, 0xD0, 0xD4}, }; static struct isst_mmio_range mmio_range_devid_1[] = { - {0x04, 0x14}, - {0x20, 0x11C}, + {0x04, 0x14, 0x18}, + {0x20, 0x11C, 0x120}, }; struct isst_if_device { @@ -93,6 +94,7 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct isst_if_device *punit_dev; struct isst_if_cmd_cb cb; u32 mmio_base, pcu_base; + struct resource r; u64 base_addr; int ret; @@ -114,13 +116,16 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pcu_base &= GENMASK(10, 0); base_addr = (u64)mmio_base << 23 | (u64) pcu_base << 12; - punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, 256); - if (!punit_dev->punit_mmio) - return -ENOMEM; + + punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data; + + r = DEFINE_RES_MEM(base_addr, punit_dev->mmio_range[1].size); + punit_dev->punit_mmio = devm_ioremap_resource(&pdev->dev, &r); + if (IS_ERR(punit_dev->punit_mmio)) + return PTR_ERR(punit_dev->punit_mmio); mutex_init(&punit_dev->mutex); pci_set_drvdata(pdev, punit_dev); - punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data; memset(&cb, 0, sizeof(cb)); cb.cmd_size = sizeof(struct isst_if_io_reg); diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index 63faa2ea8327..0b6d2c864437 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -30,7 +30,8 @@ #include "isst_if_common.h" /* Supported SST hardware version by this driver */ -#define ISST_HEADER_VERSION 1 +#define ISST_MAJOR_VERSION 0 +#define ISST_MINOR_VERSION 1 /* * Used to indicate if value read from MMIO needs to get multiplied @@ -352,21 +353,25 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai pd_info->sst_header.cp_offset *= 8; pd_info->sst_header.pp_offset *= 8; - if (pd_info->sst_header.interface_version != ISST_HEADER_VERSION) { - dev_err(&auxdev->dev, "SST: Unsupported version:%x\n", - pd_info->sst_header.interface_version); + if (pd_info->sst_header.interface_version == TPMI_VERSION_INVALID) + return -ENODEV; + + if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) { + dev_err(&auxdev->dev, "SST: Unsupported major version:%lx\n", + TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version)); return -ENODEV; } + if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION) + dev_info(&auxdev->dev, "SST: Ignore: Unsupported minor version:%lx\n", + TPMI_MINOR_VERSION(pd_info->sst_header.interface_version)); + /* Read SST CP Header */ *((u64 *)&pd_info->cp_header) = readq(pd_info->sst_base + pd_info->sst_header.cp_offset); /* Read PP header */ *((u64 *)&pd_info->pp_header) = readq(pd_info->sst_base + pd_info->sst_header.pp_offset); - /* Force level_en_mask level 0 */ - pd_info->pp_header.level_en_mask |= 0x01; - mask = 0x01; levels = 0; for (i = 0; i < 8; ++i) { @@ -704,7 +709,7 @@ static int isst_if_get_perf_level(void __user *argp) return -EINVAL; perf_level.max_level = power_domain_info->max_level; - perf_level.level_mask = power_domain_info->pp_header.allowed_level_mask; + perf_level.level_mask = power_domain_info->pp_header.level_en_mask; perf_level.feature_rev = power_domain_info->pp_header.feature_rev; _read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET, SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 0a95736d97e4..311abcac894a 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -143,6 +143,33 @@ struct tpmi_info_header { u64 lock:1; } __packed; +/** + * struct tpmi_feature_state - Structure to read hardware state of a feature + * @enabled: Enable state of a feature, 1: enabled, 0: disabled + * @reserved_1: Reserved for future use + * @write_blocked: Writes are blocked means all write operations are ignored + * @read_blocked: Reads are blocked means will read 0xFFs + * @pcs_select: Interface used by out of band software, not used in OS + * @reserved_2: Reserved for future use + * @id: TPMI ID of the feature + * @reserved_3: Reserved for future use + * @locked: When set to 1, OS can't change this register. + * + * The structure is used to read hardware state of a TPMI feature. This + * information is used for debug and restricting operations for this feature. + */ +struct tpmi_feature_state { + u32 enabled:1; + u32 reserved_1:3; + u32 write_blocked:1; + u32 read_blocked:1; + u32 pcs_select:1; + u32 reserved_2:1; + u32 id:8; + u32 reserved_3:15; + u32 locked:1; +} __packed; + /* * List of supported TMPI IDs. * Some TMPI IDs are not used by Linux, so the numbers are not consecutive. @@ -202,6 +229,7 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); #define TPMI_CONTROL_STATUS_OFFSET 0x00 #define TPMI_COMMAND_OFFSET 0x08 +#define TMPI_CONTROL_DATA_VAL_OFFSET 0x0c /* * Spec is calling for max 1 seconds to get ownership at the worst @@ -230,7 +258,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); /* TPMI command data registers */ #define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0) -#define TMPI_CONTROL_DATA_VAL GENMASK_ULL(63, 32) #define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40) /* Command to send via control interface */ @@ -240,9 +267,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); #define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16) -#define TPMI_STATE_DISABLED BIT_ULL(0) -#define TPMI_STATE_LOCKED BIT_ULL(31) - /* Mutex to complete get feature status without interruption */ static DEFINE_MUTEX(tpmi_dev_lock); @@ -256,7 +280,7 @@ static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner) } static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id, - int *locked, int *disabled) + struct tpmi_feature_state *feature_state) { u64 control, data; int ret; @@ -306,17 +330,8 @@ static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int featu } /* Response is ready */ - data = readq(tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET); - data = FIELD_GET(TMPI_CONTROL_DATA_VAL, data); - - *disabled = 0; - *locked = 0; - - if (!(data & TPMI_STATE_DISABLED)) - *disabled = 1; - - if (data & TPMI_STATE_LOCKED) - *locked = 1; + memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET, + sizeof(*feature_state)); ret = 0; @@ -335,34 +350,50 @@ int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id, { struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); + struct tpmi_feature_state feature_state; + int ret; + + ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state); + if (ret) + return ret; - return tpmi_read_feature_status(tpmi_info, feature_id, locked, disabled); + *locked = feature_state.locked; + *disabled = !feature_state.enabled; + + return 0; } EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI); static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused) { struct intel_tpmi_info *tpmi_info = s->private; + int locked, disabled, read_blocked, write_blocked; + struct tpmi_feature_state feature_state; struct intel_tpmi_pm_feature *pfs; - int locked, disabled, ret, i; + int ret, i; + seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start); - seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\n"); + seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n"); for (i = 0; i < tpmi_info->feature_count; ++i) { pfs = &tpmi_info->tpmi_features[i]; - ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &locked, - &disabled); + ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state); if (ret) { locked = 'U'; disabled = 'U'; + read_blocked = 'U'; + write_blocked = 'U'; } else { - disabled = disabled ? 'Y' : 'N'; - locked = locked ? 'Y' : 'N'; + disabled = feature_state.enabled ? 'N' : 'Y'; + locked = feature_state.locked ? 'Y' : 'N'; + read_blocked = feature_state.read_blocked ? 'Y' : 'N'; + write_blocked = feature_state.write_blocked ? 'Y' : 'N'; } - seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\n", + seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\t\t%c\t\t%c\n", pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries, pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset, - pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled); + pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled, + read_blocked, write_blocked); } return 0; diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 7d0a67f8b517..4fb790552c47 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -28,7 +28,8 @@ #include "uncore-frequency-common.h" -#define UNCORE_HEADER_VERSION 1 +#define UNCORE_MAJOR_VERSION 0 +#define UNCORE_MINOR_VERSION 1 #define UNCORE_HEADER_INDEX 0 #define UNCORE_FABRIC_CLUSTER_OFFSET 8 @@ -302,12 +303,21 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ /* Check for version and skip this resource if there is mismatch */ header = readq(pd_info->uncore_base); pd_info->ufs_header_ver = header & UNCORE_VERSION_MASK; - if (pd_info->ufs_header_ver != UNCORE_HEADER_VERSION) { - dev_info(&auxdev->dev, "Uncore: Unsupported version:%d\n", - pd_info->ufs_header_ver); + + if (pd_info->ufs_header_ver == TPMI_VERSION_INVALID) continue; + + if (TPMI_MAJOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MAJOR_VERSION) { + dev_err(&auxdev->dev, "Uncore: Unsupported major version:%lx\n", + TPMI_MAJOR_VERSION(pd_info->ufs_header_ver)); + ret = -ENODEV; + goto remove_clusters; } + if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MINOR_VERSION) + dev_info(&auxdev->dev, "Uncore: Ignore: Unsupported minor version:%lx\n", + TPMI_MINOR_VERSION(pd_info->ufs_header_ver)); + /* Get Cluster ID Mask */ cluster_mask = FIELD_GET(UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK, header); if (!cluster_mask) { diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 3d96dbf79a72..32981e2ad3b3 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -368,7 +368,7 @@ struct mlxplat_priv { }; static struct platform_device *mlxplat_dev; -static int mlxplat_i2c_main_complition_notify(void *handle, int id); +static int mlxplat_i2c_main_completion_notify(void *handle, int id); static void __iomem *i2c_bridge_addr, *jtag_bridge_addr; /* Regions for LPC I2C controller and LPC base register space */ @@ -384,7 +384,7 @@ static const struct resource mlxplat_lpc_resources[] = { /* Platform systems default i2c data */ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = { - .completion_notify = mlxplat_i2c_main_complition_notify, + .completion_notify = mlxplat_i2c_main_completion_notify, }; /* Platform i2c next generation systems data */ @@ -409,7 +409,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, - .completion_notify = mlxplat_i2c_main_complition_notify, + .completion_notify = mlxplat_i2c_main_completion_notify, }; /* Platform default channels */ @@ -6291,7 +6291,7 @@ static void mlxplat_pci_fpga_devices_exit(void) } static int -mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) +mlxplat_logicdev_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) { int err; @@ -6302,7 +6302,7 @@ mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_reso return err; } -static void mlxplat_post_exit(void) +static void mlxplat_logicdev_exit(void) { if (lpc_bridge) mlxplat_pci_fpga_devices_exit(); @@ -6310,7 +6310,7 @@ static void mlxplat_post_exit(void) mlxplat_lpc_cpld_device_exit(); } -static int mlxplat_post_init(struct mlxplat_priv *priv) +static int mlxplat_platdevs_init(struct mlxplat_priv *priv) { int i = 0, err; @@ -6407,7 +6407,7 @@ fail_platform_hotplug_register: return err; } -static void mlxplat_pre_exit(struct mlxplat_priv *priv) +static void mlxplat_platdevs_exit(struct mlxplat_priv *priv) { int i; @@ -6429,7 +6429,7 @@ mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, { struct mlxplat_priv *priv = handle; - return mlxplat_post_init(priv); + return mlxplat_platdevs_init(priv); } static int mlxplat_i2c_mux_topology_init(struct mlxplat_priv *priv) @@ -6471,7 +6471,7 @@ static void mlxplat_i2c_mux_topology_exit(struct mlxplat_priv *priv) } } -static int mlxplat_i2c_main_complition_notify(void *handle, int id) +static int mlxplat_i2c_main_completion_notify(void *handle, int id) { struct mlxplat_priv *priv = handle; @@ -6514,6 +6514,7 @@ static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) return 0; fail_mlxplat_i2c_mux_topology_init: + platform_device_unregister(priv->pdev_i2c); fail_platform_i2c_register: fail_mlxplat_mlxcpld_verify_bus_topology: return err; @@ -6521,6 +6522,7 @@ fail_mlxplat_mlxcpld_verify_bus_topology: static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv) { + mlxplat_platdevs_exit(priv); mlxplat_i2c_mux_topology_exit(priv); if (priv->pdev_i2c) platform_device_unregister(priv->pdev_i2c); @@ -6542,7 +6544,7 @@ static int mlxplat_probe(struct platform_device *pdev) mlxplat_dev = pdev; } - err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); + err = mlxplat_logicdev_init(&hotplug_resources, &hotplug_resources_size); if (err) return err; @@ -6597,16 +6599,16 @@ static int mlxplat_probe(struct platform_device *pdev) fail_register_reboot_notifier: fail_regcache_sync: - mlxplat_pre_exit(priv); + mlxplat_i2c_main_exit(priv); fail_mlxplat_i2c_main_init: fail_regmap_write: fail_alloc: - mlxplat_post_exit(); + mlxplat_logicdev_exit(); return err; } -static int mlxplat_remove(struct platform_device *pdev) +static void mlxplat_remove(struct platform_device *pdev) { struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); @@ -6614,10 +6616,8 @@ static int mlxplat_remove(struct platform_device *pdev) pm_power_off = NULL; if (mlxplat_reboot_nb) unregister_reboot_notifier(mlxplat_reboot_nb); - mlxplat_pre_exit(priv); mlxplat_i2c_main_exit(priv); - mlxplat_post_exit(); - return 0; + mlxplat_logicdev_exit(); } static const struct acpi_device_id mlxplat_acpi_table[] = { @@ -6633,7 +6633,7 @@ static struct platform_driver mlxplat_driver = { .probe_type = PROBE_FORCE_SYNCHRONOUS, }, .probe = mlxplat_probe, - .remove = mlxplat_remove, + .remove_new = mlxplat_remove, }; static int __init mlxplat_init(void) diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c index f26a3121092f..2be92ba45926 100644 --- a/drivers/platform/x86/msi-ec.c +++ b/drivers/platform/x86/msi-ec.c @@ -58,7 +58,7 @@ static struct msi_ec_conf CONF0 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, .bit = 4, }, @@ -138,7 +138,7 @@ static struct msi_ec_conf CONF1 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, .bit = 4, }, @@ -215,7 +215,7 @@ static struct msi_ec_conf CONF2 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xe8, .bit = 4, }, @@ -294,7 +294,7 @@ static struct msi_ec_conf CONF3 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xe8, .bit = 4, }, @@ -372,7 +372,7 @@ static struct msi_ec_conf CONF4 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = MSI_EC_ADDR_UNKNOWN, // supported, but unknown .bit = 4, }, @@ -451,7 +451,7 @@ static struct msi_ec_conf CONF5 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { // todo: reverse + .fn_win_swap = { // todo: reverse .address = 0xbf, .bit = 4, }, @@ -529,7 +529,7 @@ static struct msi_ec_conf CONF6 __initdata = { .block_address = MSI_EC_ADDR_UNSUPP, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, // todo: reverse .bit = 4, }, @@ -609,7 +609,7 @@ static struct msi_ec_conf CONF7 __initdata = { .block_address = MSI_EC_ADDR_UNSUPP, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, // needs testing .bit = 4, }, @@ -668,6 +668,467 @@ static struct msi_ec_conf CONF7 __initdata = { }, }; +static const char * const ALLOWED_FW_8[] __initconst = { + "14F1EMS1.115", + NULL +}; + +static struct msi_ec_conf CONF8 __initdata = { + .allowed_fw = ALLOWED_FW_8, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = MSI_EC_ADDR_UNSUPP, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = 0xeb, + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_BASIC_NAME, 0x4d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, + .rt_fan_speed_base_min = 0x19, + .rt_fan_speed_base_max = 0x37, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNKNOWN, + .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN, + }, + .leds = { + .micmute_led_address = MSI_EC_ADDR_UNSUPP, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ? + .bl_modes = { 0x00, 0x08 }, // ? + .max_mode = 1, // ? + .bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_9[] __initconst = { + "14JKEMS1.104", + NULL +}; + +static struct msi_ec_conf CONF9 __initdata = { + .allowed_fw = ALLOWED_FW_9, + .charge_control = { + .address = 0xef, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xbf, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xf2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xf4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, + .rt_fan_speed_base_min = 0x00, + .rt_fan_speed_base_max = 0x96, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNSUPP, + .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, + }, + .leds = { + .micmute_led_address = 0x2b, + .mute_led_address = 0x2c, + .bit = 2, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app + .bl_modes = { 0x00, 0x08 }, + .max_mode = 1, + .bl_state_address = 0xf3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_10[] __initconst = { + "1582EMS1.107", // GF66 11UC + NULL +}; + +static struct msi_ec_conf CONF10 __initdata = { + .allowed_fw = ALLOWED_FW_10, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = MSI_EC_ADDR_UNSUPP, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + { SM_TURBO_NAME, 0xc4 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = 0xe5, + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, // ? + .rt_fan_speed_base_min = 0x19, + .rt_fan_speed_base_max = 0x37, + .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ? + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = 0x80, + .rt_fan_speed_address = 0x89, + }, + .leds = { + .micmute_led_address = 0x2c, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = 0x2c, + .bl_modes = { 0x00, 0x08 }, + .max_mode = 1, + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_11[] __initconst = { + "16S6EMS1.111", // Prestige 15 a11scx + "1552EMS1.115", // Modern 15 a11m + NULL +}; + +static struct msi_ec_conf CONF11 __initdata = { + .allowed_fw = ALLOWED_FW_11, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = MSI_EC_ADDR_UNKNOWN, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = 0xeb, + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x4d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNSUPP, + .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, + }, + .leds = { + .micmute_led_address = 0x2c, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNKNOWN, + .bl_modes = {}, // ? + .max_mode = 1, // ? + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_12[] __initconst = { + "16R6EMS1.104", // GF63 Thin 11UC + NULL +}; + +static struct msi_ec_conf CONF12 __initdata = { + .allowed_fw = ALLOWED_FW_12, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + { SM_TURBO_NAME, 0xc4 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = MSI_EC_ADDR_UNSUPP, // 0xeb + .mask = 0x0f, // 00, 0f + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, + .rt_fan_speed_base_min = 0x19, + .rt_fan_speed_base_max = 0x37, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNSUPP, + .rt_fan_speed_address = 0x89, + }, + .leds = { + .micmute_led_address = MSI_EC_ADDR_UNSUPP, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNKNOWN, + .bl_modes = { 0x00, 0x08 }, + .max_mode = 1, + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_13[] __initconst = { + "1594EMS1.109", // MSI Prestige 16 Studio A13VE + NULL +}; + +static struct msi_ec_conf CONF13 __initdata = { + .allowed_fw = ALLOWED_FW_13, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, // 0x00-0x10 + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, // super battery + { SM_COMFORT_NAME, 0xc1 }, // balanced + { SM_TURBO_NAME, 0xc4 }, // extreme + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = MSI_EC_ADDR_UNSUPP, + .mask = 0x0f, // 00, 0f + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, // 0x0-0x96 + .rt_fan_speed_base_min = 0x00, + .rt_fan_speed_base_max = 0x96, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = 0x80, + .rt_fan_speed_address = 0x89, + }, + .leds = { + .micmute_led_address = 0x2c, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = 0x2c, // KB auto turn off + .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec + .max_mode = 1, + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + static struct msi_ec_conf *CONFIGS[] __initdata = { &CONF0, &CONF1, @@ -677,6 +1138,12 @@ static struct msi_ec_conf *CONFIGS[] __initdata = { &CONF5, &CONF6, &CONF7, + &CONF8, + &CONF9, + &CONF10, + &CONF11, + &CONF12, + &CONF13, NULL }; diff --git a/drivers/platform/x86/msi-ec.h b/drivers/platform/x86/msi-ec.h index be3533dc9cc6..086351217505 100644 --- a/drivers/platform/x86/msi-ec.h +++ b/drivers/platform/x86/msi-ec.h @@ -40,7 +40,7 @@ struct msi_ec_webcam_conf { int bit; }; -struct msi_ec_fn_super_swap_conf { +struct msi_ec_fn_win_swap_conf { int address; int bit; }; @@ -108,7 +108,7 @@ struct msi_ec_conf { struct msi_ec_charge_control_conf charge_control; struct msi_ec_webcam_conf webcam; - struct msi_ec_fn_super_swap_conf fn_super_swap; + struct msi_ec_fn_win_swap_conf fn_win_swap; struct msi_ec_cooler_boost_conf cooler_boost; struct msi_ec_shift_mode_conf shift_mode; struct msi_ec_super_battery_conf super_battery; diff --git a/drivers/platform/x86/sel3350-platform.c b/drivers/platform/x86/sel3350-platform.c index fa267d0d3778..d09e976e7148 100644 --- a/drivers/platform/x86/sel3350-platform.c +++ b/drivers/platform/x86/sel3350-platform.c @@ -218,15 +218,13 @@ err_platform: return rs; } -static int sel3350_remove(struct platform_device *pdev) +static void sel3350_remove(struct platform_device *pdev) { struct sel3350_data *sel3350 = platform_get_drvdata(pdev); platform_device_unregister(sel3350->leds_pdev); gpiod_remove_lookup_table(&sel3350_gpios_table); gpiod_remove_lookup_table(&sel3350_leds_table); - - return 0; } static const struct acpi_device_id sel3350_device_ids[] = { @@ -237,7 +235,7 @@ MODULE_DEVICE_TABLE(acpi, sel3350_device_ids); static struct platform_driver sel3350_platform_driver = { .probe = sel3350_probe, - .remove = sel3350_remove, + .remove_new = sel3350_remove, .driver = { .name = "sel3350-platform", .acpi_match_table = sel3350_device_ids, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c index 8a67979d8f96..31a139d87d9a 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c @@ -25,9 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = { }, }; -static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev) +static void simatic_ipc_batt_apollolake_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e); + simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e); } static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) @@ -37,7 +37,7 @@ static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_apollolake_probe, - .remove = simatic_ipc_batt_apollolake_remove, + .remove_new = simatic_ipc_batt_apollolake_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c index 607d033911a2..a7676f224075 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c @@ -25,9 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = { }, }; -static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev) +static void simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a); + simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a); } static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) @@ -37,7 +37,7 @@ static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_elkhartlake_probe, - .remove = simatic_ipc_batt_elkhartlake_remove, + .remove_new = simatic_ipc_batt_elkhartlake_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c index a66107e0fe1e..5e77e05fdb5d 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c @@ -45,9 +45,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_59a = { } }; -static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev) +static void simatic_ipc_batt_f7188x_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, batt_lookup_table); + simatic_ipc_batt_remove(pdev, batt_lookup_table); } static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) @@ -73,7 +73,7 @@ static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_f7188x_probe, - .remove = simatic_ipc_batt_f7188x_remove, + .remove_new = simatic_ipc_batt_f7188x_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c index ef28c806b383..c6dd263b4ee3 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.c @@ -146,10 +146,9 @@ static const struct hwmon_chip_info simatic_ipc_batt_chip_info = { .info = simatic_ipc_batt_info, }; -int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table) +void simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table) { gpiod_remove_lookup_table(table); - return 0; } EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove); @@ -228,9 +227,9 @@ out: } EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe); -static int simatic_ipc_batt_io_remove(struct platform_device *pdev) +static void simatic_ipc_batt_io_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, NULL); + simatic_ipc_batt_remove(pdev, NULL); } static int simatic_ipc_batt_io_probe(struct platform_device *pdev) @@ -240,7 +239,7 @@ static int simatic_ipc_batt_io_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_io_probe, - .remove = simatic_ipc_batt_io_remove, + .remove_new = simatic_ipc_batt_io_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.h b/drivers/platform/x86/siemens/simatic-ipc-batt.h index 4545cd3e3026..89891db26a2c 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt.h +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.h @@ -14,7 +14,7 @@ int simatic_ipc_batt_probe(struct platform_device *pdev, struct gpiod_lookup_table *table); -int simatic_ipc_batt_remove(struct platform_device *pdev, - struct gpiod_lookup_table *table); +void simatic_ipc_batt_remove(struct platform_device *pdev, + struct gpiod_lookup_table *table); #endif /* _SIMATIC_IPC_BATT_H */ diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d70c89d32534..9c19624a7454 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10785,6 +10785,89 @@ static struct ibm_struct dprc_driver_data = { .name = "dprc", }; +/* + * Auxmac + * + * This auxiliary mac address is enabled in the bios through the + * MAC Address Pass-through feature. In most cases, there are three + * possibilities: Internal Mac, Second Mac, and disabled. + * + */ + +#define AUXMAC_LEN 12 +#define AUXMAC_START 9 +#define AUXMAC_STRLEN 22 +#define AUXMAC_BEGIN_MARKER 8 +#define AUXMAC_END_MARKER 21 + +static char auxmac[AUXMAC_LEN + 1]; + +static int auxmac_init(struct ibm_init_struct *iibm) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + status = acpi_evaluate_object(NULL, "\\MACA", NULL, &buffer); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + obj = buffer.pointer; + + if (obj->type != ACPI_TYPE_STRING || obj->string.length != AUXMAC_STRLEN) { + pr_info("Invalid buffer for MAC address pass-through.\n"); + goto auxmacinvalid; + } + + if (obj->string.pointer[AUXMAC_BEGIN_MARKER] != '#' || + obj->string.pointer[AUXMAC_END_MARKER] != '#') { + pr_info("Invalid header for MAC address pass-through.\n"); + goto auxmacinvalid; + } + + if (strncmp(obj->string.pointer + AUXMAC_START, "XXXXXXXXXXXX", AUXMAC_LEN) != 0) + strscpy(auxmac, obj->string.pointer + AUXMAC_START, sizeof(auxmac)); + else + strscpy(auxmac, "disabled", sizeof(auxmac)); + +free: + kfree(obj); + return 0; + +auxmacinvalid: + strscpy(auxmac, "unavailable", sizeof(auxmac)); + goto free; +} + +static struct ibm_struct auxmac_data = { + .name = "auxmac", +}; + +static ssize_t auxmac_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", auxmac); +} +static DEVICE_ATTR_RO(auxmac); + +static umode_t auxmac_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return auxmac[0] == 0 ? 0 : attr->mode; +} + +static struct attribute *auxmac_attributes[] = { + &dev_attr_auxmac.attr, + NULL +}; + +static const struct attribute_group auxmac_attr_group = { + .is_visible = auxmac_attr_is_visible, + .attrs = auxmac_attributes, +}; + /* --------------------------------------------------------------------- */ static struct attribute *tpacpi_driver_attributes[] = { @@ -10843,6 +10926,7 @@ static const struct attribute_group *tpacpi_groups[] = { &proxsensor_attr_group, &kbdlang_attr_group, &dprc_attr_group, + &auxmac_attr_group, NULL, }; @@ -11414,6 +11498,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { .init = tpacpi_dprc_init, .data = &dprc_driver_data, }, + { + .init = auxmac_init, + .data = &auxmac_data, + }, }; static int __init set_ibm_param(const char *val, const struct kernel_param *kp) diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c index 391f7ea4431e..df2bf1c58523 100644 --- a/drivers/platform/x86/xo15-ebook.c +++ b/drivers/platform/x86/xo15-ebook.c @@ -81,9 +81,9 @@ static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume); static int ebook_switch_add(struct acpi_device *device) { + const struct acpi_device_id *id; struct ebook_switch *button; struct input_dev *input; - const char *hid = acpi_device_hid(device); char *name, *class; int error; @@ -102,8 +102,9 @@ static int ebook_switch_add(struct acpi_device *device) name = acpi_device_name(device); class = acpi_device_class(device); - if (strcmp(hid, XO15_EBOOK_HID)) { - pr_err("Unsupported hid [%s]\n", hid); + id = acpi_match_acpi_device(ebook_device_ids, device); + if (!id) { + dev_err(&device->dev, "Unsupported hid\n"); error = -ENODEV; goto err_free_input; } @@ -111,7 +112,7 @@ static int ebook_switch_add(struct acpi_device *device) strcpy(name, XO15_EBOOK_DEVICE_NAME); sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); - snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); input->name = name; input->phys = button->phys; diff --git a/include/linux/intel_tpmi.h b/include/linux/intel_tpmi.h index 04d937ad4dc4..ee07393445f9 100644 --- a/include/linux/intel_tpmi.h +++ b/include/linux/intel_tpmi.h @@ -6,6 +6,12 @@ #ifndef _INTEL_TPMI_H_ #define _INTEL_TPMI_H_ +#include <linux/bitfield.h> + +#define TPMI_VERSION_INVALID 0xff +#define TPMI_MINOR_VERSION(val) FIELD_GET(GENMASK(4, 0), val) +#define TPMI_MAJOR_VERSION(val) FIELD_GET(GENMASK(7, 5), val) + /** * struct intel_tpmi_plat_info - Platform information for a TPMI device instance * @package_id: CPU Package id diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index cb7980805920..5b67f0f47d80 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -44,7 +44,7 @@ struct ssam_event { u8 command_id; u8 instance_id; u16 length; - u8 data[]; + u8 data[] __counted_by(length); }; /** diff --git a/include/trace/events/intel_ifs.h b/include/trace/events/intel_ifs.h index d7353024016c..af0af3f1d9b7 100644 --- a/include/trace/events/intel_ifs.h +++ b/include/trace/events/intel_ifs.h @@ -10,25 +10,25 @@ TRACE_EVENT(ifs_status, - TP_PROTO(int cpu, union ifs_scan activate, union ifs_status status), + TP_PROTO(int cpu, int start, int stop, u64 status), - TP_ARGS(cpu, activate, status), + TP_ARGS(cpu, start, stop, status), TP_STRUCT__entry( __field( u64, status ) __field( int, cpu ) - __field( u8, start ) - __field( u8, stop ) + __field( u16, start ) + __field( u16, stop ) ), TP_fast_assign( __entry->cpu = cpu; - __entry->start = activate.start; - __entry->stop = activate.stop; - __entry->status = status.data; + __entry->start = start; + __entry->stop = stop; + __entry->status = status; ), - TP_printk("cpu: %d, start: %.2x, stop: %.2x, status: %llx", + TP_printk("cpu: %d, start: %.4x, stop: %.4x, status: %.16llx", __entry->cpu, __entry->start, __entry->stop, |