Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 037d76f4 authored by Len Brown's avatar Len Brown
Browse files

Merge branch 'apei' into release

parents 5d1f8657 4134b8c8
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -714,7 +714,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
}
#endif

#ifdef CONFIG_HIBERNATION
#ifdef CONFIG_ACPI
/**
 * Mark ACPI NVS memory region, so that we can save/restore it during
 * hibernation and the subsequent resume.
@@ -727,7 +727,7 @@ static int __init e820_mark_nvs_memory(void)
		struct e820entry *ei = &e820.map[i];

		if (ei->type == E820_NVS)
			suspend_nvs_register(ei->addr, ei->size);
			acpi_nvs_register(ei->addr, ei->size);
	}

	return 0;
+2 −1
Original line number Diff line number Diff line
@@ -20,11 +20,12 @@ obj-y += acpi.o \
# All the builtin files are in the "acpi." module_param namespace.
acpi-y				+= osl.o utils.o reboot.o
acpi-y				+= atomicio.o
acpi-y				+= nvs.o

# sleep related files
acpi-y				+= wakeup.o
acpi-y				+= sleep.o
acpi-$(CONFIG_ACPI_SLEEP)	+= proc.o nvs.o
acpi-$(CONFIG_ACPI_SLEEP)	+= proc.o


#
+43 −5
Original line number Diff line number Diff line
@@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
	return 0;
}

int apei_resources_add(struct apei_resources *resources,
		       unsigned long start, unsigned long size,
		       bool iomem)
{
	if (iomem)
		return apei_res_add(&resources->iomem, start, size);
	else
		return apei_res_add(&resources->ioport, start, size);
}
EXPORT_SYMBOL_GPL(apei_resources_add);

/*
 * EINJ has two groups of GARs (EINJ table entry and trigger table
 * entry), so common resources are subtracted from the trigger table
@@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1,
}
EXPORT_SYMBOL_GPL(apei_resources_sub);

static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
{
	struct apei_resources *resources = data;
	return apei_res_add(&resources->iomem, start, size);
}

static int apei_get_nvs_resources(struct apei_resources *resources)
{
	return acpi_nvs_for_each_region(apei_get_nvs_callback, resources);
}

/*
 * IO memory/port rersource management mechanism is used to check
 * IO memory/port resource management mechanism is used to check
 * whether memory/port area used by GARs conflicts with normal memory
 * or IO memory/port of devices.
 */
@@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources,
{
	struct apei_res *res, *res_bak = NULL;
	struct resource *r;
	struct apei_resources nvs_resources;
	int rc;

	rc = apei_resources_sub(resources, &apei_resources_all);
	if (rc)
		return rc;

	/*
	 * Some firmware uses ACPI NVS region, that has been marked as
	 * busy, so exclude it from APEI resources to avoid false
	 * conflict.
	 */
	apei_resources_init(&nvs_resources);
	rc = apei_get_nvs_resources(&nvs_resources);
	if (rc)
		goto res_fini;
	rc = apei_resources_sub(resources, &nvs_resources);
	if (rc)
		goto res_fini;

	rc = -EINVAL;
	list_for_each_entry(res, &resources->iomem, list) {
		r = request_mem_region(res->start, res->end - res->start,
				       desc);
		if (!r) {
			pr_err(APEI_PFX
		"Can not request iomem region <%016llx-%016llx> for GARs.\n",
		"Can not request [mem %#010llx-%#010llx] for %s registers\n",
			       (unsigned long long)res->start,
			       (unsigned long long)res->end);
			       (unsigned long long)res->end - 1, desc);
			res_bak = res;
			goto err_unmap_iomem;
		}
@@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources,
		r = request_region(res->start, res->end - res->start, desc);
		if (!r) {
			pr_err(APEI_PFX
		"Can not request ioport region <%016llx-%016llx> for GARs.\n",
		"Can not request [io  %#06llx-%#06llx] for %s registers\n",
			       (unsigned long long)res->start,
			       (unsigned long long)res->end);
			       (unsigned long long)res->end - 1, desc);
			res_bak = res;
			goto err_unmap_ioport;
		}
@@ -500,6 +536,8 @@ err_unmap_iomem:
			break;
		release_mem_region(res->start, res->end - res->start);
	}
res_fini:
	apei_resources_fini(&nvs_resources);
	return rc;
}
EXPORT_SYMBOL_GPL(apei_resources_request);
+3 −0
Original line number Diff line number Diff line
@@ -95,6 +95,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
}

void apei_resources_fini(struct apei_resources *resources);
int apei_resources_add(struct apei_resources *resources,
		       unsigned long start, unsigned long size,
		       bool iomem);
int apei_resources_sub(struct apei_resources *resources1,
		       struct apei_resources *resources2);
int apei_resources_request(struct apei_resources *resources,
+56 −10
Original line number Diff line number Diff line
@@ -194,8 +194,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
	return 0;
}

static struct acpi_generic_address *einj_get_trigger_parameter_region(
	struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)
{
	int i;
	struct acpi_whea_header *entry;

	entry = (struct acpi_whea_header *)
		((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
	for (i = 0; i < trigger_tab->entry_count; i++) {
		if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&
		entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE &&
		entry->register_region.space_id ==
			ACPI_ADR_SPACE_SYSTEM_MEMORY &&
		(entry->register_region.address & param2) == (param1 & param2))
			return &entry->register_region;
		entry++;
	}

	return NULL;
}
/* Execute instructions in trigger error action table */
static int __einj_error_trigger(u64 trigger_paddr)
static int __einj_error_trigger(u64 trigger_paddr, u32 type,
				u64 param1, u64 param2)
{
	struct acpi_einj_trigger *trigger_tab = NULL;
	struct apei_exec_context trigger_ctx;
@@ -204,14 +225,16 @@ static int __einj_error_trigger(u64 trigger_paddr)
	struct resource *r;
	u32 table_size;
	int rc = -EIO;
	struct acpi_generic_address *trigger_param_region = NULL;

	r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
			       "APEI EINJ Trigger Table");
	if (!r) {
		pr_err(EINJ_PFX
	"Can not request iomem region <%016llx-%016llx> for Trigger table.\n",
	"Can not request [mem %#010llx-%#010llx] for Trigger table\n",
		       (unsigned long long)trigger_paddr,
		       (unsigned long long)trigger_paddr+sizeof(*trigger_tab));
		       (unsigned long long)trigger_paddr +
			    sizeof(*trigger_tab) - 1);
		goto out;
	}
	trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
@@ -232,9 +255,9 @@ static int __einj_error_trigger(u64 trigger_paddr)
			       "APEI EINJ Trigger Table");
	if (!r) {
		pr_err(EINJ_PFX
"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n",
"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
		       (unsigned long long)trigger_paddr + sizeof(*trigger_tab),
		       (unsigned long long)trigger_paddr + table_size);
		       (unsigned long long)trigger_paddr + table_size - 1);
		goto out_rel_header;
	}
	iounmap(trigger_tab);
@@ -255,6 +278,30 @@ static int __einj_error_trigger(u64 trigger_paddr)
	rc = apei_resources_sub(&trigger_resources, &einj_resources);
	if (rc)
		goto out_fini;
	/*
	 * Some firmware will access target address specified in
	 * param1 to trigger the error when injecting memory error.
	 * This will cause resource conflict with regular memory.  So
	 * remove it from trigger table resources.
	 */
	if (param_extension && (type & 0x0038) && param2) {
		struct apei_resources addr_resources;
		apei_resources_init(&addr_resources);
		trigger_param_region = einj_get_trigger_parameter_region(
			trigger_tab, param1, param2);
		if (trigger_param_region) {
			rc = apei_resources_add(&addr_resources,
				trigger_param_region->address,
				trigger_param_region->bit_width/8, true);
			if (rc)
				goto out_fini;
			rc = apei_resources_sub(&trigger_resources,
					&addr_resources);
		}
		apei_resources_fini(&addr_resources);
		if (rc)
			goto out_fini;
	}
	rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
	if (rc)
		goto out_fini;
@@ -324,7 +371,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
	if (rc)
		return rc;
	trigger_paddr = apei_exec_ctx_get_output(&ctx);
	rc = __einj_error_trigger(trigger_paddr);
	rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
	if (rc)
		return rc;
	rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
@@ -465,10 +512,9 @@ static int __init einj_init(void)

	status = acpi_get_table(ACPI_SIG_EINJ, 0,
				(struct acpi_table_header **)&einj_tab);
	if (status == AE_NOT_FOUND) {
		pr_info(EINJ_PFX "Table is not found!\n");
	if (status == AE_NOT_FOUND)
		return -ENODEV;
	} else if (ACPI_FAILURE(status)) {
	else if (ACPI_FAILURE(status)) {
		const char *msg = acpi_format_exception(status);
		pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
		return -EINVAL;
Loading