Merge branches 'acpi-pm', 'acpi-video', 'acpi-apei' and 'acpi-extlog'

Merge an ACPI power management change, ACPI backlight driver changes, APEI
updates and ACPI extlog driver changes for 6.8-rc1:

 - Modify the ACPI LPIT table handling code to avoid u32 multiplication
   overflows in state residency computations (Nikita Kiryushin).

 - Drop an unused helper function from the ACPI backlight (video) driver
   and add a clarifying comment to it (Hans de Goede).

 - Update the ACPI backlight driver to avoid using uninitialized memory
   in some cases (Nikita Kiryushin).

 - Add ACPI backlight quirk for the Colorful X15 AT 23 laptop (Yuluo
   Qiu).

 - Add support for vendor-defined error types to the ACPI APEI error
   injection code (Avadhut Naik).

 - Adjust APEI to properly set MF_ACTION_REQUIRED on synchronous memory
   failure events, so they are handled differently from the asynchronous
   ones (Shuai Xue).

 - Fix NULL pointer dereference check in the ACPI extlog driver (Prarit
   Bhargava).

 - Adjust the ACPI extlog driver to clear the Extended Error Log status
   when RAS_CEC handled the error (Tony Luck).

* acpi-pm:
  ACPI: LPIT: Avoid u32 multiplication overflow

* acpi-video:
  ACPI: video: Add quirk for the Colorful X15 AT 23 Laptop
  ACPI: video: check for error while searching for backlight device parent
  ACPI: video: Drop should_check_lcd_flag()
  ACPI: video: Add comment about acpi_video_backlight_use_native() usage

* acpi-apei:
  ACPI: APEI: set memory failure flags as MF_ACTION_REQUIRED on synchronous events
  ACPI: APEI: EINJ: Add support for vendor defined error types
  platform/chrome: cros_ec_debugfs: Fix permissions for panicinfo
  fs: debugfs: Add write functionality to debugfs blobs
  ACPI: APEI: EINJ: Refactor available_error_type_show()

* acpi-extlog:
  ACPI: extlog: Clear Extended Error Log status when RAS_CEC handled the error
  ACPI: extlog: fix NULL pointer dereference check
This commit is contained in:
Rafael J. Wysocki 2024-01-04 13:19:40 +01:00
8 changed files with 130 additions and 100 deletions

View File

@ -145,9 +145,14 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
static u32 err_seq;
estatus = extlog_elog_entry_check(cpu, bank);
if (estatus == NULL || (mce->kflags & MCE_HANDLED_CEC))
if (!estatus)
return NOTIFY_DONE;
if (mce->kflags & MCE_HANDLED_CEC) {
estatus->block_status = 0;
return NOTIFY_DONE;
}
memcpy(elog_buf, (void *)estatus, ELOG_ENTRY_LEN);
/* clear record status to enable BIOS to update it again */
estatus->block_status = 0;
@ -303,9 +308,10 @@ err:
static void __exit extlog_exit(void)
{
mce_unregister_decode_chain(&extlog_mce_dec);
((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
if (extlog_l1_addr)
if (extlog_l1_addr) {
((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
}
if (elog_addr)
acpi_os_unmap_iomem(elog_addr, elog_size);
release_mem_region(elog_base, elog_size);

View File

@ -105,7 +105,7 @@ static void lpit_update_residency(struct lpit_residency_info *info,
return;
info->frequency = lpit_native->counter_frequency ?
lpit_native->counter_frequency : tsc_khz * 1000;
lpit_native->counter_frequency : mul_u32_u32(tsc_khz, 1000U);
if (!info->frequency)
info->frequency = 1;

View File

@ -67,7 +67,7 @@ MODULE_PARM_DESC(hw_changes_brightness,
static bool device_id_scheme = false;
module_param(device_id_scheme, bool, 0444);
static int only_lcd = -1;
static int only_lcd;
module_param(only_lcd, int, 0444);
static bool may_report_brightness_keys;
@ -500,6 +500,15 @@ static const struct dmi_system_id video_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
},
},
{
.callback = video_set_report_key_events,
.driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS),
.ident = "COLORFUL X15 AT 23",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "COLORFUL"),
DMI_MATCH(DMI_PRODUCT_NAME, "X15 AT 23"),
},
},
/*
* Some machines change the brightness themselves when a brightness
* hotkey gets pressed, despite us telling them not to. In this case
@ -1713,12 +1722,12 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
return;
count++;
acpi_get_parent(device->dev->handle, &acpi_parent);
pdev = acpi_get_pci_dev(acpi_parent);
if (pdev) {
parent = &pdev->dev;
pci_dev_put(pdev);
if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) {
pdev = acpi_get_pci_dev(acpi_parent);
if (pdev) {
parent = &pdev->dev;
pci_dev_put(pdev);
}
}
memset(&props, 0, sizeof(struct backlight_properties));
@ -2137,57 +2146,6 @@ static int __init intel_opregion_present(void)
return opregion;
}
/* Check if the chassis-type indicates there is no builtin LCD panel */
static bool dmi_is_desktop(void)
{
const char *chassis_type;
unsigned long type;
chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
if (!chassis_type)
return false;
if (kstrtoul(chassis_type, 10, &type) != 0)
return false;
switch (type) {
case 0x03: /* Desktop */
case 0x04: /* Low Profile Desktop */
case 0x05: /* Pizza Box */
case 0x06: /* Mini Tower */
case 0x07: /* Tower */
case 0x10: /* Lunch Box */
case 0x11: /* Main Server Chassis */
return true;
}
return false;
}
/*
* We're seeing a lot of bogus backlight interfaces on newer machines
* without a LCD such as desktops, servers and HDMI sticks. Checking the
* lcd flag fixes this, enable this by default on any machines which are:
* 1. Win8 ready (where we also prefer the native backlight driver, so
* normally the acpi_video code should not register there anyways); *and*
* 2.1 Report a desktop/server DMI chassis-type, or
* 2.2 Are an ACPI-reduced-hardware platform (and thus won't use the EC for
backlight control)
*/
static bool should_check_lcd_flag(void)
{
if (!acpi_osi_is_win8())
return false;
if (dmi_is_desktop())
return true;
if (acpi_reduced_hardware())
return true;
return false;
}
int acpi_video_register(void)
{
int ret = 0;
@ -2201,9 +2159,6 @@ int acpi_video_register(void)
goto leave;
}
if (only_lcd == -1)
only_lcd = should_check_lcd_flag();
dmi_check_system(video_dmi_table);
ret = acpi_bus_register_driver(&acpi_video_bus);

View File

@ -73,6 +73,7 @@ static u32 notrigger;
static u32 vendor_flags;
static struct debugfs_blob_wrapper vendor_blob;
static struct debugfs_blob_wrapper vendor_errors;
static char vendor_dev[64];
/*
@ -182,6 +183,21 @@ static int einj_timedout(u64 *t)
return 0;
}
static void get_oem_vendor_struct(u64 paddr, int offset,
struct vendor_error_type_extension *v)
{
unsigned long vendor_size;
u64 target_pa = paddr + offset + sizeof(struct vendor_error_type_extension);
vendor_size = v->length - sizeof(struct vendor_error_type_extension);
if (vendor_size)
vendor_errors.data = acpi_os_map_memory(target_pa, vendor_size);
if (vendor_errors.data)
vendor_errors.size = vendor_size;
}
static void check_vendor_extension(u64 paddr,
struct set_error_type_with_address *v5param)
{
@ -194,6 +210,7 @@ static void check_vendor_extension(u64 paddr,
v = acpi_os_map_iomem(paddr + offset, sizeof(*v));
if (!v)
return;
get_oem_vendor_struct(paddr, offset, v);
sbdf = v->pcie_sbdf;
sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",
sbdf >> 24, (sbdf >> 16) & 0xff,
@ -577,38 +594,40 @@ static u64 error_param2;
static u64 error_param3;
static u64 error_param4;
static struct dentry *einj_debug_dir;
static const char * const einj_error_type_string[] = {
"0x00000001\tProcessor Correctable\n",
"0x00000002\tProcessor Uncorrectable non-fatal\n",
"0x00000004\tProcessor Uncorrectable fatal\n",
"0x00000008\tMemory Correctable\n",
"0x00000010\tMemory Uncorrectable non-fatal\n",
"0x00000020\tMemory Uncorrectable fatal\n",
"0x00000040\tPCI Express Correctable\n",
"0x00000080\tPCI Express Uncorrectable non-fatal\n",
"0x00000100\tPCI Express Uncorrectable fatal\n",
"0x00000200\tPlatform Correctable\n",
"0x00000400\tPlatform Uncorrectable non-fatal\n",
"0x00000800\tPlatform Uncorrectable fatal\n",
"0x00001000\tCXL.cache Protocol Correctable\n",
"0x00002000\tCXL.cache Protocol Uncorrectable non-fatal\n",
"0x00004000\tCXL.cache Protocol Uncorrectable fatal\n",
"0x00008000\tCXL.mem Protocol Correctable\n",
"0x00010000\tCXL.mem Protocol Uncorrectable non-fatal\n",
"0x00020000\tCXL.mem Protocol Uncorrectable fatal\n",
static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
{ BIT(0), "Processor Correctable" },
{ BIT(1), "Processor Uncorrectable non-fatal" },
{ BIT(2), "Processor Uncorrectable fatal" },
{ BIT(3), "Memory Correctable" },
{ BIT(4), "Memory Uncorrectable non-fatal" },
{ BIT(5), "Memory Uncorrectable fatal" },
{ BIT(6), "PCI Express Correctable" },
{ BIT(7), "PCI Express Uncorrectable non-fatal" },
{ BIT(8), "PCI Express Uncorrectable fatal" },
{ BIT(9), "Platform Correctable" },
{ BIT(10), "Platform Uncorrectable non-fatal" },
{ BIT(11), "Platform Uncorrectable fatal"},
{ BIT(12), "CXL.cache Protocol Correctable" },
{ BIT(13), "CXL.cache Protocol Uncorrectable non-fatal" },
{ BIT(14), "CXL.cache Protocol Uncorrectable fatal" },
{ BIT(15), "CXL.mem Protocol Correctable" },
{ BIT(16), "CXL.mem Protocol Uncorrectable non-fatal" },
{ BIT(17), "CXL.mem Protocol Uncorrectable fatal" },
{ BIT(31), "Vendor Defined Error Types" },
};
static int available_error_type_show(struct seq_file *m, void *v)
{
int rc;
u32 available_error_type = 0;
u32 error_type = 0;
rc = einj_get_available_error_type(&available_error_type);
rc = einj_get_available_error_type(&error_type);
if (rc)
return rc;
for (int pos = 0; pos < ARRAY_SIZE(einj_error_type_string); pos++)
if (available_error_type & BIT(pos))
seq_puts(m, einj_error_type_string[pos]);
if (error_type & einj_error_type_string[pos].mask)
seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask,
einj_error_type_string[pos].str);
return 0;
}
@ -767,6 +786,10 @@ static int __init einj_init(void)
einj_debug_dir, &vendor_flags);
}
if (vendor_errors.size)
debugfs_create_blob("oem_error", 0600, einj_debug_dir,
&vendor_errors);
pr_info("Error INJection is initialized.\n");
return 0;
@ -792,6 +815,8 @@ static void __exit einj_exit(void)
sizeof(struct einj_parameter);
acpi_os_unmap_iomem(einj_param, size);
if (vendor_errors.size)
acpi_os_unmap_memory(vendor_errors.data, vendor_errors.size);
}
einj_exec_ctx_init(&ctx);
apei_exec_post_unmap_gars(&ctx);

View File

@ -101,6 +101,20 @@ static inline bool is_hest_type_generic_v2(struct ghes *ghes)
return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
}
/*
* A platform may describe one error source for the handling of synchronous
* errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI
* or External Interrupt). On x86, the HEST notifications are always
* asynchronous, so only SEA on ARM is delivered as a synchronous
* notification.
*/
static inline bool is_hest_sync_notify(struct ghes *ghes)
{
u8 notify_type = ghes->generic->notify.type;
return notify_type == ACPI_HEST_NOTIFY_SEA;
}
/*
* This driver isn't really modular, however for the time being,
* continuing to use module_param is the easiest way to remain
@ -489,7 +503,7 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags)
}
static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
int sev)
int sev, bool sync)
{
int flags = -1;
int sec_sev = ghes_severity(gdata->error_severity);
@ -503,7 +517,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
(gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
flags = MF_SOFT_OFFLINE;
if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
flags = 0;
flags = sync ? MF_ACTION_REQUIRED : 0;
if (flags != -1)
return ghes_do_memory_failure(mem_err->physical_addr, flags);
@ -511,9 +525,11 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
return false;
}
static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev)
static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
int sev, bool sync)
{
struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
int flags = sync ? MF_ACTION_REQUIRED : 0;
bool queued = false;
int sec_sev, i;
char *p;
@ -538,7 +554,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int s
* and don't filter out 'corrected' error here.
*/
if (is_cache && has_pa) {
queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0);
queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags);
p += err_info->length;
continue;
}
@ -666,6 +682,7 @@ static bool ghes_do_proc(struct ghes *ghes,
const guid_t *fru_id = &guid_null;
char *fru_text = "";
bool queued = false;
bool sync = is_hest_sync_notify(ghes);
sev = ghes_severity(estatus->error_severity);
apei_estatus_for_each_section(estatus, gdata) {
@ -683,13 +700,13 @@ static bool ghes_do_proc(struct ghes *ghes,
atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err);
arch_apei_report_mem_error(sev, mem_err);
queued = ghes_handle_memory_failure(gdata, sev);
queued = ghes_handle_memory_failure(gdata, sev, sync);
}
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
ghes_handle_aer(gdata);
}
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
queued = ghes_handle_arm_hw_error(gdata, sev);
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
} else {
void *err = acpi_hest_get_payload(gdata);

View File

@ -454,7 +454,7 @@ static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
debug_info->panicinfo_blob.data = data;
debug_info->panicinfo_blob.size = ret;
debugfs_create_blob("panicinfo", S_IFREG | 0444, debug_info->dir,
debugfs_create_blob("panicinfo", 0444, debug_info->dir,
&debug_info->panicinfo_blob);
return 0;

View File

@ -1100,17 +1100,35 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf,
return r;
}
static ssize_t write_file_blob(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct debugfs_blob_wrapper *blob = file->private_data;
struct dentry *dentry = F_DENTRY(file);
ssize_t r;
r = debugfs_file_get(dentry);
if (unlikely(r))
return r;
r = simple_write_to_buffer(blob->data, blob->size, ppos, user_buf,
count);
debugfs_file_put(dentry);
return r;
}
static const struct file_operations fops_blob = {
.read = read_file_blob,
.write = write_file_blob,
.open = simple_open,
.llseek = default_llseek,
};
/**
* debugfs_create_blob - create a debugfs file that is used to read a binary blob
* debugfs_create_blob - create a debugfs file that is used to read and write
* a binary blob
* @name: a pointer to a string containing the name of the file to create.
* @mode: the read permission that the file should have (other permissions are
* masked out)
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this parameter is %NULL, then the
* file will be created in the root of the debugfs filesystem.
@ -1119,7 +1137,7 @@ static const struct file_operations fops_blob = {
*
* This function creates a file in debugfs with the given name that exports
* @blob->data as a binary blob. If the @mode variable is so set it can be
* read from. Writing is not supported.
* read from and written to.
*
* This function will return a pointer to a dentry if it succeeds. This
* pointer must be passed to the debugfs_remove() function when the file is
@ -1134,7 +1152,7 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
struct dentry *parent,
struct debugfs_blob_wrapper *blob)
{
return debugfs_create_file_unsafe(name, mode & 0444, parent, blob, &fops_blob);
return debugfs_create_file_unsafe(name, mode & 0644, parent, blob, &fops_blob);
}
EXPORT_SYMBOL_GPL(debugfs_create_blob);

View File

@ -75,6 +75,15 @@ static inline enum acpi_backlight_type acpi_video_get_backlight_type(void)
return __acpi_video_get_backlight_type(false, NULL);
}
/*
* This function MUST only be called by GPU drivers to check if the driver
* should register a backlight class device. This function not only checks
* if a GPU native backlight device should be registered it *also* tells
* the ACPI video-detect code that native GPU backlight control is available.
* Therefor calling this from any place other then the GPU driver is wrong!
* To check if GPU native backlight control is used in other places instead use:
* if (acpi_video_get_backlight_type() == acpi_backlight_native) { ... }
*/
static inline bool acpi_video_backlight_use_native(void)
{
return __acpi_video_get_backlight_type(true, NULL) == acpi_backlight_native;