blob: 07b0daaab0d93e1b392d1514210abc9b335a5631 [file] [log] [blame]
Simon Glassf50cc952020-04-08 16:57:34 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Tests for ACPI table generation
4 *
5 * Copyright 2019 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#include <common.h>
Simon Glass0b885bc2020-04-26 09:19:53 -060010#include <console.h>
Simon Glassf50cc952020-04-08 16:57:34 -060011#include <dm.h>
Simon Glass7e586f62020-04-26 09:19:51 -060012#include <malloc.h>
Simon Glass29b35112020-04-26 09:19:50 -060013#include <mapmem.h>
Simon Glass0b885bc2020-04-26 09:19:53 -060014#include <version.h>
Simon Glass7e586f62020-04-26 09:19:51 -060015#include <tables_csum.h>
Simon Glass93f7f822020-04-26 09:19:46 -060016#include <version.h>
Simon Glass1361a532020-07-07 13:11:39 -060017#include <acpi/acpi_device.h>
Simon Glass91fe8b72020-04-08 16:57:38 -060018#include <acpi/acpi_table.h>
Simon Glassf50cc952020-04-08 16:57:34 -060019#include <dm/acpi.h>
20#include <dm/test.h>
21#include <test/ut.h>
22
23#define ACPI_TEST_DEV_NAME "ABCD"
Simon Glass1361a532020-07-07 13:11:39 -060024#define ACPI_TEST_CHILD_NAME "EFGH"
Simon Glass93f7f822020-04-26 09:19:46 -060025#define BUF_SIZE 4096
26
Simon Glass1361a532020-07-07 13:11:39 -060027/**
28 * struct testacpi_platdata - Platform data for the test ACPI device
29 *
30 * @no_name: true to emit an empty ACPI name from testacpi_get_name()
31 * @return_error: true to return an error instead of a name
32 */
33struct testacpi_platdata {
34 bool return_error;
35 bool no_name;
36};
37
Simon Glass93f7f822020-04-26 09:19:46 -060038static int testacpi_write_tables(const struct udevice *dev,
39 struct acpi_ctx *ctx)
40{
41 struct acpi_dmar *dmar;
Simon Glass29b35112020-04-26 09:19:50 -060042 int ret;
Simon Glass93f7f822020-04-26 09:19:46 -060043
44 dmar = (struct acpi_dmar *)ctx->current;
45 acpi_create_dmar(dmar, DMAR_INTR_REMAP);
46 ctx->current += sizeof(struct acpi_dmar);
Simon Glass29b35112020-04-26 09:19:50 -060047 ret = acpi_add_table(ctx, dmar);
48 if (ret)
49 return log_msg_ret("add", ret);
Simon Glass93f7f822020-04-26 09:19:46 -060050
51 return 0;
52}
Simon Glassf50cc952020-04-08 16:57:34 -060053
54static int testacpi_get_name(const struct udevice *dev, char *out_name)
55{
Simon Glass1361a532020-07-07 13:11:39 -060056 struct testacpi_platdata *plat = dev_get_platdata(dev);
57
58 if (plat->return_error)
59 return -EINVAL;
60 if (plat->no_name) {
61 *out_name = '\0';
62 return 0;
63 }
64 if (device_get_uclass_id(dev->parent) == UCLASS_TEST_ACPI)
65 return acpi_copy_name(out_name, ACPI_TEST_CHILD_NAME);
66 else
67 return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME);
Simon Glassf50cc952020-04-08 16:57:34 -060068}
69
70struct acpi_ops testacpi_ops = {
71 .get_name = testacpi_get_name,
Simon Glass93f7f822020-04-26 09:19:46 -060072 .write_tables = testacpi_write_tables,
Simon Glassf50cc952020-04-08 16:57:34 -060073};
74
75static const struct udevice_id testacpi_ids[] = {
76 { .compatible = "denx,u-boot-acpi-test" },
77 { }
78};
79
80U_BOOT_DRIVER(testacpi_drv) = {
81 .name = "testacpi_drv",
82 .of_match = testacpi_ids,
83 .id = UCLASS_TEST_ACPI,
Simon Glass1361a532020-07-07 13:11:39 -060084 .bind = dm_scan_fdt_dev,
85 .platdata_auto_alloc_size = sizeof(struct testacpi_platdata),
Simon Glassf50cc952020-04-08 16:57:34 -060086 ACPI_OPS_PTR(&testacpi_ops)
87};
88
89UCLASS_DRIVER(testacpi) = {
90 .name = "testacpi",
91 .id = UCLASS_TEST_ACPI,
92};
93
94/* Test ACPI get_name() */
95static int dm_test_acpi_get_name(struct unit_test_state *uts)
96{
97 char name[ACPI_NAME_MAX];
98 struct udevice *dev;
99
100 ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
101 ut_assertok(acpi_get_name(dev, name));
102 ut_asserteq_str(ACPI_TEST_DEV_NAME, name);
103
104 return 0;
105}
106DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass91fe8b72020-04-08 16:57:38 -0600107
108/* Test acpi_get_table_revision() */
109static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
110{
111 ut_asserteq(1, acpi_get_table_revision(ACPITAB_MCFG));
112 ut_asserteq(2, acpi_get_table_revision(ACPITAB_RSDP));
113 ut_asserteq(4, acpi_get_table_revision(ACPITAB_TPM2));
114 ut_asserteq(-EINVAL, acpi_get_table_revision(ACPITAB_COUNT));
115
116 return 0;
117}
118DM_TEST(dm_test_acpi_get_table_revision,
119 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassbfeb5d42020-04-08 16:57:39 -0600120
Simon Glassbfeb5d42020-04-08 16:57:39 -0600121/* Test acpi_create_dmar() */
122static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
123{
124 struct acpi_dmar dmar;
125
126 ut_assertok(acpi_create_dmar(&dmar, DMAR_INTR_REMAP));
127 ut_asserteq(DMAR_INTR_REMAP, dmar.flags);
128 ut_asserteq(32 - 1, dmar.host_address_width);
129
130 return 0;
131}
132DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass93f7f822020-04-26 09:19:46 -0600133
134/* Test acpi_fill_header() */
135static int dm_test_acpi_fill_header(struct unit_test_state *uts)
136{
137 struct acpi_table_header hdr;
138
139 /* Make sure these 5 fields are not changed */
140 hdr.length = 0x11;
141 hdr.revision = 0x22;
142 hdr.checksum = 0x33;
143 hdr.aslc_revision = 0x44;
144 acpi_fill_header(&hdr, "ABCD");
145
146 ut_asserteq_mem("ABCD", hdr.signature, sizeof(hdr.signature));
147 ut_asserteq(0x11, hdr.length);
148 ut_asserteq(0x22, hdr.revision);
149 ut_asserteq(0x33, hdr.checksum);
150 ut_asserteq_mem(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id));
151 ut_asserteq_mem(OEM_TABLE_ID, hdr.oem_table_id,
152 sizeof(hdr.oem_table_id));
153 ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision);
154 ut_asserteq_mem(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id));
155 ut_asserteq(0x44, hdr.aslc_revision);
156
157 return 0;
158}
159DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
160
161/* Test ACPI write_tables() */
162static int dm_test_acpi_write_tables(struct unit_test_state *uts)
163{
164 struct acpi_dmar *dmar;
165 struct acpi_ctx ctx;
166 void *buf;
Simon Glass1361a532020-07-07 13:11:39 -0600167 int i;
Simon Glass93f7f822020-04-26 09:19:46 -0600168
169 buf = malloc(BUF_SIZE);
170 ut_assertnonnull(buf);
171
Simon Glass7e586f62020-04-26 09:19:51 -0600172 acpi_setup_base_tables(&ctx, buf);
Simon Glass29b35112020-04-26 09:19:50 -0600173 dmar = ctx.current;
Simon Glass93f7f822020-04-26 09:19:46 -0600174 ut_assertok(acpi_write_dev_tables(&ctx));
Simon Glass93f7f822020-04-26 09:19:46 -0600175
176 /*
Simon Glass1361a532020-07-07 13:11:39 -0600177 * We should have three dmar tables, one for each
178 * "denx,u-boot-acpi-test" device
Simon Glass93f7f822020-04-26 09:19:46 -0600179 */
Simon Glass1361a532020-07-07 13:11:39 -0600180 ut_asserteq_ptr(dmar + 3, ctx.current);
Simon Glass93f7f822020-04-26 09:19:46 -0600181 ut_asserteq(DMAR_INTR_REMAP, dmar->flags);
182 ut_asserteq(32 - 1, dmar->host_address_width);
183
184 ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
185 ut_asserteq(32 - 1, dmar[1].host_address_width);
186
Simon Glass1361a532020-07-07 13:11:39 -0600187 ut_asserteq(DMAR_INTR_REMAP, dmar[2].flags);
188 ut_asserteq(32 - 1, dmar[2].host_address_width);
Simon Glass7e586f62020-04-26 09:19:51 -0600189
Simon Glass1361a532020-07-07 13:11:39 -0600190 /* Check that the pointers were added correctly */
191 for (i = 0; i < 3; i++) {
192 ut_asserteq(map_to_sysmem(dmar + i), ctx.rsdt->entry[i]);
193 ut_asserteq(map_to_sysmem(dmar + i), ctx.xsdt->entry[i]);
194 }
195 ut_asserteq(0, ctx.rsdt->entry[3]);
196 ut_asserteq(0, ctx.xsdt->entry[3]);
Simon Glassb38309b2020-04-26 09:19:52 -0600197
Simon Glass93f7f822020-04-26 09:19:46 -0600198 return 0;
199}
200DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass86e17782020-04-26 09:19:47 -0600201
202/* Test basic ACPI functions */
203static int dm_test_acpi_basic(struct unit_test_state *uts)
204{
205 struct acpi_ctx ctx;
206
207 /* Check align works */
208 ctx.current = (void *)5;
209 acpi_align(&ctx);
210 ut_asserteq_ptr((void *)16, ctx.current);
211
212 /* Check that align does nothing if already aligned */
213 acpi_align(&ctx);
214 ut_asserteq_ptr((void *)16, ctx.current);
215 acpi_align64(&ctx);
216 ut_asserteq_ptr((void *)64, ctx.current);
217 acpi_align64(&ctx);
218 ut_asserteq_ptr((void *)64, ctx.current);
219
220 /* Check incrementing */
221 acpi_inc(&ctx, 3);
222 ut_asserteq_ptr((void *)67, ctx.current);
223 acpi_inc_align(&ctx, 3);
224 ut_asserteq_ptr((void *)80, ctx.current);
225
226 return 0;
227}
228DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7e586f62020-04-26 09:19:51 -0600229
230/* Test acpi_setup_base_tables */
231static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
232{
233 struct acpi_rsdp *rsdp;
234 struct acpi_rsdt *rsdt;
235 struct acpi_xsdt *xsdt;
236 struct acpi_ctx ctx;
237 void *buf, *end;
238
239 /*
240 * Use an unaligned address deliberately, by allocating an aligned
241 * address and then adding 4 to it
242 */
243 buf = memalign(64, BUF_SIZE);
244 ut_assertnonnull(buf);
245 acpi_setup_base_tables(&ctx, buf + 4);
Simon Glass0b885bc2020-04-26 09:19:53 -0600246 ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd->arch.acpi_start);
Simon Glass7e586f62020-04-26 09:19:51 -0600247
248 rsdp = buf + 16;
249 ut_asserteq_ptr(rsdp, ctx.rsdp);
Simon Glassf91f3662020-05-10 12:52:45 -0600250 ut_asserteq_mem(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature));
Simon Glass7e586f62020-04-26 09:19:51 -0600251 ut_asserteq(sizeof(*rsdp), rsdp->length);
252 ut_assertok(table_compute_checksum(rsdp, 20));
253 ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp)));
254
255 rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
256 ut_asserteq_ptr(rsdt, ctx.rsdt);
Simon Glassf91f3662020-05-10 12:52:45 -0600257 ut_asserteq_mem("RSDT", rsdt->header.signature, ACPI_NAME_LEN);
Simon Glass7e586f62020-04-26 09:19:51 -0600258 ut_asserteq(sizeof(*rsdt), rsdt->header.length);
259 ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
260
261 xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
Simon Glassb38309b2020-04-26 09:19:52 -0600262 ut_asserteq_ptr(xsdt, ctx.xsdt);
Simon Glassf91f3662020-05-10 12:52:45 -0600263 ut_asserteq_mem("XSDT", xsdt->header.signature, ACPI_NAME_LEN);
Simon Glass7e586f62020-04-26 09:19:51 -0600264 ut_asserteq(sizeof(*xsdt), xsdt->header.length);
265 ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
266
267 end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
268 ut_asserteq_ptr(end, ctx.current);
269
270 ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address);
271 ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address);
272
273 return 0;
274}
275DM_TEST(dm_test_acpi_setup_base_tables,
276 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass0b885bc2020-04-26 09:19:53 -0600277
278/* Test 'acpi list' command */
279static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
280{
281 struct acpi_ctx ctx;
282 ulong addr;
283 void *buf;
284
285 buf = memalign(16, BUF_SIZE);
286 ut_assertnonnull(buf);
287 acpi_setup_base_tables(&ctx, buf);
288
289 ut_assertok(acpi_write_dev_tables(&ctx));
290
291 console_record_reset();
292 run_command("acpi list", 0);
293 addr = (ulong)map_to_sysmem(buf);
294 ut_assert_nextline("ACPI tables start at %lx", addr);
295 ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
296 sizeof(struct acpi_rsdp));
297 addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
298 ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
299 addr, sizeof(struct acpi_table_header) +
Simon Glass1361a532020-07-07 13:11:39 -0600300 3 * sizeof(u32), U_BOOT_BUILD_DATE);
Simon Glass0b885bc2020-04-26 09:19:53 -0600301 addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
302 ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
303 addr, sizeof(struct acpi_table_header) +
Simon Glass1361a532020-07-07 13:11:39 -0600304 3 * sizeof(u64), U_BOOT_BUILD_DATE);
Simon Glass0b885bc2020-04-26 09:19:53 -0600305 addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
306 ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
307 addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
308 addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
309 ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
310 addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
Simon Glass1361a532020-07-07 13:11:39 -0600311 addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
312 ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
313 addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
Simon Glass0b885bc2020-04-26 09:19:53 -0600314 ut_assert_console_end();
315
316 return 0;
317}
318DM_TEST(dm_test_acpi_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
319
320/* Test 'acpi dump' command */
321static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
322{
323 struct acpi_ctx ctx;
324 ulong addr;
325 void *buf;
326
327 buf = memalign(16, BUF_SIZE);
328 ut_assertnonnull(buf);
329 acpi_setup_base_tables(&ctx, buf);
330
331 ut_assertok(acpi_write_dev_tables(&ctx));
332
333 /* First search for a non-existent table */
334 console_record_reset();
335 run_command("acpi dump rdst", 0);
336 ut_assert_nextline("Table 'RDST' not found");
337 ut_assert_console_end();
338
339 /* Now a real table */
340 console_record_reset();
341 run_command("acpi dump dmar", 0);
342 addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64);
343 ut_assert_nextline("DMAR @ %08lx", addr);
344 ut_assert_nextlines_are_dump(0x30);
345 ut_assert_console_end();
346
347 return 0;
348}
349DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass1361a532020-07-07 13:11:39 -0600350
351/* Test acpi_device_path() */
352static int dm_test_acpi_device_path(struct unit_test_state *uts)
353{
354 struct testacpi_platdata *plat;
355 char buf[ACPI_PATH_MAX];
356 struct udevice *dev, *child;
357
358 ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
359 ut_assertok(acpi_device_path(dev, buf, sizeof(buf)));
360 ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME, buf);
361
362 /* Test running out of space */
363 buf[5] = '\0';
364 ut_asserteq(-ENOSPC, acpi_device_path(dev, buf, 5));
365 ut_asserteq('\0', buf[5]);
366
367 /* Test a three-component name */
368 ut_assertok(device_first_child_err(dev, &child));
369 ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
370 ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME "." ACPI_TEST_CHILD_NAME,
371 buf);
372
373 /* Test handling of a device which doesn't produce a name */
374 plat = dev_get_platdata(dev);
375 plat->no_name = true;
376 ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
377 ut_asserteq_str("\\_SB." ACPI_TEST_CHILD_NAME, buf);
378
379 /* Test handling of a device which returns an error */
380 plat = dev_get_platdata(dev);
381 plat->return_error = true;
382 ut_asserteq(-EINVAL, acpi_device_path(child, buf, sizeof(buf)));
383
384 return 0;
385}
386DM_TEST(dm_test_acpi_device_path, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass2715b362020-07-07 13:11:40 -0600387
388/* Test acpi_device_status() */
389static int dm_test_acpi_device_status(struct unit_test_state *uts)
390{
391 struct udevice *dev;
392
393 ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
394 ut_asserteq(ACPI_DSTATUS_ALL_ON, acpi_device_status(dev));
395
396 return 0;
397}
398DM_TEST(dm_test_acpi_device_status, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);