Commit 22349e79 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -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 @@ static int __init extlog_init(void)
static void __exit extlog_exit(void)
{
	mce_unregister_decode_chain(&extlog_mce_dec);
	if (extlog_l1_addr) {
		((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
	if (extlog_l1_addr)
		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);
+1 −1
Original line number Diff line number Diff line
@@ -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;

+16 −61
Original line number Diff line number Diff line
@@ -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,13 +1722,13 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
		return;
	count++;

	acpi_get_parent(device->dev->handle, &acpi_parent);

	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));
	props.type = BACKLIGHT_FIRMWARE;
@@ -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);
+48 −23
Original line number Diff line number Diff line
@@ -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);
+23 −6
Original line number Diff line number Diff line
@@ -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);

Loading