summaryrefslogtreecommitdiff
path: root/tools/bfapei/bfapei.c
diff options
context:
space:
mode:
authorTomasz Nowicki <tomasz.nowicki@linaro.org>2013-09-19 17:51:59 +0200
committerTomasz Nowicki <tomasz.nowicki@linaro.org>2013-09-23 11:42:54 +0200
commit5aebae7f179e41649b2b93996e882ace444a736f (patch)
treee53397cb3553ba73530f7817174077384b40b5d0 /tools/bfapei/bfapei.c
parent157bbfd13948abdd860d46a05ec13dc174a9d41f (diff)
bfapei: Expand bfapei tool to EINJ table testing.
bfapei now can create blob for EINJ driver as well. Blob for EINJ driver need to be combined with blob for HEST driver since EINJ is designed to set status flag for Error Status Block pointed from HEST table. This way EINJ driver can be tested in easy way. Note that SCI must be triggered in the next step so GHES driver start to parse error. This could be done using SCI emulate mechanism. Logic path: 1. Create Error Status Block (ESB information related to given error, pointed by HEST) 2. Create pretended registers (blob for EINJ) that instruct kernel to set status flag in ESB. 3. Trigger error using debugfs 4. Emulate SCI HOWTO: Enter to acpi tool repository: # make PADDR=0x<physical address> APEI=einj <platform>.acpi Boot target: Print available error list: # cat /sys/kernel/debug/apei/einj/available_error_type 0x00000008 Memory Correctable Set given error type: # echo 0x00000008 > /sys/kernel/debug/apei/einj/error_type Confirm error was really set: # cat /sys/kernel/debug/apei/einj/error_type 0x8 Inject error (here status flag for ESB is set) # echo 0x00000008 > /sys/kernel/debug/apei/einj/error_inject Emulate SCI (notification of HED device with 0x80 value) # echo "HED 128" > /sys/kernel/debug/acpi/sci_notify ACPI: ACPI device name is <HED>, event code is <128> ACPI: Notify event is queued {1}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 2 {1}[Hardware Error]: APEI generic hardware error status {1}[Hardware Error]: severity: 1, fatal {1}[Hardware Error]: section: 0, severity: 0, recoverable {1}[Hardware Error]: flags: 0x00 {1}[Hardware Error]: section_type: memory error Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
Diffstat (limited to 'tools/bfapei/bfapei.c')
-rw-r--r--tools/bfapei/bfapei.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/tools/bfapei/bfapei.c b/tools/bfapei/bfapei.c
index 73a421c..ff99953 100644
--- a/tools/bfapei/bfapei.c
+++ b/tools/bfapei/bfapei.c
@@ -45,6 +45,10 @@
* | |
* +--------------------+ +0x200
* | |
+ * | place for EINJ | EINJ driver reference to this region during
+ * | registers | error injection.
+ * | |
+ * +--------------------+ +0x300
*
* ~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -182,6 +186,55 @@ static int bfapei_hest(char **buf, int *size, uint64_t paddr, int status)
return BFAPEI_OK;
}
+static int bfapei_einj(char **buf, int *size, uint64_t paddr)
+{
+ struct acpi_hest_generic_status *block_ptr;
+ struct acpi_einj_trigger *trigger_tab;
+ struct acpi_whea_header *trigger_entry;
+ int reqr_size = 0x300;
+ uint64_t *add_ptr;
+
+ if (bfapei_expand_buf(buf, size, reqr_size))
+ return BFAPEI_FAIL;
+
+ /* Available error type: Memory Correctable */
+ WRITE_EINJ_REG(*buf, ACPI_EINJ_GET_ERROR_TYPE, 0x00000008);
+
+ WRITE_EINJ_REG(*buf, ACPI_EINJ_GET_COMMAND_STATUS, ACPI_EINJ_SUCCESS);
+ WRITE_EINJ_REG(*buf, ACPI_EINJ_CHECK_BUSY_STATUS, 1);
+
+ /*
+ * Nothing to do more than just set status flag for previous prepared
+ * ESB (error status block)
+ */
+ WRITE_EINJ_REG(*buf, ACPI_EINJ_GET_TRIGGER_TABLE, paddr + 0x280);
+ trigger_tab = (struct acpi_einj_trigger *) (*buf + 0x280);
+ trigger_tab->header_size = sizeof(struct acpi_einj_trigger);
+ trigger_tab->table_size = sizeof(struct acpi_einj_trigger) +
+ sizeof(struct acpi_whea_header);
+ trigger_tab->entry_count = 1;
+
+ trigger_entry = (struct acpi_whea_header *) ++trigger_tab;
+ trigger_entry->action = ACPI_EINJ_TRIGGER_ERROR;
+ trigger_entry->instruction = ACPI_EINJ_WRITE_REGISTER_VALUE;
+
+ trigger_entry->register_region.space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
+ trigger_entry->register_region.bit_width = 40;
+ trigger_entry->register_region.bit_offset = 0;
+ trigger_entry->register_region.access_width = 4;
+
+ /* Obtain address of status block field */
+ add_ptr = (uint64_t *) *buf;
+ block_ptr = (struct acpi_hest_generic_status *) (++add_ptr);
+ trigger_entry->register_region.address =
+ paddr + ((char *)&(block_ptr->block_status) - *buf);
+
+ trigger_entry->value = 1;
+ trigger_entry->mask = 0xFFFFFFFFFFFFFFFFUL;
+
+ return BFAPEI_OK;
+}
+
static int bfapei_erst(char **buf, int *size, uint64_t paddr)
{
int reqr_size = 0x200;
@@ -250,6 +303,14 @@ int main(int argc, char *argv[]) {
return BFAPEI_FAIL;
}
+ if (strncmp(blob_type, "einj", 4) == 0) {
+ if (bfapei_hest(&buf, &size, paddr, 0))
+ return BFAPEI_FAIL;
+
+ if (bfapei_einj(&buf, &size, paddr))
+ return BFAPEI_FAIL;
+ }
+
/* Set status flag so error will be visible for BERT driver */
if (strncmp(blob_type, "bert", 4) == 0) {
if (bfapei_hest(&buf, &size, paddr, 1))