source: mainline/kernel/genarch/src/acpi/madt.c@ 0fb70e1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0fb70e1 was e2793a4, checked in by Jakub Jermar <jakub@…>, 14 years ago

Improve handling of ACPI MADT Interrupt Source Overrides slightly.

  • Do not ignore the override entries in the first place and propagate the changes into the IRQ to IO APIC pin map.
  • Do not assert on IRQ beyond the ISA IRQ limit in madt_irq_to_pin(); the excessive entries should be mapped identically.
  • The IRQ to pin map is still not used for anything.
  • Property mode set to 100644
File size: 6.8 KB
RevLine 
[10a2e22]1/*
[df4ed85]2 * Copyright (c) 2005 Jakub Jermar
[10a2e22]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[fe32163]29/** @addtogroup genarch
[b45c443]30 * @{
31 */
[0f27b4c]32/**
[7257021e]33 * @file
[fe32163]34 * @brief Multiple APIC Description Table (MADT) parsing.
[0f27b4c]35 */
36
[d99c1d2]37#include <typedefs.h>
[e16e036a]38#include <genarch/acpi/acpi.h>
39#include <genarch/acpi/madt.h>
[ed0dd65]40#include <arch/smp/apic.h>
[232e3ec7]41#include <arch/smp/smp.h>
[6b7c36f]42#include <panic.h>
[232e3ec7]43#include <debug.h>
44#include <config.h>
[9c0a9b3]45#include <print.h>
[085d973]46#include <mm/slab.h>
[50a4e25]47#include <memstr.h>
[8491c48]48#include <sort.h>
[10a2e22]49
50struct acpi_madt *acpi_madt = NULL;
[ed0dd65]51
[5f85c91]52#ifdef CONFIG_SMP
[ed0dd65]53
[fe32163]54/**
55 * Standard ISA IRQ map; can be overriden by
56 * Interrupt Source Override entries of MADT.
57 */
58static int isa_irq_map[] =
59 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
[6b7c36f]60
61struct madt_l_apic *madt_l_apic_entries = NULL;
62struct madt_io_apic *madt_io_apic_entries = NULL;
63
[fe32163]64static size_t madt_l_apic_entry_index = 0;
65static size_t madt_io_apic_entry_index = 0;
66static size_t madt_l_apic_entry_cnt = 0;
67static size_t madt_io_apic_entry_cnt = 0;
[6b7c36f]68
[fe32163]69static struct madt_apic_header **madt_entries_index = NULL;
[50a4e25]70
[a000878c]71const char *entry[] = {
[ed0dd65]72 "L_APIC",
73 "IO_APIC",
74 "INTR_SRC_OVRD",
75 "NMI_SRC",
76 "L_APIC_NMI",
77 "L_APIC_ADDR_OVRD",
78 "IO_SAPIC",
79 "L_SAPIC",
80 "PLATFORM_INTR_SRC"
81};
82
[fe32163]83static uint8_t madt_cpu_apic_id(size_t i)
[232e3ec7]84{
85 ASSERT(i < madt_l_apic_entry_cnt);
[fe32163]86
87 return ((struct madt_l_apic *)
88 madt_entries_index[madt_l_apic_entry_index + i])->apic_id;
[232e3ec7]89}
90
[fe32163]91static bool madt_cpu_enabled(size_t i)
[232e3ec7]92{
93 ASSERT(i < madt_l_apic_entry_cnt);
[fe32163]94
95 /*
96 * FIXME: The current local APIC driver limits usable
[4edd57fd]97 * CPU IDs to 8.
[fe32163]98 *
99 */
[4edd57fd]100 if (i > 7)
[fe32163]101 return false;
102
103 return ((struct madt_l_apic *)
104 madt_entries_index[madt_l_apic_entry_index + i])->flags & 0x1;
[232e3ec7]105}
106
[fe32163]107static bool madt_cpu_bootstrap(size_t i)
[232e3ec7]108{
109 ASSERT(i < madt_l_apic_entry_cnt);
[fe32163]110
111 return ((struct madt_l_apic *)
112 madt_entries_index[madt_l_apic_entry_index + i])->apic_id ==
[99718a2e]113 bsp_l_apic;
[232e3ec7]114}
115
[fe32163]116static int madt_irq_to_pin(unsigned int irq)
[a83a802]117{
[e2793a4]118 if (irq >= sizeof(isa_irq_map) / sizeof(int))
119 return (int) irq;
[fe32163]120
121 return isa_irq_map[irq];
[a83a802]122}
123
[fe32163]124/** ACPI MADT Implementation of SMP configuration interface.
125 *
126 */
127struct smp_config_operations madt_config_operations = {
128 .cpu_enabled = madt_cpu_enabled,
129 .cpu_bootstrap = madt_cpu_bootstrap,
130 .cpu_apic_id = madt_cpu_apic_id,
131 .irq_to_pin = madt_irq_to_pin
132};
133
[e9f4b59]134static int madt_cmp(void *a, void *b, void *arg)
[8491c48]135{
[e9f4b59]136 uint8_t typea = (*((struct madt_apic_header **) a))->type;
137 uint8_t typeb = (*((struct madt_apic_header **) b))->type;
[8491c48]138
[fe32163]139 if (typea > typeb)
140 return 1;
[2cd073bd]141
[fe32163]142 if (typea < typeb)
143 return -1;
144
145 return 0;
[ed0dd65]146}
[6b7c36f]147
[fe32163]148static void madt_l_apic_entry(struct madt_l_apic *la, size_t i)
[50a4e25]149{
[99718a2e]150 if (madt_l_apic_entry_cnt == 0)
[fe32163]151 madt_l_apic_entry_index = i;
152
[99718a2e]153 madt_l_apic_entry_cnt++;
154
[6b7c36f]155 if (!(la->flags & 0x1)) {
156 /* Processor is unusable, skip it. */
157 return;
158 }
[74b2f5bf]159
[fe32163]160 apic_id_mask |= 1 << la->apic_id;
[6b7c36f]161}
162
[fe32163]163static void madt_io_apic_entry(struct madt_io_apic *ioa, size_t i)
[6b7c36f]164{
[99718a2e]165 if (madt_io_apic_entry_cnt == 0) {
[fe32163]166 /* Remember index of the first io apic entry */
167 madt_io_apic_entry_index = i;
[96b02eb9]168 io_apic = (uint32_t *) (sysarg_t) ioa->io_apic_address;
[50a4e25]169 } else {
[fe32163]170 /* Currently not supported */
[6b7c36f]171 }
[99718a2e]172
173 madt_io_apic_entry_cnt++;
[6b7c36f]174}
175
[fe32163]176static void madt_intr_src_ovrd_entry(struct madt_intr_src_ovrd *override,
177 size_t i)
[a83a802]178{
[f4c2b6a]179 ASSERT(override->source < sizeof(isa_irq_map) / sizeof(int));
[fe32163]180
[e2793a4]181 isa_irq_map[override->source] = override->global_int;
[fe32163]182}
183
184void acpi_madt_parse(void)
185{
186 struct madt_apic_header *end = (struct madt_apic_header *)
187 (((uint8_t *) acpi_madt) + acpi_madt->header.length);
188 struct madt_apic_header *hdr;
189
[96b02eb9]190 l_apic = (uint32_t *) (sysarg_t) acpi_madt->l_apic_address;
[fe32163]191
192 /* Count MADT entries */
193 unsigned int madt_entries_index_cnt = 0;
[99718a2e]194 for (hdr = acpi_madt->apic_header; hdr < end;
[fe32163]195 hdr = (struct madt_apic_header *) (((uint8_t *) hdr) + hdr->length))
196 madt_entries_index_cnt++;
197
198 /* Create MADT APIC entries index array */
199 madt_entries_index = (struct madt_apic_header **)
[99718a2e]200 malloc(madt_entries_index_cnt * sizeof(struct madt_apic_header *),
[fe32163]201 FRAME_ATOMIC);
202 if (!madt_entries_index)
203 panic("Memory allocation error.");
204
205 size_t i = 0;
206
[99718a2e]207 for (hdr = acpi_madt->apic_header; hdr < end;
208 hdr = (struct madt_apic_header *) (((uint8_t *) hdr) + hdr->length)) {
209 madt_entries_index[i] = hdr;
210 i++;
211 }
[fe32163]212
213 /* Sort MADT index structure */
[e9f4b59]214 if (!gsort(madt_entries_index, madt_entries_index_cnt,
215 sizeof(struct madt_apic_header *), madt_cmp, NULL))
216 panic("Sorting error.");
[fe32163]217
218 /* Parse MADT entries */
219 for (i = 0; i < madt_entries_index_cnt; i++) {
220 hdr = madt_entries_index[i];
221
222 switch (hdr->type) {
223 case MADT_L_APIC:
224 madt_l_apic_entry((struct madt_l_apic *) hdr, i);
225 break;
226 case MADT_IO_APIC:
227 madt_io_apic_entry((struct madt_io_apic *) hdr, i);
228 break;
229 case MADT_INTR_SRC_OVRD:
230 madt_intr_src_ovrd_entry((struct madt_intr_src_ovrd *) hdr, i);
231 break;
232 case MADT_NMI_SRC:
233 case MADT_L_APIC_NMI:
234 case MADT_L_APIC_ADDR_OVRD:
235 case MADT_IO_SAPIC:
236 case MADT_L_SAPIC:
237 case MADT_PLATFORM_INTR_SRC:
238 printf("MADT: Skipping %s entry (type=%" PRIu8 ")\n",
239 entry[hdr->type], hdr->type);
240 break;
241 default:
242 if ((hdr->type >= MADT_RESERVED_SKIP_BEGIN)
243 && (hdr->type <= MADT_RESERVED_SKIP_END))
244 printf("MADT: Skipping reserved entry (type=%" PRIu8 ")\n",
245 hdr->type);
246
247 if (hdr->type >= MADT_RESERVED_OEM_BEGIN)
248 printf("MADT: Skipping OEM entry (type=%" PRIu8 ")\n",
249 hdr->type);
250
251 break;
252 }
253 }
254
255 if (madt_l_apic_entry_cnt > 0)
256 config.cpu_count = madt_l_apic_entry_cnt;
[a83a802]257}
[ed0dd65]258
[5f85c91]259#endif /* CONFIG_SMP */
[b45c443]260
[06e1e95]261/** @}
[b45c443]262 */
Note: See TracBrowser for help on using the repository browser.