]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/gic_acpi.c
Add a testcase to test ls -s; remove an unnecessary sync
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / gic_acpi.c
1 /*-
2  * Copyright (c) 2015 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Andrew Turner under
6  * sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37
38 #include <machine/bus.h>
39
40 #include <arm64/arm64/gic.h>
41
42 #include <contrib/dev/acpica/include/acpi.h>
43
44 #include <dev/acpica/acpivar.h>
45
46 struct arm_gic_acpi_softc {
47         struct arm_gic_softc gic_sc;
48         struct resource_list res;
49 };
50
51 struct madt_table_data {
52         device_t parent;
53         ACPI_MADT_GENERIC_DISTRIBUTOR *dist;
54         ACPI_MADT_GENERIC_INTERRUPT *intr;
55 };
56
57 static void
58 madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
59 {
60         struct madt_table_data *madt_data;
61
62         madt_data = (struct madt_table_data *)arg;
63
64         switch(entry->Type) {
65         case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
66                 if (madt_data->intr != NULL) {
67                         if (bootverbose)
68                                 device_printf(madt_data->parent,
69                                     "gic: Already have an interrupt table");
70                         break;
71                 }
72
73                 madt_data->intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
74                 break;
75
76         case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
77                 if (madt_data->dist != NULL) {
78                         if (bootverbose)
79                                 device_printf(madt_data->parent,
80                                     "gic: Already have a distributor table");
81                         break;
82                 }
83
84                 madt_data->dist = (ACPI_MADT_GENERIC_DISTRIBUTOR *)entry;
85                 break;
86
87         default:
88                 break;
89         }
90 }
91
92 static void
93 arm_gic_acpi_identify(driver_t *driver, device_t parent)
94 {
95         struct madt_table_data madt_data;
96         ACPI_TABLE_MADT *madt;
97         vm_paddr_t physaddr;
98         device_t dev;
99
100         physaddr = acpi_find_table(ACPI_SIG_MADT);
101         if (physaddr == 0)
102                 return;
103
104         madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
105         if (madt == NULL) {
106                 device_printf(parent, "gic: Unable to map the MADT\n");
107                 return;
108         }
109
110         madt_data.parent = parent;
111         madt_data.dist = NULL;
112         madt_data.intr = NULL;
113
114         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
115             madt_handler, &madt_data);
116         if (madt_data.intr == NULL || madt_data.dist == NULL) {
117                 device_printf(parent,
118                     "No gic interrupt or distributor table\n");
119                 goto out;
120         }
121
122         dev = BUS_ADD_CHILD(parent, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE,
123             "gic", -1);
124         if (dev == NULL) {
125                 device_printf(parent, "add gic child failed\n");
126                 goto out;
127         }
128
129         /* Add the MADT data */
130         BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0,
131             madt_data.dist->BaseAddress, PAGE_SIZE);
132         BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 1,
133             madt_data.intr->BaseAddress, PAGE_SIZE);
134
135 out:
136         acpi_unmap_table(madt);
137 }
138
139 static int
140 arm_gic_acpi_probe(device_t dev)
141 {
142
143         device_set_desc(dev, "ARM Generic Interrupt Controller");
144         return (BUS_PROBE_NOWILDCARD);
145 }
146
147 static device_method_t arm_gic_acpi_methods[] = {
148         /* Device interface */
149         DEVMETHOD(device_identify,      arm_gic_acpi_identify),
150         DEVMETHOD(device_probe,         arm_gic_acpi_probe),
151
152         DEVMETHOD_END
153 };
154
155 DEFINE_CLASS_1(gic, arm_gic_acpi_driver, arm_gic_acpi_methods,
156     sizeof(struct arm_gic_acpi_softc), arm_gic_driver);
157
158 static devclass_t arm_gic_acpi_devclass;
159
160 EARLY_DRIVER_MODULE(gic, acpi, arm_gic_acpi_driver,
161     arm_gic_acpi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);