1*32640292SAndy Fiddaman /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
3*32640292SAndy Fiddaman *
4*32640292SAndy Fiddaman * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5*32640292SAndy Fiddaman * Author: Corvin Köhne <c.koehne@beckhoff.com>
6*32640292SAndy Fiddaman */
7*32640292SAndy Fiddaman
8*32640292SAndy Fiddaman #include <sys/param.h>
9*32640292SAndy Fiddaman #include <sys/queue.h>
10*32640292SAndy Fiddaman
11*32640292SAndy Fiddaman #include <machine/vmm.h>
12*32640292SAndy Fiddaman
13*32640292SAndy Fiddaman #include <assert.h>
14*32640292SAndy Fiddaman #include <err.h>
15*32640292SAndy Fiddaman #include <errno.h>
16*32640292SAndy Fiddaman #include <vmmapi.h>
17*32640292SAndy Fiddaman
18*32640292SAndy Fiddaman #include "acpi.h"
19*32640292SAndy Fiddaman #include "acpi_device.h"
20*32640292SAndy Fiddaman #include "basl.h"
21*32640292SAndy Fiddaman
22*32640292SAndy Fiddaman /**
23*32640292SAndy Fiddaman * List entry to enumerate all resources used by an ACPI device.
24*32640292SAndy Fiddaman *
25*32640292SAndy Fiddaman * @param chain Used to chain multiple elements together.
26*32640292SAndy Fiddaman * @param type Type of the ACPI resource.
27*32640292SAndy Fiddaman * @param data Data of the ACPI resource.
28*32640292SAndy Fiddaman */
29*32640292SAndy Fiddaman struct acpi_resource_list_entry {
30*32640292SAndy Fiddaman SLIST_ENTRY(acpi_resource_list_entry) chain;
31*32640292SAndy Fiddaman UINT32 type;
32*32640292SAndy Fiddaman ACPI_RESOURCE_DATA data;
33*32640292SAndy Fiddaman };
34*32640292SAndy Fiddaman
35*32640292SAndy Fiddaman /**
36*32640292SAndy Fiddaman * Holds information about an ACPI device.
37*32640292SAndy Fiddaman *
38*32640292SAndy Fiddaman * @param vm_ctx VM context the ACPI device was created in.
39*32640292SAndy Fiddaman * @param softc A pointer to the software context of the ACPI device.
40*32640292SAndy Fiddaman * @param emul Device emulation struct. It contains some information like the
41*32640292SAndy Fiddaman name of the ACPI device and some device specific functions.
42*32640292SAndy Fiddaman * @param crs Current resources used by the ACPI device.
43*32640292SAndy Fiddaman */
44*32640292SAndy Fiddaman struct acpi_device {
45*32640292SAndy Fiddaman struct vmctx *vm_ctx;
46*32640292SAndy Fiddaman void *softc;
47*32640292SAndy Fiddaman const struct acpi_device_emul *emul;
48*32640292SAndy Fiddaman SLIST_HEAD(acpi_resource_list, acpi_resource_list_entry) crs;
49*32640292SAndy Fiddaman };
50*32640292SAndy Fiddaman
51*32640292SAndy Fiddaman int
acpi_device_create(struct acpi_device ** const new_dev,void * const softc,struct vmctx * const vm_ctx,const struct acpi_device_emul * const emul)52*32640292SAndy Fiddaman acpi_device_create(struct acpi_device **const new_dev, void *const softc,
53*32640292SAndy Fiddaman struct vmctx *const vm_ctx, const struct acpi_device_emul *const emul)
54*32640292SAndy Fiddaman {
55*32640292SAndy Fiddaman assert(new_dev != NULL);
56*32640292SAndy Fiddaman assert(vm_ctx != NULL);
57*32640292SAndy Fiddaman assert(emul != NULL);
58*32640292SAndy Fiddaman
59*32640292SAndy Fiddaman struct acpi_device *const dev = calloc(1, sizeof(*dev));
60*32640292SAndy Fiddaman if (dev == NULL) {
61*32640292SAndy Fiddaman return (ENOMEM);
62*32640292SAndy Fiddaman }
63*32640292SAndy Fiddaman
64*32640292SAndy Fiddaman dev->vm_ctx = vm_ctx;
65*32640292SAndy Fiddaman dev->softc = softc;
66*32640292SAndy Fiddaman dev->emul = emul;
67*32640292SAndy Fiddaman SLIST_INIT(&dev->crs);
68*32640292SAndy Fiddaman
69*32640292SAndy Fiddaman const int error = acpi_tables_add_device(dev);
70*32640292SAndy Fiddaman if (error) {
71*32640292SAndy Fiddaman acpi_device_destroy(dev);
72*32640292SAndy Fiddaman return (error);
73*32640292SAndy Fiddaman }
74*32640292SAndy Fiddaman
75*32640292SAndy Fiddaman *new_dev = dev;
76*32640292SAndy Fiddaman
77*32640292SAndy Fiddaman return (0);
78*32640292SAndy Fiddaman }
79*32640292SAndy Fiddaman
80*32640292SAndy Fiddaman void
acpi_device_destroy(struct acpi_device * const dev)81*32640292SAndy Fiddaman acpi_device_destroy(struct acpi_device *const dev)
82*32640292SAndy Fiddaman {
83*32640292SAndy Fiddaman if (dev == NULL) {
84*32640292SAndy Fiddaman return;
85*32640292SAndy Fiddaman }
86*32640292SAndy Fiddaman
87*32640292SAndy Fiddaman struct acpi_resource_list_entry *res;
88*32640292SAndy Fiddaman while (!SLIST_EMPTY(&dev->crs)) {
89*32640292SAndy Fiddaman res = SLIST_FIRST(&dev->crs);
90*32640292SAndy Fiddaman SLIST_REMOVE_HEAD(&dev->crs, chain);
91*32640292SAndy Fiddaman free(res);
92*32640292SAndy Fiddaman }
93*32640292SAndy Fiddaman
94*32640292SAndy Fiddaman free(dev);
95*32640292SAndy Fiddaman }
96*32640292SAndy Fiddaman
97*32640292SAndy Fiddaman int
acpi_device_add_res_fixed_ioport(struct acpi_device * const dev,const UINT16 port,const UINT8 length)98*32640292SAndy Fiddaman acpi_device_add_res_fixed_ioport(struct acpi_device *const dev,
99*32640292SAndy Fiddaman const UINT16 port, const UINT8 length)
100*32640292SAndy Fiddaman {
101*32640292SAndy Fiddaman if (dev == NULL) {
102*32640292SAndy Fiddaman return (EINVAL);
103*32640292SAndy Fiddaman }
104*32640292SAndy Fiddaman
105*32640292SAndy Fiddaman struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
106*32640292SAndy Fiddaman if (res == NULL) {
107*32640292SAndy Fiddaman return (ENOMEM);
108*32640292SAndy Fiddaman }
109*32640292SAndy Fiddaman
110*32640292SAndy Fiddaman res->type = ACPI_RESOURCE_TYPE_FIXED_IO;
111*32640292SAndy Fiddaman res->data.FixedIo.Address = port;
112*32640292SAndy Fiddaman res->data.FixedIo.AddressLength = length;
113*32640292SAndy Fiddaman
114*32640292SAndy Fiddaman SLIST_INSERT_HEAD(&dev->crs, res, chain);
115*32640292SAndy Fiddaman
116*32640292SAndy Fiddaman return (0);
117*32640292SAndy Fiddaman }
118*32640292SAndy Fiddaman
119*32640292SAndy Fiddaman int
acpi_device_add_res_fixed_memory32(struct acpi_device * const dev,const UINT8 write_protected,const UINT32 address,const UINT32 length)120*32640292SAndy Fiddaman acpi_device_add_res_fixed_memory32(struct acpi_device *const dev,
121*32640292SAndy Fiddaman const UINT8 write_protected, const UINT32 address, const UINT32 length)
122*32640292SAndy Fiddaman {
123*32640292SAndy Fiddaman if (dev == NULL) {
124*32640292SAndy Fiddaman return (EINVAL);
125*32640292SAndy Fiddaman }
126*32640292SAndy Fiddaman
127*32640292SAndy Fiddaman struct acpi_resource_list_entry *const res = calloc(1, sizeof(*res));
128*32640292SAndy Fiddaman if (res == NULL) {
129*32640292SAndy Fiddaman return (ENOMEM);
130*32640292SAndy Fiddaman }
131*32640292SAndy Fiddaman
132*32640292SAndy Fiddaman res->type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
133*32640292SAndy Fiddaman res->data.FixedMemory32.WriteProtect = write_protected;
134*32640292SAndy Fiddaman res->data.FixedMemory32.Address = address;
135*32640292SAndy Fiddaman res->data.FixedMemory32.AddressLength = length;
136*32640292SAndy Fiddaman
137*32640292SAndy Fiddaman SLIST_INSERT_HEAD(&dev->crs, res, chain);
138*32640292SAndy Fiddaman
139*32640292SAndy Fiddaman return (0);
140*32640292SAndy Fiddaman }
141*32640292SAndy Fiddaman
142*32640292SAndy Fiddaman void *
acpi_device_get_softc(const struct acpi_device * const dev)143*32640292SAndy Fiddaman acpi_device_get_softc(const struct acpi_device *const dev)
144*32640292SAndy Fiddaman {
145*32640292SAndy Fiddaman assert(dev != NULL);
146*32640292SAndy Fiddaman
147*32640292SAndy Fiddaman return (dev->softc);
148*32640292SAndy Fiddaman }
149*32640292SAndy Fiddaman
150*32640292SAndy Fiddaman int
acpi_device_build_table(const struct acpi_device * const dev)151*32640292SAndy Fiddaman acpi_device_build_table(const struct acpi_device *const dev)
152*32640292SAndy Fiddaman {
153*32640292SAndy Fiddaman assert(dev != NULL);
154*32640292SAndy Fiddaman assert(dev->emul != NULL);
155*32640292SAndy Fiddaman
156*32640292SAndy Fiddaman if (dev->emul->build_table != NULL) {
157*32640292SAndy Fiddaman return (dev->emul->build_table(dev));
158*32640292SAndy Fiddaman }
159*32640292SAndy Fiddaman
160*32640292SAndy Fiddaman return (0);
161*32640292SAndy Fiddaman }
162*32640292SAndy Fiddaman
163*32640292SAndy Fiddaman static int
acpi_device_write_dsdt_crs(const struct acpi_device * const dev)164*32640292SAndy Fiddaman acpi_device_write_dsdt_crs(const struct acpi_device *const dev)
165*32640292SAndy Fiddaman {
166*32640292SAndy Fiddaman const struct acpi_resource_list_entry *res;
167*32640292SAndy Fiddaman SLIST_FOREACH(res, &dev->crs, chain) {
168*32640292SAndy Fiddaman switch (res->type) {
169*32640292SAndy Fiddaman case ACPI_RESOURCE_TYPE_FIXED_IO:
170*32640292SAndy Fiddaman dsdt_fixed_ioport(res->data.FixedIo.Address,
171*32640292SAndy Fiddaman res->data.FixedIo.AddressLength);
172*32640292SAndy Fiddaman break;
173*32640292SAndy Fiddaman case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
174*32640292SAndy Fiddaman dsdt_fixed_mem32(res->data.FixedMemory32.Address,
175*32640292SAndy Fiddaman res->data.FixedMemory32.AddressLength);
176*32640292SAndy Fiddaman break;
177*32640292SAndy Fiddaman default:
178*32640292SAndy Fiddaman assert(0);
179*32640292SAndy Fiddaman break;
180*32640292SAndy Fiddaman }
181*32640292SAndy Fiddaman }
182*32640292SAndy Fiddaman
183*32640292SAndy Fiddaman return (0);
184*32640292SAndy Fiddaman }
185*32640292SAndy Fiddaman
186*32640292SAndy Fiddaman int
acpi_device_write_dsdt(const struct acpi_device * const dev)187*32640292SAndy Fiddaman acpi_device_write_dsdt(const struct acpi_device *const dev)
188*32640292SAndy Fiddaman {
189*32640292SAndy Fiddaman assert(dev != NULL);
190*32640292SAndy Fiddaman
191*32640292SAndy Fiddaman dsdt_line("");
192*32640292SAndy Fiddaman dsdt_line(" Scope (\\_SB)");
193*32640292SAndy Fiddaman dsdt_line(" {");
194*32640292SAndy Fiddaman dsdt_line(" Device (%s)", dev->emul->name);
195*32640292SAndy Fiddaman dsdt_line(" {");
196*32640292SAndy Fiddaman dsdt_line(" Name (_HID, \"%s\")", dev->emul->hid);
197*32640292SAndy Fiddaman dsdt_line(" Name (_STA, 0x0F)");
198*32640292SAndy Fiddaman dsdt_line(" Name (_CRS, ResourceTemplate ()");
199*32640292SAndy Fiddaman dsdt_line(" {");
200*32640292SAndy Fiddaman dsdt_indent(4);
201*32640292SAndy Fiddaman BASL_EXEC(acpi_device_write_dsdt_crs(dev));
202*32640292SAndy Fiddaman dsdt_unindent(4);
203*32640292SAndy Fiddaman dsdt_line(" })");
204*32640292SAndy Fiddaman if (dev->emul->write_dsdt != NULL) {
205*32640292SAndy Fiddaman dsdt_indent(3);
206*32640292SAndy Fiddaman BASL_EXEC(dev->emul->write_dsdt(dev));
207*32640292SAndy Fiddaman dsdt_unindent(3);
208*32640292SAndy Fiddaman }
209*32640292SAndy Fiddaman dsdt_line(" }");
210*32640292SAndy Fiddaman dsdt_line(" }");
211*32640292SAndy Fiddaman
212*32640292SAndy Fiddaman return (0);
213*32640292SAndy Fiddaman }
214