linux/arch/x86/platform/intel-quark/imr_selftest.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * imr_selftest.c -- Intel Isolated Memory Region self-test driver
   4 *
   5 * Copyright(c) 2013 Intel Corporation.
   6 * Copyright(c) 2015 Bryan O'Donoghue <pure.logic@nexus-software.ie>
   7 *
   8 * IMR self test. The purpose of this module is to run a set of tests on the
   9 * IMR API to validate it's sanity. We check for overlapping, reserved
  10 * addresses and setup/teardown sanity.
  11 *
  12 */
  13
  14#include <asm-generic/sections.h>
  15#include <asm/cpu_device_id.h>
  16#include <asm/imr.h>
  17#include <asm/io.h>
  18
  19#include <linux/init.h>
  20#include <linux/mm.h>
  21#include <linux/types.h>
  22
  23#define SELFTEST KBUILD_MODNAME ": "
  24/**
  25 * imr_self_test_result - Print result string for self test.
  26 *
  27 * @res:        result code - true if test passed false otherwise.
  28 * @fmt:        format string.
  29 * ...          variadic argument list.
  30 */
  31static __printf(2, 3)
  32void __init imr_self_test_result(int res, const char *fmt, ...)
  33{
  34        va_list vlist;
  35
  36        /* Print pass/fail. */
  37        if (res)
  38                pr_info(SELFTEST "pass ");
  39        else
  40                pr_info(SELFTEST "fail ");
  41
  42        /* Print variable string. */
  43        va_start(vlist, fmt);
  44        vprintk(fmt, vlist);
  45        va_end(vlist);
  46
  47        /* Optional warning. */
  48        WARN(res == 0, "test failed");
  49}
  50#undef SELFTEST
  51
  52/**
  53 * imr_self_test
  54 *
  55 * Verify IMR self_test with some simple tests to verify overlap,
  56 * zero sized allocations and 1 KiB sized areas.
  57 *
  58 */
  59static void __init imr_self_test(void)
  60{
  61        phys_addr_t base  = virt_to_phys(&_text);
  62        size_t size = virt_to_phys(&__end_rodata) - base;
  63        const char *fmt_over = "overlapped IMR @ (0x%08lx - 0x%08lx)\n";
  64        int ret;
  65
  66        /* Test zero zero. */
  67        ret = imr_add_range(0, 0, 0, 0);
  68        imr_self_test_result(ret < 0, "zero sized IMR\n");
  69
  70        /* Test exact overlap. */
  71        ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
  72        imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
  73
  74        /* Test overlap with base inside of existing. */
  75        base += size - IMR_ALIGN;
  76        ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
  77        imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
  78
  79        /* Test overlap with end inside of existing. */
  80        base -= size + IMR_ALIGN * 2;
  81        ret = imr_add_range(base, size, IMR_CPU, IMR_CPU);
  82        imr_self_test_result(ret < 0, fmt_over, __va(base), __va(base + size));
  83
  84        /* Test that a 1 KiB IMR @ zero with read/write all will bomb out. */
  85        ret = imr_add_range(0, IMR_ALIGN, IMR_READ_ACCESS_ALL,
  86                            IMR_WRITE_ACCESS_ALL);
  87        imr_self_test_result(ret < 0, "1KiB IMR @ 0x00000000 - access-all\n");
  88
  89        /* Test that a 1 KiB IMR @ zero with CPU only will work. */
  90        ret = imr_add_range(0, IMR_ALIGN, IMR_CPU, IMR_CPU);
  91        imr_self_test_result(ret >= 0, "1KiB IMR @ 0x00000000 - cpu-access\n");
  92        if (ret >= 0) {
  93                ret = imr_remove_range(0, IMR_ALIGN);
  94                imr_self_test_result(ret == 0, "teardown - cpu-access\n");
  95        }
  96
  97        /* Test 2 KiB works. */
  98        size = IMR_ALIGN * 2;
  99        ret = imr_add_range(0, size, IMR_READ_ACCESS_ALL, IMR_WRITE_ACCESS_ALL);
 100        imr_self_test_result(ret >= 0, "2KiB IMR @ 0x00000000\n");
 101        if (ret >= 0) {
 102                ret = imr_remove_range(0, size);
 103                imr_self_test_result(ret == 0, "teardown 2KiB\n");
 104        }
 105}
 106
 107static const struct x86_cpu_id imr_ids[] __initconst = {
 108        X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
 109        {}
 110};
 111
 112/**
 113 * imr_self_test_init - entry point for IMR driver.
 114 *
 115 * return: -ENODEV for no IMR support 0 if good to go.
 116 */
 117static int __init imr_self_test_init(void)
 118{
 119        if (x86_match_cpu(imr_ids))
 120                imr_self_test();
 121        return 0;
 122}
 123
 124/**
 125 * imr_self_test_exit - exit point for IMR code.
 126 *
 127 * return:
 128 */
 129device_initcall(imr_self_test_init);
 130