Merge branch 'master' of git://git.theshell.com/dragonfly
[dragonfly.git] / sys / platform / pc64 / x86_64 / mp_madt.c
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
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
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38
39 #include <machine/pmap.h>
40 #include <machine/smp.h>
41 #include <machine/md_var.h>
42 #include <machine/specialreg.h>
43 #include <machine_base/apic/mpapic.h>
44
45 #define MADT_VPRINTF(fmt, arg...) \
46 do { \
47         if (bootverbose) \
48                 kprintf("ACPI MADT: " fmt , ##arg); \
49 } while (0)
50
51 #define ACPI_RSDP_EBDA_MAPSZ    1024
52 #define ACPI_RSDP_BIOS_MAPSZ    0x20000
53 #define ACPI_RSDP_BIOS_MAPADDR  0xe0000
54
55 #define ACPI_RSDP_ALIGN         16
56
57 #define ACPI_RSDP_SIGLEN        8
58 #define ACPI_RSDP_SIG           "RSD PTR "
59
60 #define ACPI_SDTH_SIGLEN        4
61 #define ACPI_RSDT_SIG           "RSDT"
62 #define ACPI_XSDT_SIG           "XSDT"
63 #define ACPI_MADT_SIG           "APIC"
64
65 /* Root System Description Pointer */
66 struct acpi_rsdp {
67         uint8_t                 rsdp_sig[ACPI_RSDP_SIGLEN];
68         uint8_t                 rsdp_cksum;
69         uint8_t                 rsdp_oem_id[6];
70         uint8_t                 rsdp_rev;
71         uint32_t                rsdp_rsdt;
72         uint32_t                rsdp_len;
73         uint64_t                rsdp_xsdt;
74         uint8_t                 rsdp_ext_cksum;
75         uint8_t                 rsdp_rsvd[3];
76 } __packed;
77
78 /* System Description Table Header */
79 struct acpi_sdth {
80         uint8_t                 sdth_sig[ACPI_SDTH_SIGLEN];
81         uint32_t                sdth_len;
82         uint8_t                 sdth_rev;
83         uint8_t                 sdth_cksum;
84         uint8_t                 sdth_oem_id[6];
85         uint8_t                 sdth_oem_tbid[8];
86         uint32_t                sdth_oem_rev;
87         uint32_t                sdth_crt_id;
88         uint32_t                sdth_crt_rev;
89 } __packed;
90
91 /* Extended System Description Table */
92 struct acpi_xsdt {
93         struct acpi_sdth        xsdt_hdr;
94         uint64_t                xsdt_ents[1];
95 } __packed;
96
97 /* Root System Description Table */
98 struct acpi_rsdt {
99         struct acpi_sdth        rsdt_hdr;
100         uint32_t                rsdt_ents[1];
101 } __packed;
102
103 /* Multiple APIC Description Table */
104 struct acpi_madt {
105         struct acpi_sdth        madt_hdr;
106         uint32_t                madt_lapic_addr;
107         uint32_t                madt_flags;
108         uint8_t                 madt_ents[1];
109 } __packed;
110
111 /* Common parts of MADT APIC structure */
112 struct acpi_madt_ent {
113         uint8_t                 me_type;        /* MADT_ENT_ */
114         uint8_t                 me_len;
115 } __packed;
116
117 #define MADT_ENT_LAPIC          0
118 #define MADT_ENT_IOAPIC         1
119 #define MADT_ENT_LAPIC_ADDR     5
120
121 /* MADT Processor Local APIC */
122 struct acpi_madt_lapic {
123         struct acpi_madt_ent    ml_hdr;
124         uint8_t                 ml_cpu_id;
125         uint8_t                 ml_apic_id;
126         uint32_t                ml_flags;       /* MADT_LAPIC_ */
127 } __packed;
128
129 #define MADT_LAPIC_ENABLED      0x1
130
131 /* MADT I/O APIC */
132 struct acpi_madt_ioapic {
133         struct acpi_madt_ent    mio_hdr;
134         uint8_t                 mio_apic_id;
135         uint8_t                 mio_reserved;
136         uint32_t                mio_addr;
137         uint32_t                mio_gsi_base;
138 } __packed;
139
140 /* MADT Local APIC Address Override */
141 struct acpi_madt_lapic_addr {
142         struct acpi_madt_ent    mla_hdr;
143         uint16_t                mla_reserved;
144         uint64_t                mla_lapic_addr;
145 } __packed;
146
147 struct madt_lapic_enumerator {
148         struct lapic_enumerator enumerator;
149         vm_paddr_t              madt_paddr;
150 };
151
152 typedef vm_paddr_t              (*madt_search_t)(vm_paddr_t);
153 typedef int                     (*madt_iter_t)(void *,
154                                     const struct acpi_madt_ent *);
155
156 static const struct acpi_rsdp   *madt_rsdp_search(const uint8_t *, int);
157 static void                     *madt_sdth_map(vm_paddr_t);
158 static void                     madt_sdth_unmap(struct acpi_sdth *);
159 static vm_paddr_t               madt_search_xsdt(vm_paddr_t);
160 static vm_paddr_t               madt_search_rsdt(vm_paddr_t);
161 static int                      madt_check(vm_paddr_t);
162 static int                      madt_iterate_entries(struct acpi_madt *,
163                                     madt_iter_t, void *);
164
165 static vm_paddr_t               madt_probe(void);
166 static vm_offset_t              madt_pass1(vm_paddr_t);
167 static int                      madt_pass2(vm_paddr_t, int);
168
169 static void                     madt_lapic_enumerate(struct lapic_enumerator *);
170 static int                      madt_lapic_probe(struct lapic_enumerator *);
171
172 extern u_long   ebda_addr;
173
174 static vm_paddr_t
175 madt_probe(void)
176 {
177         const struct acpi_rsdp *rsdp;
178         madt_search_t search;
179         vm_paddr_t search_paddr, madt_paddr;
180         vm_size_t mapsz;
181         uint8_t *ptr;
182
183         if (ebda_addr != 0) {
184                 mapsz = ACPI_RSDP_EBDA_MAPSZ;
185                 ptr = pmap_mapdev(ebda_addr, mapsz);
186
187                 rsdp = madt_rsdp_search(ptr, mapsz);
188                 if (rsdp == NULL) {
189                         MADT_VPRINTF("RSDP not in EBDA\n");
190                         pmap_unmapdev((vm_offset_t)ptr, mapsz);
191
192                         ptr = NULL;
193                         mapsz = 0;
194                 } else {
195                         MADT_VPRINTF("RSDP in EBDA\n");
196                         goto found_rsdp;
197                 }
198         }
199
200         mapsz = ACPI_RSDP_BIOS_MAPSZ;
201         ptr = pmap_mapdev(ACPI_RSDP_BIOS_MAPADDR, mapsz);
202
203         rsdp = madt_rsdp_search(ptr, mapsz);
204         if (rsdp == NULL) {
205                 kprintf("madt_probe: no RSDP\n");
206                 pmap_unmapdev((vm_offset_t)ptr, mapsz);
207                 return 0;
208         } else {
209                 MADT_VPRINTF("RSDP in BIOS mem\n");
210         }
211
212 found_rsdp:
213         if (rsdp->rsdp_rev != 2) {
214                 search_paddr = rsdp->rsdp_rsdt;
215                 search = madt_search_rsdt;
216         } else {
217                 search_paddr = rsdp->rsdp_xsdt;
218                 search = madt_search_xsdt;
219         }
220         pmap_unmapdev((vm_offset_t)ptr, mapsz);
221
222         madt_paddr = search(search_paddr);
223         if (madt_paddr == 0) {
224                 kprintf("madt_probe: can't locate MADT\n");
225                 return 0;
226         }
227
228         /* Preliminary checks */
229         if (madt_check(madt_paddr))
230                 return 0;
231         return madt_paddr;
232 }
233
234 static const struct acpi_rsdp *
235 madt_rsdp_search(const uint8_t *target, int size)
236 {
237         const struct acpi_rsdp *rsdp;
238         int i;
239
240         KKASSERT(size > sizeof(*rsdp));
241
242         for (i = 0; i < size - sizeof(*rsdp); i += ACPI_RSDP_ALIGN) {
243                 rsdp = (const struct acpi_rsdp *)&target[i];
244                 if (memcmp(rsdp->rsdp_sig, ACPI_RSDP_SIG,
245                            ACPI_RSDP_SIGLEN) == 0)
246                         return rsdp;
247         }
248         return NULL;
249 }
250
251 static void *
252 madt_sdth_map(vm_paddr_t paddr)
253 {
254         struct acpi_sdth *sdth;
255         vm_size_t mapsz;
256
257         sdth = pmap_mapdev(paddr, sizeof(*sdth));
258         mapsz = sdth->sdth_len;
259         pmap_unmapdev((vm_offset_t)sdth, sizeof(*sdth));
260
261         if (mapsz < sizeof(*sdth))
262                 return NULL;
263
264         return pmap_mapdev(paddr, mapsz);
265 }
266
267 static void
268 madt_sdth_unmap(struct acpi_sdth *sdth)
269 {
270         pmap_unmapdev((vm_offset_t)sdth, sdth->sdth_len);
271 }
272
273 static vm_paddr_t
274 madt_search_xsdt(vm_paddr_t xsdt_paddr)
275 {
276         struct acpi_xsdt *xsdt;
277         vm_paddr_t madt_paddr = 0;
278         int i, nent;
279
280         if (xsdt_paddr == 0) {
281                 kprintf("madt_search_xsdt: XSDT paddr == 0\n");
282                 return 0;
283         }
284
285         xsdt = madt_sdth_map(xsdt_paddr);
286         if (xsdt == NULL) {
287                 kprintf("madt_search_xsdt: can't map XSDT\n");
288                 return 0;
289         }
290
291         if (memcmp(xsdt->xsdt_hdr.sdth_sig, ACPI_XSDT_SIG,
292                    ACPI_SDTH_SIGLEN) != 0) {
293                 kprintf("madt_search_xsdt: not XSDT\n");
294                 goto back;
295         }
296
297         if (xsdt->xsdt_hdr.sdth_rev != 1) {
298                 kprintf("madt_search_xsdt: unsupported XSDT revision %d\n",
299                         xsdt->xsdt_hdr.sdth_rev);
300                 goto back;
301         }
302
303         nent = (xsdt->xsdt_hdr.sdth_len - sizeof(xsdt->xsdt_hdr)) /
304                sizeof(xsdt->xsdt_ents[0]);
305         for (i = 0; i < nent; ++i) {
306                 struct acpi_sdth *sdth;
307
308                 if (xsdt->xsdt_ents[i] == 0)
309                         continue;
310
311                 sdth = madt_sdth_map(xsdt->xsdt_ents[i]);
312                 if (sdth != NULL) {
313                         int ret;
314
315                         ret = memcmp(sdth->sdth_sig, ACPI_MADT_SIG,
316                                      ACPI_SDTH_SIGLEN);
317                         madt_sdth_unmap(sdth);
318
319                         if (ret == 0) {
320                                 MADT_VPRINTF("MADT in XSDT\n");
321                                 madt_paddr = xsdt->xsdt_ents[i];
322                                 break;
323                         }
324                 }
325         }
326 back:
327         madt_sdth_unmap(&xsdt->xsdt_hdr);
328         return madt_paddr;
329 }
330
331 static vm_paddr_t
332 madt_search_rsdt(vm_paddr_t rsdt_paddr)
333 {
334         struct acpi_rsdt *rsdt;
335         vm_paddr_t madt_paddr = 0;
336         int i, nent;
337
338         if (rsdt_paddr == 0) {
339                 kprintf("madt_search_rsdt: RSDT paddr == 0\n");
340                 return 0;
341         }
342
343         rsdt = madt_sdth_map(rsdt_paddr);
344         if (rsdt == NULL) {
345                 kprintf("madt_search_rsdt: can't map RSDT\n");
346                 return 0;
347         }
348
349         if (memcmp(rsdt->rsdt_hdr.sdth_sig, ACPI_RSDT_SIG,
350                    ACPI_SDTH_SIGLEN) != 0) {
351                 kprintf("madt_search_rsdt: not RSDT\n");
352                 goto back;
353         }
354
355         if (rsdt->rsdt_hdr.sdth_rev != 1) {
356                 kprintf("madt_search_rsdt: unsupported RSDT revision %d\n",
357                         rsdt->rsdt_hdr.sdth_rev);
358                 goto back;
359         }
360
361         nent = (rsdt->rsdt_hdr.sdth_len - sizeof(rsdt->rsdt_hdr)) /
362                sizeof(rsdt->rsdt_ents[0]);
363         for (i = 0; i < nent; ++i) {
364                 struct acpi_sdth *sdth;
365
366                 if (rsdt->rsdt_ents[i] == 0)
367                         continue;
368
369                 sdth = madt_sdth_map(rsdt->rsdt_ents[i]);
370                 if (sdth != NULL) {
371                         int ret;
372
373                         ret = memcmp(sdth->sdth_sig, ACPI_MADT_SIG,
374                                      ACPI_SDTH_SIGLEN);
375                         madt_sdth_unmap(sdth);
376
377                         if (ret == 0) {
378                                 MADT_VPRINTF("MADT in RSDT\n");
379                                 madt_paddr = rsdt->rsdt_ents[i];
380                                 break;
381                         }
382                 }
383         }
384 back:
385         madt_sdth_unmap(&rsdt->rsdt_hdr);
386         return madt_paddr;
387 }
388
389 static int
390 madt_pass1_callback(void *xarg, const struct acpi_madt_ent *ent)
391 {
392         const struct acpi_madt_lapic_addr *lapic_addr_ent;
393         uint64_t *addr64 = xarg;
394
395         if (ent->me_type != MADT_ENT_LAPIC_ADDR)
396                 return 0;
397         if (ent->me_len < sizeof(*lapic_addr_ent)) {
398                 kprintf("madt_pass1: invalid LAPIC address override length\n");
399                 return 0;
400         }
401         lapic_addr_ent = (const struct acpi_madt_lapic_addr *)ent;
402
403         *addr64 = lapic_addr_ent->mla_lapic_addr;
404         return 0;
405 }
406
407 static vm_offset_t
408 madt_pass1(vm_paddr_t madt_paddr)
409 {
410         struct acpi_madt *madt;
411         vm_offset_t lapic_addr;
412         uint64_t lapic_addr64;
413         int error;
414
415         KKASSERT(madt_paddr != 0);
416
417         madt = madt_sdth_map(madt_paddr);
418         KKASSERT(madt != NULL);
419
420         MADT_VPRINTF("LAPIC address 0x%08x, flags %#x\n",
421                      madt->madt_lapic_addr, madt->madt_flags);
422         lapic_addr = madt->madt_lapic_addr;
423
424         lapic_addr64 = 0;
425         error = madt_iterate_entries(madt, madt_pass1_callback, &lapic_addr64);
426         if (error)
427                 panic("madt_iterate_entries(pass1) failed\n");
428
429         if (lapic_addr64 != 0) {
430                 kprintf("ACPI MADT: 64bits lapic address 0x%lx\n",
431                         lapic_addr64);
432                 lapic_addr = lapic_addr64;
433         }
434
435         madt_sdth_unmap(&madt->madt_hdr);
436
437         return lapic_addr;
438 }
439
440 struct madt_pass2_cbarg {
441         int     cpu;
442         int     bsp_found;
443         int     bsp_apic_id;
444 };
445
446 static int
447 madt_pass2_callback(void *xarg, const struct acpi_madt_ent *ent)
448 {
449         const struct acpi_madt_lapic *lapic_ent;
450         struct madt_pass2_cbarg *arg = xarg;
451
452         if (ent->me_type != MADT_ENT_LAPIC)
453                 return 0;
454
455         lapic_ent = (const struct acpi_madt_lapic *)ent;
456         if (lapic_ent->ml_flags & MADT_LAPIC_ENABLED) {
457                 MADT_VPRINTF("cpu_id %d, apic_id %d\n",
458                              lapic_ent->ml_cpu_id, lapic_ent->ml_apic_id);
459                 if (lapic_ent->ml_apic_id == arg->bsp_apic_id) {
460                         mp_set_cpuids(0, lapic_ent->ml_apic_id);
461                         arg->bsp_found = 1;
462                 } else {
463                         mp_set_cpuids(arg->cpu, lapic_ent->ml_apic_id);
464                         arg->cpu++;
465                 }
466         }
467         return 0;
468 }
469
470 static int
471 madt_pass2(vm_paddr_t madt_paddr, int bsp_apic_id)
472 {
473         struct acpi_madt *madt;
474         struct madt_pass2_cbarg arg;
475         int error;
476
477         MADT_VPRINTF("BSP apic id %d\n", bsp_apic_id);
478
479         KKASSERT(madt_paddr != 0);
480
481         madt = madt_sdth_map(madt_paddr);
482         KKASSERT(madt != NULL);
483
484         bzero(&arg, sizeof(arg));
485         arg.cpu = 1;
486         arg.bsp_apic_id = bsp_apic_id;
487
488         error = madt_iterate_entries(madt, madt_pass2_callback, &arg);
489         if (error)
490                 panic("madt_iterate_entries(pass2) failed\n");
491
492         KKASSERT(arg.bsp_found);
493         KKASSERT(arg.cpu > 1);
494         mp_naps = arg.cpu - 1; /* exclude BSP */
495
496         madt_sdth_unmap(&madt->madt_hdr);
497
498         return 0;
499 }
500
501 struct madt_check_cbarg {
502         int     cpu_count;
503 };
504
505 static int
506 madt_check_callback(void *xarg, const struct acpi_madt_ent *ent)
507 {
508         struct madt_check_cbarg *arg = xarg;
509         const struct acpi_madt_lapic *lapic_ent;
510
511         if (ent->me_type != MADT_ENT_LAPIC)
512                 return 0;
513         lapic_ent = (const struct acpi_madt_lapic *)ent;
514
515         if (lapic_ent->ml_flags & MADT_LAPIC_ENABLED)
516                 arg->cpu_count++;
517         return 0;
518 }
519
520 static int
521 madt_check(vm_paddr_t madt_paddr)
522 {
523         struct madt_check_cbarg arg;
524         struct acpi_madt *madt;
525         int error = 0;
526
527         KKASSERT(madt_paddr != 0);
528
529         madt = madt_sdth_map(madt_paddr);
530         KKASSERT(madt != NULL);
531
532         if (madt->madt_hdr.sdth_rev != 1 && madt->madt_hdr.sdth_rev != 2) {
533                 kprintf("madt_check: unsupported MADT revision %d\n",
534                         madt->madt_hdr.sdth_rev);
535                 error = EOPNOTSUPP;
536                 goto back;
537         }
538
539         if (madt->madt_hdr.sdth_len <
540             sizeof(*madt) - sizeof(madt->madt_ents)) {
541                 kprintf("madt_check: invalid MADT length %u\n",
542                         madt->madt_hdr.sdth_len);
543                 error = EINVAL;
544                 goto back;
545         }
546
547         bzero(&arg, sizeof(arg));
548
549         error = madt_iterate_entries(madt, madt_check_callback, &arg);
550         if (!error) {
551                 if (arg.cpu_count <= 1) {
552                         kprintf("madt_check: less than 2 CPUs is found\n");
553                         error = EOPNOTSUPP;
554                 }
555         }
556 back:
557         madt_sdth_unmap(&madt->madt_hdr);
558         return error;
559 }
560
561 static int
562 madt_iterate_entries(struct acpi_madt *madt, madt_iter_t func, void *arg)
563 {
564         int size, cur, error;
565
566         size = madt->madt_hdr.sdth_len -
567                (sizeof(*madt) - sizeof(madt->madt_ents));
568         cur = 0;
569         error = 0;
570
571         while (size - cur > sizeof(struct acpi_madt_ent)) {
572                 const struct acpi_madt_ent *ent;
573
574                 ent = (const struct acpi_madt_ent *)&madt->madt_ents[cur];
575                 if (ent->me_len < sizeof(*ent)) {
576                         kprintf("madt_iterate_entries: invalid MADT "
577                                 "entry len %d\n", ent->me_len);
578                         error = EINVAL;
579                         break;
580                 }
581                 if (ent->me_len > (size - cur)) {
582                         kprintf("madt_iterate_entries: invalid MADT "
583                                 "entry len %d, > table length\n", ent->me_len);
584                         error = EINVAL;
585                         break;
586                 }
587
588                 cur += ent->me_len;
589
590                 /*
591                  * Only Local APIC and I/O APIC are defined in
592                  * ACPI specification 1.0 - 3.0
593                  */
594                 switch (ent->me_type) {
595                 case MADT_ENT_LAPIC:
596                         if (ent->me_len < sizeof(struct acpi_madt_lapic)) {
597                                 kprintf("madt_iterate_entries: invalid MADT "
598                                         "lapic entry len %d\n", ent->me_len);
599                                 error = EINVAL;
600                         }
601                         break;
602
603                 case MADT_ENT_IOAPIC:
604                         if (ent->me_len < sizeof(struct acpi_madt_ioapic)) {
605                                 kprintf("madt_iterate_entries: invalid MADT "
606                                         "ioapic entry len %d\n", ent->me_len);
607                                 error = EINVAL;
608                         }
609                         break;
610                 }
611                 if (error)
612                         break;
613
614                 error = func(arg, ent);
615                 if (error)
616                         break;
617         }
618         return error;
619 }
620
621 static int
622 madt_lapic_probe(struct lapic_enumerator *e)
623 {
624         vm_paddr_t madt_paddr;
625
626         madt_paddr = madt_probe();
627         if (madt_paddr == 0)
628                 return ENXIO;
629
630         ((struct madt_lapic_enumerator *)e)->madt_paddr = madt_paddr;
631         return 0;
632 }
633
634 static void
635 madt_lapic_enumerate(struct lapic_enumerator *e)
636 {
637         vm_paddr_t madt_paddr;
638         vm_offset_t lapic_addr;
639         int bsp_apic_id;
640
641         madt_paddr = ((struct madt_lapic_enumerator *)e)->madt_paddr;
642         KKASSERT(madt_paddr != 0);
643
644         lapic_addr = madt_pass1(madt_paddr);
645         if (lapic_addr == 0)
646                 panic("madt_lapic_enumerate no local apic\n");
647
648         lapic_init(lapic_addr);
649
650         bsp_apic_id = APIC_ID(lapic->id);
651         if (madt_pass2(madt_paddr, bsp_apic_id))
652                 panic("mp_enable: madt_pass2 failed\n");
653 }
654
655 static struct madt_lapic_enumerator     madt_lapic_enumerator = {
656         .enumerator = {
657                 .lapic_prio = LAPIC_ENUM_PRIO_MADT,
658                 .lapic_probe = madt_lapic_probe,
659                 .lapic_enumerate = madt_lapic_enumerate
660         }
661 };
662
663 static void
664 madt_apic_register(void)
665 {
666         int prio;
667
668         prio = LAPIC_ENUM_PRIO_MADT;
669         kgetenv_int("hw.madt_lapic_prio", &prio);
670         madt_lapic_enumerator.enumerator.lapic_prio = prio;
671
672         lapic_enumerator_register(&madt_lapic_enumerator.enumerator);
673 }
674 SYSINIT(madt, SI_BOOT2_PRESMP, SI_ORDER_ANY, madt_apic_register, 0);
675
676