Skip to content

Commit

Permalink
Merge branches 'acpi-sysfs', 'acpi-apei' and 'acpi-blacklist'
Browse files Browse the repository at this point in the history
* acpi-sysfs:
  ACPI / sysfs: Extend ACPI sysfs to provide access to boot error region

* acpi-apei:
  ACPI / APEI: Suppress message if HEST not present
  ACPI, APEI, EINJ: Subtract any matching Register Region from Trigger resources
  ACPI: APEI: fix the wrong iteration of generic error status block
  ACPI: APEI: Enable APEI multiple GHES source to share a single external IRQ

* acpi-blacklist:
  intel_pstate: convert to use acpi_match_platform_list()
  ACPI / blacklist: add acpi_match_platform_list()
  • Loading branch information
Rafael J. Wysocki committed Sep 3, 2017
4 parents 940c8df + 7dae632 + e931d0d + 5e93232 commit 298bd7f
Show file tree
Hide file tree
Showing 12 changed files with 203 additions and 133 deletions.
5 changes: 0 additions & 5 deletions drivers/acpi/apei/apei-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,6 @@ int apei_exec_collect_resources(struct apei_exec_context *ctx,
struct dentry;
struct dentry *apei_get_debugfs_dir(void);

#define apei_estatus_for_each_section(estatus, section) \
for (section = (struct acpi_hest_generic_data *)(estatus + 1); \
(void *)section - (void *)estatus < estatus->data_length; \
section = (void *)(section+1) + section->error_data_length)

static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus)
{
if (estatus->raw_data_length)
Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/apei/einj.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
((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->instruction <= ACPI_EINJ_WRITE_REGISTER_VALUE &&
entry->register_region.space_id ==
ACPI_ADR_SPACE_SYSTEM_MEMORY &&
(entry->register_region.address & param2) == (param1 & param2))
Expand Down
10 changes: 8 additions & 2 deletions drivers/acpi/apei/ghes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,8 @@ static int ghes_probe(struct platform_device *ghes_dev)
generic->header.source_id);
goto err_edac_unreg;
}
rc = request_irq(ghes->irq, ghes_irq_func, 0, "GHES IRQ", ghes);
rc = request_irq(ghes->irq, ghes_irq_func, IRQF_SHARED,
"GHES IRQ", ghes);
if (rc) {
pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
generic->header.source_id);
Expand Down Expand Up @@ -1265,9 +1266,14 @@ static int __init ghes_init(void)
if (acpi_disabled)
return -ENODEV;

if (hest_disable) {
switch (hest_disable) {
case HEST_NOT_FOUND:
return -ENODEV;
case HEST_DISABLED:
pr_info(GHES_PFX "HEST is not enabled!\n");
return -EINVAL;
default:
break;
}

if (ghes_disable) {
Expand Down
13 changes: 7 additions & 6 deletions drivers/acpi/apei/hest.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

#define HEST_PFX "HEST: "

bool hest_disable;
int hest_disable;
EXPORT_SYMBOL_GPL(hest_disable);

/* HEST table parsing */
Expand Down Expand Up @@ -213,7 +213,7 @@ static int __init hest_ghes_dev_register(unsigned int ghes_count)

static int __init setup_hest_disable(char *str)
{
hest_disable = 1;
hest_disable = HEST_DISABLED;
return 0;
}

Expand All @@ -232,9 +232,10 @@ void __init acpi_hest_init(void)

status = acpi_get_table(ACPI_SIG_HEST, 0,
(struct acpi_table_header **)&hest_tab);
if (status == AE_NOT_FOUND)
goto err;
else if (ACPI_FAILURE(status)) {
if (status == AE_NOT_FOUND) {
hest_disable = HEST_NOT_FOUND;
return;
} else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status);
pr_err(HEST_PFX "Failed to get table, %s\n", msg);
rc = -EINVAL;
Expand All @@ -257,5 +258,5 @@ void __init acpi_hest_init(void)
pr_info(HEST_PFX "Table parsing has been initialized.\n");
return;
err:
hest_disable = 1;
hest_disable = HEST_DISABLED;
}
83 changes: 14 additions & 69 deletions drivers/acpi/blacklist.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,13 @@

#include "internal.h"

enum acpi_blacklist_predicates {
all_versions,
less_than_or_equal,
equal,
greater_than_or_equal,
};

struct acpi_blacklist_item {
char oem_id[7];
char oem_table_id[9];
u32 oem_revision;
char *table;
enum acpi_blacklist_predicates oem_revision_predicate;
char *reason;
u32 is_critical_error;
};

static struct dmi_system_id acpi_rev_dmi_table[] __initdata;

/*
* POLICY: If *anything* doesn't work, put it on the blacklist.
* If they are critical errors, mark it critical, and abort driver load.
*/
static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
static struct acpi_platform_list acpi_blacklist[] __initdata = {
/* Compaq Presario 1700 */
{"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
"Multiple problems", 1},
Expand All @@ -67,65 +50,27 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
{"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1},

{""}
{ }
};

int __init acpi_blacklisted(void)
{
int i = 0;
int i;
int blacklisted = 0;
struct acpi_table_header table_header;

while (acpi_blacklist[i].oem_id[0] != '\0') {
if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
i++;
continue;
}

if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
i++;
continue;
}

if (strncmp
(acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
8)) {
i++;
continue;
}

if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
|| (acpi_blacklist[i].oem_revision_predicate ==
less_than_or_equal
&& table_header.oem_revision <=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate ==
greater_than_or_equal
&& table_header.oem_revision >=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate == equal
&& table_header.oem_revision ==
acpi_blacklist[i].oem_revision)) {

printk(KERN_ERR PREFIX
"Vendor \"%6.6s\" System \"%8.8s\" "
"Revision 0x%x has a known ACPI BIOS problem.\n",
acpi_blacklist[i].oem_id,
acpi_blacklist[i].oem_table_id,
acpi_blacklist[i].oem_revision);
i = acpi_match_platform_list(acpi_blacklist);
if (i >= 0) {
pr_err(PREFIX "Vendor \"%6.6s\" System \"%8.8s\" Revision 0x%x has a known ACPI BIOS problem.\n",
acpi_blacklist[i].oem_id,
acpi_blacklist[i].oem_table_id,
acpi_blacklist[i].oem_revision);

printk(KERN_ERR PREFIX
"Reason: %s. This is a %s error\n",
acpi_blacklist[i].reason,
(acpi_blacklist[i].
is_critical_error ? "non-recoverable" :
"recoverable"));
pr_err(PREFIX "Reason: %s. This is a %s error\n",
acpi_blacklist[i].reason,
(acpi_blacklist[i].data ?
"non-recoverable" : "recoverable"));

blacklisted = acpi_blacklist[i].is_critical_error;
break;
} else {
i++;
}
blacklisted = acpi_blacklist[i].data;
}

(void)early_acpi_osi_init();
Expand Down
79 changes: 79 additions & 0 deletions drivers/acpi/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,13 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
/*
* ACPI table sysfs I/F:
* /sys/firmware/acpi/tables/
* /sys/firmware/acpi/tables/data/
* /sys/firmware/acpi/tables/dynamic/
*/

static LIST_HEAD(acpi_table_attr_list);
static struct kobject *tables_kobj;
static struct kobject *tables_data_kobj;
static struct kobject *dynamic_tables_kobj;
static struct kobject *hotplug_kobj;

Expand All @@ -327,6 +329,11 @@ struct acpi_table_attr {
struct list_head node;
};

struct acpi_data_attr {
struct bin_attribute attr;
u64 addr;
};

static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t offset, size_t count)
Expand Down Expand Up @@ -422,6 +429,70 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
return AE_OK;
}

static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t offset, size_t count)
{
struct acpi_data_attr *data_attr;
void __iomem *base;
ssize_t rc;

data_attr = container_of(bin_attr, struct acpi_data_attr, attr);

base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size);
if (!base)
return -ENOMEM;
rc = memory_read_from_buffer(buf, count, &offset, base,
data_attr->attr.size);
acpi_os_unmap_memory(base, data_attr->attr.size);

return rc;
}

static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
{
struct acpi_table_bert *bert = th;

if (bert->header.length < sizeof(struct acpi_table_bert) ||
bert->region_length < sizeof(struct acpi_hest_generic_status)) {
kfree(data_attr);
return -EINVAL;
}
data_attr->addr = bert->address;
data_attr->attr.size = bert->region_length;
data_attr->attr.attr.name = "BERT";

return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
}

static struct acpi_data_obj {
char *name;
int (*fn)(void *, struct acpi_data_attr *);
} acpi_data_objs[] = {
{ ACPI_SIG_BERT, acpi_bert_data_init },
};

#define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)

static int acpi_table_data_init(struct acpi_table_header *th)
{
struct acpi_data_attr *data_attr;
int i;

for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) {
if (ACPI_COMPARE_NAME(th->signature, acpi_data_objs[i].name)) {
data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL);
if (!data_attr)
return -ENOMEM;
sysfs_attr_init(&data_attr->attr.attr);
data_attr->attr.read = acpi_data_show;
data_attr->attr.attr.mode = 0400;
return acpi_data_objs[i].fn(th, data_attr);
}
}
return 0;
}

static int acpi_tables_sysfs_init(void)
{
struct acpi_table_attr *table_attr;
Expand All @@ -434,6 +505,10 @@ static int acpi_tables_sysfs_init(void)
if (!tables_kobj)
goto err;

tables_data_kobj = kobject_create_and_add("data", tables_kobj);
if (!tables_data_kobj)
goto err_tables_data;

dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);
if (!dynamic_tables_kobj)
goto err_dynamic_tables;
Expand All @@ -458,13 +533,17 @@ static int acpi_tables_sysfs_init(void)
return ret;
}
list_add_tail(&table_attr->node, &acpi_table_attr_list);
acpi_table_data_init(table_header);
}

kobject_uevent(tables_kobj, KOBJ_ADD);
kobject_uevent(tables_data_kobj, KOBJ_ADD);
kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);

return 0;
err_dynamic_tables:
kobject_put(tables_data_kobj);
err_tables_data:
kobject_put(tables_kobj);
err:
return -ENOMEM;
Expand Down
36 changes: 36 additions & 0 deletions drivers/acpi/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -816,3 +816,39 @@ static int __init acpi_backlight(char *str)
return 1;
}
__setup("acpi_backlight=", acpi_backlight);

/**
* acpi_match_platform_list - Check if the system matches with a given list
* @plat: pointer to acpi_platform_list table terminated by a NULL entry
*
* Return the matched index if the system is found in the platform list.
* Otherwise, return a negative error code.
*/
int acpi_match_platform_list(const struct acpi_platform_list *plat)
{
struct acpi_table_header hdr;
int idx = 0;

if (acpi_disabled)
return -ENODEV;

for (; plat->oem_id[0]; plat++, idx++) {
if (ACPI_FAILURE(acpi_get_table_header(plat->table, 0, &hdr)))
continue;

if (strncmp(plat->oem_id, hdr.oem_id, ACPI_OEM_ID_SIZE))
continue;

if (strncmp(plat->oem_table_id, hdr.oem_table_id, ACPI_OEM_TABLE_ID_SIZE))
continue;

if ((plat->pred == all_versions) ||
(plat->pred == less_than_or_equal && hdr.oem_revision <= plat->oem_revision) ||
(plat->pred == greater_than_or_equal && hdr.oem_revision >= plat->oem_revision) ||
(plat->pred == equal && hdr.oem_revision == plat->oem_revision))
return idx;
}

return -ENODEV;
}
EXPORT_SYMBOL(acpi_match_platform_list);
Loading

0 comments on commit 298bd7f

Please sign in to comment.