diff options
author | Tomasz Nowicki <tomasz.nowicki@linaro.org> | 2013-09-19 17:51:59 +0200 |
---|---|---|
committer | Tomasz Nowicki <tomasz.nowicki@linaro.org> | 2013-09-23 11:42:54 +0200 |
commit | 5aebae7f179e41649b2b93996e882ace444a736f (patch) | |
tree | e53397cb3553ba73530f7817174077384b40b5d0 /tools/bfapei/bfapei.c | |
parent | 157bbfd13948abdd860d46a05ec13dc174a9d41f (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.c | 61 |
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)) |