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:
commit
22349e79b9
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue