summaryrefslogtreecommitdiff
path: root/src/acpi/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/acpi/acpi.c')
-rw-r--r--src/acpi/acpi.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c
index 64af505941..5c3fe13614 100644
--- a/src/acpi/acpi.c
+++ b/src/acpi/acpi.c
@@ -785,6 +785,152 @@ void acpi_create_hpet(acpi_hpet_t *hpet)
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
}
+/*
+ * This method adds the ACPI error injection capability. It fills the default information.
+ * HW dependent code (caller) can modify the defaults upon return. If no changes are necessary
+ * and the defaults are acceptable then caller can simply add the table (acpi_add_table).
+ * INPUTS:
+ * einj - ptr to the starting location of EINJ table
+ * actions - number of actions to trigger an error (HW dependent)
+ * addr - address of trigger action table. This should be ACPI reserved memory and it will be
+ * shared between OS and FW.
+ */
+void acpi_create_einj(acpi_einj_t *einj, uintptr_t addr, u8 actions)
+{
+ int i;
+ acpi_header_t *header = &(einj->header);
+ acpi_injection_header_t *inj_header = &(einj->inj_header);
+ acpi_einj_smi_t *einj_smi = (acpi_einj_smi_t *)addr;
+ acpi_einj_trigger_table_t *tat;
+ if (!header)
+ return;
+
+ printk(BIOS_DEBUG, "%s einj_smi = %p\n", __func__, einj_smi);
+ memset(einj_smi, 0, sizeof(acpi_einj_smi_t));
+ tat = (acpi_einj_trigger_table_t *)(einj_smi + sizeof(acpi_einj_smi_t));
+ tat->header_size = 16;
+ tat->revision = 0;
+ tat->table_size = sizeof(acpi_einj_trigger_table_t) +
+ sizeof(acpi_einj_action_table_t) * actions - 1;
+ tat->entry_count = actions;
+ printk(BIOS_DEBUG, "%s trigger_action_table = %p\n", __func__, tat);
+
+ for (i = 0; i < actions; i++) {
+ tat->trigger_action[i].action = TRIGGER_ERROR;
+ tat->trigger_action[i].instruction = NO_OP;
+ tat->trigger_action[i].flags = FLAG_IGNORE;
+ tat->trigger_action[i].reg.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ tat->trigger_action[i].reg.bit_width = 64;
+ tat->trigger_action[i].reg.bit_offset = 0;
+ tat->trigger_action[i].reg.access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
+ tat->trigger_action[i].reg.addr = 0;
+ tat->trigger_action[i].value = 0;
+ tat->trigger_action[i].mask = 0xFFFFFFFF;
+ }
+
+ acpi_einj_action_table_t default_actions[ACTION_COUNT] = {
+ [0] = {
+ .action = BEGIN_INJECT_OP,
+ .instruction = WRITE_REGISTER_VALUE,
+ .flags = FLAG_PRESERVE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_state),
+ .value = 0,
+ .mask = 0xFFFFFFFF
+ },
+ [1] = {
+ .action = GET_TRIGGER_ACTION_TABLE,
+ .instruction = READ_REGISTER,
+ .flags = FLAG_IGNORE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->trigger_action_table),
+ .value = 0,
+ .mask = 0xFFFFFFFFFFFFFFFF
+ },
+ [2] = {
+ .action = SET_ERROR_TYPE,
+ .instruction = WRITE_REGISTER,
+ .flags = FLAG_PRESERVE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->err_inject[0]),
+ .value = 0,
+ .mask = 0xFFFFFFFF
+ },
+ [3] = {
+ .action = GET_ERROR_TYPE,
+ .instruction = READ_REGISTER,
+ .flags = FLAG_IGNORE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->err_inj_cap),
+ .value = 0,
+ .mask = 0xFFFFFFFF
+ },
+ [4] = {
+ .action = END_INJECT_OP,
+ .instruction = WRITE_REGISTER_VALUE,
+ .flags = FLAG_PRESERVE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_state),
+ .value = 0,
+ .mask = 0xFFFFFFFF
+
+ },
+ [5] = {
+ .action = EXECUTE_INJECT_OP,
+ .instruction = WRITE_REGISTER_VALUE,
+ .flags = FLAG_PRESERVE,
+ .reg = EINJ_REG_IO(),
+ .value = 0x9a,
+ .mask = 0xFFFF,
+ },
+ [6] = {
+ .action = CHECK_BUSY_STATUS,
+ .instruction = READ_REGISTER_VALUE,
+ .flags = FLAG_IGNORE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_status),
+ .value = 1,
+ .mask = 1,
+ },
+ [7] = {
+ .action = GET_CMD_STATUS,
+ .instruction = READ_REGISTER,
+ .flags = FLAG_PRESERVE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->cmd_sts),
+ .value = 0,
+ .mask = 0x1fe,
+ },
+ [8] = {
+ .action = SET_ERROR_TYPE_WITH_ADDRESS,
+ .instruction = WRITE_REGISTER,
+ .flags = FLAG_PRESERVE,
+ .reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->setaddrtable),
+ .value = 1,
+ .mask = 0xffffffff
+ }
+ };
+
+ einj_smi->err_inj_cap = ACPI_EINJ_DEFAULT_CAP;
+ einj_smi->trigger_action_table = (u64) (uintptr_t)tat;
+
+ for (i = 0; i < ACTION_COUNT; i++)
+ printk(BIOS_DEBUG, "default_actions[%d].reg.addr is %llx\n", i,
+ default_actions[i].reg.addr);
+
+ memset((void *)einj, 0, sizeof(einj));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "EINJ", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->asl_compiler_revision = asl_revision;
+ header->length = sizeof(acpi_einj_t);
+ header->revision = 1;
+ inj_header->einj_header_size = sizeof(acpi_injection_header_t);
+ inj_header->entry_count = ACTION_COUNT;
+
+ printk(BIOS_DEBUG, "%s einj->action_table = %p\n",
+ __func__, einj->action_table);
+ memcpy((void *)einj->action_table, (void *)default_actions, sizeof(einj->action_table));
+ header->checksum = acpi_checksum((void *)einj, sizeof(einj));
+}
+
void acpi_create_vfct(const struct device *device,
acpi_vfct_t *vfct,
unsigned long (*acpi_fill_vfct)(const struct device *device,
@@ -1756,6 +1902,8 @@ int get_acpi_table_revision(enum acpi_tables table)
return 1;
case RSDP: /* ACPI 2.0 upto 6.3: 2 */
return 2;
+ case EINJ:
+ return 1;
case HEST:
return 1;
case NHLT: