blob: 4e1d401e0d6c48f7f8eab9dcb6e4b9189d116ce3 [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 Glassb5183172020-07-07 13:12:03 -060017#include <acpi/acpigen.h>
Simon Glass1361a532020-07-07 13:11:39 -060018#include <acpi/acpi_device.h>
Simon Glass91fe8b72020-04-08 16:57:38 -060019#include <acpi/acpi_table.h>
Simon Glassf50cc952020-04-08 16:57:34 -060020#include <dm/acpi.h>
21#include <dm/test.h>
22#include <test/ut.h>
23
24#define ACPI_TEST_DEV_NAME "ABCD"
Simon Glass1361a532020-07-07 13:11:39 -060025#define ACPI_TEST_CHILD_NAME "EFGH"
Simon Glass93f7f822020-04-26 09:19:46 -060026#define BUF_SIZE 4096
27
Simon Glass1361a532020-07-07 13:11:39 -060028/**
29 * struct testacpi_platdata - Platform data for the test ACPI device
30 *
31 * @no_name: true to emit an empty ACPI name from testacpi_get_name()
32 * @return_error: true to return an error instead of a name
33 */
34struct testacpi_platdata {
35 bool return_error;
36 bool no_name;
37};
38
Simon Glass93f7f822020-04-26 09:19:46 -060039static int testacpi_write_tables(const struct udevice *dev,
40 struct acpi_ctx *ctx)
41{
42 struct acpi_dmar *dmar;
Simon Glass29b35112020-04-26 09:19:50 -060043 int ret;
Simon Glass93f7f822020-04-26 09:19:46 -060044
45 dmar = (struct acpi_dmar *)ctx->current;
46 acpi_create_dmar(dmar, DMAR_INTR_REMAP);
47 ctx->current += sizeof(struct acpi_dmar);
Simon Glass29b35112020-04-26 09:19:50 -060048 ret = acpi_add_table(ctx, dmar);
49 if (ret)
50 return log_msg_ret("add", ret);
Simon Glass93f7f822020-04-26 09:19:46 -060051
52 return 0;
53}
Simon Glassf50cc952020-04-08 16:57:34 -060054
55static int testacpi_get_name(const struct udevice *dev, char *out_name)
56{
Simon Glass1361a532020-07-07 13:11:39 -060057 struct testacpi_platdata *plat = dev_get_platdata(dev);
58
59 if (plat->return_error)
60 return -EINVAL;
61 if (plat->no_name) {
62 *out_name = '\0';
63 return 0;
64 }
65 if (device_get_uclass_id(dev->parent) == UCLASS_TEST_ACPI)
66 return acpi_copy_name(out_name, ACPI_TEST_CHILD_NAME);
67 else
68 return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME);
Simon Glassf50cc952020-04-08 16:57:34 -060069}
70
Simon Glassb5183172020-07-07 13:12:03 -060071static int testacpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
72{
73 const char *data;
74
75 data = dev_read_string(dev, "acpi-ssdt-test-data");
76 if (data) {
77 while (*data)
78 acpigen_emit_byte(ctx, *data++);
79 }
80
81 return 0;
82}
83
Simon Glassf50cc952020-04-08 16:57:34 -060084struct acpi_ops testacpi_ops = {
85 .get_name = testacpi_get_name,
Simon Glass93f7f822020-04-26 09:19:46 -060086 .write_tables = testacpi_write_tables,
Simon Glassb5183172020-07-07 13:12:03 -060087 .fill_ssdt = testacpi_fill_ssdt,
Simon Glassf50cc952020-04-08 16:57:34 -060088};
89
90static const struct udevice_id testacpi_ids[] = {
91 { .compatible = "denx,u-boot-acpi-test" },
92 { }
93};
94
95U_BOOT_DRIVER(testacpi_drv) = {
96 .name = "testacpi_drv",
97 .of_match = testacpi_ids,
98 .id = UCLASS_TEST_ACPI,
Simon Glass1361a532020-07-07 13:11:39 -060099 .bind = dm_scan_fdt_dev,
100 .platdata_auto_alloc_size = sizeof(struct testacpi_platdata),
Simon Glassf50cc952020-04-08 16:57:34 -0600101 ACPI_OPS_PTR(&testacpi_ops)
102};
103
104UCLASS_DRIVER(testacpi) = {
105 .name = "testacpi",
106 .id = UCLASS_TEST_ACPI,
107};
108
109/* Test ACPI get_name() */
110static int dm_test_acpi_get_name(struct unit_test_state *uts)
111{
112 char name[ACPI_NAME_MAX];
113 struct udevice *dev;
114
115 ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
116 ut_assertok(acpi_get_name(dev, name));
117 ut_asserteq_str(ACPI_TEST_DEV_NAME, name);
118
119 return 0;
120}
121DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass91fe8b72020-04-08 16:57:38 -0600122
123/* Test acpi_get_table_revision() */
124static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
125{
126 ut_asserteq(1, acpi_get_table_revision(ACPITAB_MCFG));
127 ut_asserteq(2, acpi_get_table_revision(ACPITAB_RSDP));
128 ut_asserteq(4, acpi_get_table_revision(ACPITAB_TPM2));
129 ut_asserteq(-EINVAL, acpi_get_table_revision(ACPITAB_COUNT));
130
131 return 0;
132}
133DM_TEST(dm_test_acpi_get_table_revision,
134 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassbfeb5d42020-04-08 16:57:39 -0600135
Simon Glassbfeb5d42020-04-08 16:57:39 -0600136/* Test acpi_create_dmar() */
137static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
138{
139 struct acpi_dmar dmar;
140
141 ut_assertok(acpi_create_dmar(&dmar, DMAR_INTR_REMAP));
142 ut_asserteq(DMAR_INTR_REMAP, dmar.flags);
143 ut_asserteq(32 - 1, dmar.host_address_width);
144
145 return 0;
146}
147DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass93f7f822020-04-26 09:19:46 -0600148
149/* Test acpi_fill_header() */
150static int dm_test_acpi_fill_header(struct unit_test_state *uts)
151{
152 struct acpi_table_header hdr;
153
154 /* Make sure these 5 fields are not changed */
155 hdr.length = 0x11;
156 hdr.revision = 0x22;
157 hdr.checksum = 0x33;
158 hdr.aslc_revision = 0x44;
159 acpi_fill_header(&hdr, "ABCD");
160
161 ut_asserteq_mem("ABCD", hdr.signature, sizeof(hdr.signature));
162 ut_asserteq(0x11, hdr.length);
163 ut_asserteq(0x22, hdr.revision);
164 ut_asserteq(0x33, hdr.checksum);
165 ut_asserteq_mem(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id));
166 ut_asserteq_mem(OEM_TABLE_ID, hdr.oem_table_id,
167 sizeof(hdr.oem_table_id));
168 ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision);
169 ut_asserteq_mem(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id));
170 ut_asserteq(0x44, hdr.aslc_revision);
171
172 return 0;
173}
174DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
175
176/* Test ACPI write_tables() */
177static int dm_test_acpi_write_tables(struct unit_test_state *uts)
178{
179 struct acpi_dmar *dmar;
180 struct acpi_ctx ctx;
181 void *buf;
Simon Glass1361a532020-07-07 13:11:39 -0600182 int i;
Simon Glass93f7f822020-04-26 09:19:46 -0600183
184 buf = malloc(BUF_SIZE);
185 ut_assertnonnull(buf);
186
Simon Glass7e586f62020-04-26 09:19:51 -0600187 acpi_setup_base_tables(&ctx, buf);
Simon Glass29b35112020-04-26 09:19:50 -0600188 dmar = ctx.current;
Simon Glass93f7f822020-04-26 09:19:46 -0600189 ut_assertok(acpi_write_dev_tables(&ctx));
Simon Glass93f7f822020-04-26 09:19:46 -0600190
191 /*
Simon Glass1361a532020-07-07 13:11:39 -0600192 * We should have three dmar tables, one for each
193 * "denx,u-boot-acpi-test" device
Simon Glass93f7f822020-04-26 09:19:46 -0600194 */
Simon Glass1361a532020-07-07 13:11:39 -0600195 ut_asserteq_ptr(dmar + 3, ctx.current);
Simon Glass93f7f822020-04-26 09:19:46 -0600196 ut_asserteq(DMAR_INTR_REMAP, dmar->flags);
197 ut_asserteq(32 - 1, dmar->host_address_width);
198
199 ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
200 ut_asserteq(32 - 1, dmar[1].host_address_width);
201
Simon Glass1361a532020-07-07 13:11:39 -0600202 ut_asserteq(DMAR_INTR_REMAP, dmar[2].flags);
203 ut_asserteq(32 - 1, dmar[2].host_address_width);
Simon Glass7e586f62020-04-26 09:19:51 -0600204
Simon Glass1361a532020-07-07 13:11:39 -0600205 /* Check that the pointers were added correctly */
206 for (i = 0; i < 3; i++) {
207 ut_asserteq(map_to_sysmem(dmar + i), ctx.rsdt->entry[i]);
208 ut_asserteq(map_to_sysmem(dmar + i), ctx.xsdt->entry[i]);
209 }
210 ut_asserteq(0, ctx.rsdt->entry[3]);
211 ut_asserteq(0, ctx.xsdt->entry[3]);
Simon Glassb38309b2020-04-26 09:19:52 -0600212
Simon Glass93f7f822020-04-26 09:19:46 -0600213 return 0;
214}
215DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass86e17782020-04-26 09:19:47 -0600216
217/* Test basic ACPI functions */
218static int dm_test_acpi_basic(struct unit_test_state *uts)
219{
220 struct acpi_ctx ctx;
221
222 /* Check align works */
223 ctx.current = (void *)5;
224 acpi_align(&ctx);
225 ut_asserteq_ptr((void *)16, ctx.current);
226
227 /* Check that align does nothing if already aligned */
228 acpi_align(&ctx);
229 ut_asserteq_ptr((void *)16, ctx.current);
230 acpi_align64(&ctx);
231 ut_asserteq_ptr((void *)64, ctx.current);
232 acpi_align64(&ctx);
233 ut_asserteq_ptr((void *)64, ctx.current);
234
235 /* Check incrementing */
236 acpi_inc(&ctx, 3);
237 ut_asserteq_ptr((void *)67, ctx.current);
238 acpi_inc_align(&ctx, 3);
239 ut_asserteq_ptr((void *)80, ctx.current);
240
241 return 0;
242}
243DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass7e586f62020-04-26 09:19:51 -0600244
245/* Test acpi_setup_base_tables */
246static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
247{
248 struct acpi_rsdp *rsdp;
249 struct acpi_rsdt *rsdt;
250 struct acpi_xsdt *xsdt;
251 struct acpi_ctx ctx;
252 void *buf, *end;
253
254 /*
255 * Use an unaligned address deliberately, by allocating an aligned
256 * address and then adding 4 to it
257 */
258 buf = memalign(64, BUF_SIZE);
259 ut_assertnonnull(buf);
260 acpi_setup_base_tables(&ctx, buf + 4);
Simon Glass0b885bc2020-04-26 09:19:53 -0600261 ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd->arch.acpi_start);
Simon Glass7e586f62020-04-26 09:19:51 -0600262
263 rsdp = buf + 16;
264 ut_asserteq_ptr(rsdp, ctx.rsdp);
Simon Glassf91f3662020-05-10 12:52:45 -0600265 ut_asserteq_mem(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature));
Simon Glass7e586f62020-04-26 09:19:51 -0600266 ut_asserteq(sizeof(*rsdp), rsdp->length);
267 ut_assertok(table_compute_checksum(rsdp, 20));
268 ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp)));
269
270 rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
271 ut_asserteq_ptr(rsdt, ctx.rsdt);
Simon Glassf91f3662020-05-10 12:52:45 -0600272 ut_asserteq_mem("RSDT", rsdt->header.signature, ACPI_NAME_LEN);
Simon Glass7e586f62020-04-26 09:19:51 -0600273 ut_asserteq(sizeof(*rsdt), rsdt->header.length);
274 ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
275
276 xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
Simon Glassb38309b2020-04-26 09:19:52 -0600277 ut_asserteq_ptr(xsdt, ctx.xsdt);
Simon Glassf91f3662020-05-10 12:52:45 -0600278 ut_asserteq_mem("XSDT", xsdt->header.signature, ACPI_NAME_LEN);
Simon Glass7e586f62020-04-26 09:19:51 -0600279 ut_asserteq(sizeof(*xsdt), xsdt->header.length);
280 ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
281
282 end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
283 ut_asserteq_ptr(end, ctx.current);
284
285 ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address);
286 ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address);
287
288 return 0;
289}
290DM_TEST(dm_test_acpi_setup_base_tables,
291 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass0b885bc2020-04-26 09:19:53 -0600292
293/* Test 'acpi list' command */
294static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
295{
296 struct acpi_ctx ctx;
297 ulong addr;
298 void *buf;
299
300 buf = memalign(16, BUF_SIZE);
301 ut_assertnonnull(buf);
302 acpi_setup_base_tables(&ctx, buf);
303
304 ut_assertok(acpi_write_dev_tables(&ctx));
305
306 console_record_reset();
307 run_command("acpi list", 0);
308 addr = (ulong)map_to_sysmem(buf);
309 ut_assert_nextline("ACPI tables start at %lx", addr);
310 ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
311 sizeof(struct acpi_rsdp));
312 addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
313 ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
314 addr, sizeof(struct acpi_table_header) +
Simon Glass1361a532020-07-07 13:11:39 -0600315 3 * sizeof(u32), U_BOOT_BUILD_DATE);
Simon Glass0b885bc2020-04-26 09:19:53 -0600316 addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
317 ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
318 addr, sizeof(struct acpi_table_header) +
Simon Glass1361a532020-07-07 13:11:39 -0600319 3 * sizeof(u64), U_BOOT_BUILD_DATE);
Simon Glass0b885bc2020-04-26 09:19:53 -0600320 addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
321 ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
322 addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
323 addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
324 ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
325 addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
Simon Glass1361a532020-07-07 13:11:39 -0600326 addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
327 ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
328 addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
Simon Glass0b885bc2020-04-26 09:19:53 -0600329 ut_assert_console_end();
330
331 return 0;
332}
333DM_TEST(dm_test_acpi_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
334
335/* Test 'acpi dump' command */
336static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
337{
338 struct acpi_ctx ctx;
339 ulong addr;
340 void *buf;
341
342 buf = memalign(16, BUF_SIZE);
343 ut_assertnonnull(buf);
344 acpi_setup_base_tables(&ctx, buf);
345
346 ut_assertok(acpi_write_dev_tables(&ctx));
347
348 /* First search for a non-existent table */
349 console_record_reset();
350 run_command("acpi dump rdst", 0);
351 ut_assert_nextline("Table 'RDST' not found");
352 ut_assert_console_end();
353
354 /* Now a real table */
355 console_record_reset();
356 run_command("acpi dump dmar", 0);
357 addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64);
358 ut_assert_nextline("DMAR @ %08lx", addr);
359 ut_assert_nextlines_are_dump(0x30);
360 ut_assert_console_end();
361
362 return 0;
363}
364DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass1361a532020-07-07 13:11:39 -0600365
366/* Test acpi_device_path() */
367static int dm_test_acpi_device_path(struct unit_test_state *uts)
368{
369 struct testacpi_platdata *plat;
370 char buf[ACPI_PATH_MAX];
371 struct udevice *dev, *child;
372
373 ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
374 ut_assertok(acpi_device_path(dev, buf, sizeof(buf)));
375 ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME, buf);
376
377 /* Test running out of space */
378 buf[5] = '\0';
379 ut_asserteq(-ENOSPC, acpi_device_path(dev, buf, 5));
380 ut_asserteq('\0', buf[5]);
381
382 /* Test a three-component name */
383 ut_assertok(device_first_child_err(dev, &child));
384 ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
385 ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME "." ACPI_TEST_CHILD_NAME,
386 buf);
387
388 /* Test handling of a device which doesn't produce a name */
389 plat = dev_get_platdata(dev);
390 plat->no_name = true;
391 ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
392 ut_asserteq_str("\\_SB." ACPI_TEST_CHILD_NAME, buf);
393
394 /* Test handling of a device which returns an error */
395 plat = dev_get_platdata(dev);
396 plat->return_error = true;
397 ut_asserteq(-EINVAL, acpi_device_path(child, buf, sizeof(buf)));
398
399 return 0;
400}
401DM_TEST(dm_test_acpi_device_path, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glass2715b362020-07-07 13:11:40 -0600402
403/* Test acpi_device_status() */
404static int dm_test_acpi_device_status(struct unit_test_state *uts)
405{
406 struct udevice *dev;
407
408 ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
409 ut_asserteq(ACPI_DSTATUS_ALL_ON, acpi_device_status(dev));
410
411 return 0;
412}
413DM_TEST(dm_test_acpi_device_status, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Simon Glassb5183172020-07-07 13:12:03 -0600414
415/* Test acpi_fill_ssdt() */
416static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts)
417{
418 struct acpi_ctx ctx;
419 u8 *buf;
420
421 buf = malloc(BUF_SIZE);
422 ut_assertnonnull(buf);
423
424 ctx.current = buf;
425 buf[4] = 'z'; /* sentinel */
426 ut_assertok(acpi_fill_ssdt(&ctx));
427
Simon Glass0f7b1112020-07-07 13:12:06 -0600428 /*
429 * These values come from acpi-test2's acpi-ssdt-test-data property.
430 * This device comes first because of u-boot,acpi-ssdt-order
431 */
432 ut_asserteq('c', buf[0]);
433 ut_asserteq('d', buf[1]);
Simon Glassb5183172020-07-07 13:12:03 -0600434
Simon Glass0f7b1112020-07-07 13:12:06 -0600435 /* These values come from acpi-test's acpi-ssdt-test-data property */
436 ut_asserteq('a', buf[2]);
437 ut_asserteq('b', buf[3]);
Simon Glassb5183172020-07-07 13:12:03 -0600438
439 ut_asserteq('z', buf[4]);
440
441 return 0;
442}
443DM_TEST(dm_test_acpi_fill_ssdt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);