source: mainline/kernel/arch/ia32/src/smp/apic.c@ acc7ce4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since acc7ce4 was acc7ce4, checked in by Martin Decky <martin@…>, 15 years ago

uspace interrupt controller drivers for i8259 and APIC (non-functional yet)
convert NE2000 driver to use these drivers (not enabling the IRQ in kernel), this solves the "spurious interrupt" issue
(however, on SMP machines this renders the driver unusable for now since the APIC driver does not do anything yet)

  • Property mode set to 100644
File size: 14.5 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2004 Jakub Jermar
[f761f1eb]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
[84afc7b]29/** @addtogroup ia32
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[d99c1d2]35#include <typedefs.h>
[397c77f]36#include <arch/smp/apic.h>
37#include <arch/smp/ap.h>
[ed0dd65]38#include <arch/smp/mps.h>
[66def8d]39#include <arch/boot/boot.h>
[f761f1eb]40#include <mm/page.h>
41#include <time/delay.h>
[fcfac420]42#include <interrupt.h>
[f761f1eb]43#include <arch/interrupt.h>
44#include <print.h>
45#include <arch/asm.h>
46#include <arch.h>
[3e35fd7]47#include <ddi/irq.h>
48#include <ddi/device.h>
[f761f1eb]49
[5f85c91]50#ifdef CONFIG_SMP
[8262010]51
[f761f1eb]52/*
[a83a802]53 * Advanced Programmable Interrupt Controller for SMP systems.
[f761f1eb]54 * Tested on:
[da1bafb]55 * Bochs 2.0.2 - Bochs 2.2.6 with 2-8 CPUs
56 * Simics 2.0.28 - Simics 2.2.19 2-15 CPUs
57 * VMware Workstation 5.5 with 2 CPUs
58 * QEMU 0.8.0 with 2-15 CPUs
59 * ASUS P/I-P65UP5 + ASUS C-P55T2D REV. 1.41 with 2x 200Mhz Pentium CPUs
60 * ASUS PCH-DL with 2x 3000Mhz Pentium 4 Xeon (HT) CPUs
61 * MSI K7D Master-L with 2x 2100MHz Athlon MP CPUs
62 *
[f761f1eb]63 */
64
65/*
66 * These variables either stay configured as initilalized, or are changed by
67 * the MP configuration code.
68 *
69 * Pay special attention to the volatile keyword. Without it, gcc -O2 would
70 * optimize the code too much and accesses to l_apic and io_apic, that must
71 * always be 32-bit, would use byte oriented instructions.
[da1bafb]72 *
[f761f1eb]73 */
[dc0b964]74volatile uint32_t *l_apic = (uint32_t *) UINT32_C(0xfee00000);
75volatile uint32_t *io_apic = (uint32_t *) UINT32_C(0xfec00000);
[f761f1eb]76
[7f1c620]77uint32_t apic_id_mask = 0;
[99718a2e]78uint8_t bsp_l_apic = 0;
79
[3e35fd7]80static irq_t l_apic_timer_irq;
[f761f1eb]81
[f701b236]82static int apic_poll_errors(void);
83
[9149135]84#ifdef LAPIC_VERBOSE
[da1bafb]85static const char *delmod_str[] = {
[f701b236]86 "Fixed",
87 "Lowest Priority",
88 "SMI",
89 "Reserved",
90 "NMI",
91 "INIT",
92 "STARTUP",
93 "ExtInt"
94};
95
[da1bafb]96static const char *destmod_str[] = {
[f701b236]97 "Physical",
98 "Logical"
99};
100
[da1bafb]101static const char *trigmod_str[] = {
[f701b236]102 "Edge",
103 "Level"
104};
105
[da1bafb]106static const char *mask_str[] = {
[f701b236]107 "Unmasked",
108 "Masked"
109};
110
[da1bafb]111static const char *delivs_str[] = {
[f701b236]112 "Idle",
113 "Send Pending"
114};
115
[da1bafb]116static const char *tm_mode_str[] = {
[f701b236]117 "One-shot",
118 "Periodic"
119};
120
[da1bafb]121static const char *intpol_str[] = {
[f701b236]122 "Polarity High",
123 "Polarity Low"
124};
[9149135]125#endif /* LAPIC_VERBOSE */
[f761f1eb]126
[3e35fd7]127/** APIC spurious interrupt handler.
128 *
[da1bafb]129 * @param n Interrupt vector.
[3e35fd7]130 * @param istate Interrupted state.
[da1bafb]131 *
[3e35fd7]132 */
[214ec25c]133static void apic_spurious(unsigned int n __attribute__((unused)),
[da1bafb]134 istate_t *istate __attribute__((unused)))
[3e35fd7]135{
136#ifdef CONFIG_DEBUG
[7f043c0]137 printf("cpu%u: APIC spurious interrupt\n", CPU->id);
[3e35fd7]138#endif
139}
[fcfac420]140
[c9b550b]141static irq_ownership_t l_apic_timer_claim(irq_t *irq)
[3e35fd7]142{
143 return IRQ_ACCEPT;
144}
145
[6cd9aa6]146static void l_apic_timer_irq_handler(irq_t *irq)
[3e35fd7]147{
[7e58979]148 /*
149 * Holding a spinlock could prevent clock() from preempting
150 * the current thread. In this case, we don't need to hold the
151 * irq->lock so we just unlock it and then lock it again.
152 */
[da1bafb]153 irq_spinlock_unlock(&irq->lock, false);
[3e35fd7]154 clock();
[da1bafb]155 irq_spinlock_lock(&irq->lock, false);
[3e35fd7]156}
[fcfac420]157
[99718a2e]158/** Get Local APIC ID.
159 *
160 * @return Local APIC ID.
161 *
162 */
163static uint8_t l_apic_id(void)
164{
165 l_apic_id_t idreg;
166
167 idreg.value = l_apic[L_APIC_ID];
168 return idreg.apic_id;
169}
170
[8418c7d]171/** Initialize APIC on BSP. */
[f761f1eb]172void apic_init(void)
173{
[b3b7e14a]174 exc_register(VECTOR_APIC_SPUR, "apic_spurious", false,
175 (iroutine_t) apic_spurious);
[da1bafb]176
[f761f1eb]177 enable_irqs_function = io_apic_enable_irqs;
178 disable_irqs_function = io_apic_disable_irqs;
179 eoi_function = l_apic_eoi;
[acc7ce4]180 irqs_info = "apic";
[f761f1eb]181
182 /*
183 * Configure interrupt routing.
184 * IRQ 0 remains masked as the time signal is generated by l_apic's themselves.
185 * Other interrupts will be forwarded to the lowest priority CPU.
186 */
[dc0b964]187 io_apic_disable_irqs(0xffffU);
[3e35fd7]188
189 irq_initialize(&l_apic_timer_irq);
[7bcfbbc]190 l_apic_timer_irq.preack = true;
[3e35fd7]191 l_apic_timer_irq.devno = device_assign_devno();
192 l_apic_timer_irq.inr = IRQ_CLK;
193 l_apic_timer_irq.claim = l_apic_timer_claim;
194 l_apic_timer_irq.handler = l_apic_timer_irq_handler;
195 irq_register(&l_apic_timer_irq);
196
[7f043c0]197 uint8_t i;
[9149135]198 for (i = 0; i < IRQ_COUNT; i++) {
[f761f1eb]199 int pin;
[da1bafb]200
[3e35fd7]201 if ((pin = smp_irq_to_pin(i)) != -1)
[7f043c0]202 io_apic_change_ioredtbl((uint8_t) pin, DEST_ALL, (uint8_t) (IVT_IRQBASE + i), LOPRI);
[f761f1eb]203 }
204
205 /*
206 * Ensure that io_apic has unique ID.
207 */
[da1bafb]208 io_apic_id_t idreg;
209
[9149135]210 idreg.value = io_apic_read(IOAPICID);
[da1bafb]211 if ((1 << idreg.apic_id) & apic_id_mask) { /* See if IO APIC ID is used already */
[9149135]212 for (i = 0; i < APIC_ID_COUNT; i++) {
[3e35fd7]213 if (!((1 << i) & apic_id_mask)) {
[9149135]214 idreg.apic_id = i;
215 io_apic_write(IOAPICID, idreg.value);
[f761f1eb]216 break;
217 }
218 }
219 }
[da1bafb]220
[f761f1eb]221 /*
222 * Configure the BSP's lapic.
223 */
224 l_apic_init();
[da1bafb]225 l_apic_debug();
[99718a2e]226
227 bsp_l_apic = l_apic_id();
[f761f1eb]228}
229
[f701b236]230/** Poll for APIC errors.
231 *
232 * Examine Error Status Register and report all errors found.
233 *
234 * @return 0 on error, 1 on success.
[da1bafb]235 *
[f701b236]236 */
[f761f1eb]237int apic_poll_errors(void)
238{
[f701b236]239 esr_t esr;
[f761f1eb]240
[f701b236]241 esr.value = l_apic[ESR];
[f761f1eb]242
[f701b236]243 if (esr.send_checksum_error)
[9149135]244 printf("Send Checksum Error\n");
[f701b236]245 if (esr.receive_checksum_error)
[9149135]246 printf("Receive Checksum Error\n");
[f701b236]247 if (esr.send_accept_error)
[f761f1eb]248 printf("Send Accept Error\n");
[f701b236]249 if (esr.receive_accept_error)
[f761f1eb]250 printf("Receive Accept Error\n");
[f701b236]251 if (esr.send_illegal_vector)
[f761f1eb]252 printf("Send Illegal Vector\n");
[f701b236]253 if (esr.received_illegal_vector)
[f761f1eb]254 printf("Received Illegal Vector\n");
[f701b236]255 if (esr.illegal_register_address)
[f761f1eb]256 printf("Illegal Register Address\n");
[da1bafb]257
[f701b236]258 return !esr.err_bitmap;
[f761f1eb]259}
260
[f701b236]261/** Send all CPUs excluding CPU IPI vector.
262 *
263 * @param vector Interrupt vector to be sent.
264 *
265 * @return 0 on failure, 1 on success.
[da1bafb]266 *
[169587a]267 */
[7f1c620]268int l_apic_broadcast_custom_ipi(uint8_t vector)
[169587a]269{
[8418c7d]270 icr_t icr;
[da1bafb]271
[8418c7d]272 icr.lo = l_apic[ICRlo];
273 icr.delmod = DELMOD_FIXED;
274 icr.destmod = DESTMOD_LOGIC;
275 icr.level = LEVEL_ASSERT;
276 icr.shorthand = SHORTHAND_ALL_EXCL;
277 icr.trigger_mode = TRIGMOD_LEVEL;
278 icr.vector = vector;
[da1bafb]279
[8418c7d]280 l_apic[ICRlo] = icr.lo;
[da1bafb]281
[8418c7d]282 icr.lo = l_apic[ICRlo];
[88636f68]283 if (icr.delivs == DELIVS_PENDING) {
284#ifdef CONFIG_DEBUG
[169587a]285 printf("IPI is pending.\n");
[88636f68]286#endif
287 }
[da1bafb]288
[169587a]289 return apic_poll_errors();
290}
291
[f701b236]292/** Universal Start-up Algorithm for bringing up the AP processors.
293 *
294 * @param apicid APIC ID of the processor to be brought up.
295 *
296 * @return 0 on failure, 1 on success.
[da1bafb]297 *
[f761f1eb]298 */
[7f1c620]299int l_apic_send_init_ipi(uint8_t apicid)
[f761f1eb]300{
301 /*
302 * Read the ICR register in and zero all non-reserved fields.
303 */
[da1bafb]304 icr_t icr;
305
[8418c7d]306 icr.lo = l_apic[ICRlo];
307 icr.hi = l_apic[ICRhi];
[f761f1eb]308
[8418c7d]309 icr.delmod = DELMOD_INIT;
310 icr.destmod = DESTMOD_PHYS;
311 icr.level = LEVEL_ASSERT;
312 icr.trigger_mode = TRIGMOD_LEVEL;
313 icr.shorthand = SHORTHAND_NONE;
314 icr.vector = 0;
315 icr.dest = apicid;
[f761f1eb]316
[8418c7d]317 l_apic[ICRhi] = icr.hi;
318 l_apic[ICRlo] = icr.lo;
[da1bafb]319
[f761f1eb]320 /*
321 * According to MP Specification, 20us should be enough to
322 * deliver the IPI.
323 */
324 delay(20);
[da1bafb]325
[88636f68]326 if (!apic_poll_errors())
327 return 0;
[da1bafb]328
[8418c7d]329 icr.lo = l_apic[ICRlo];
[88636f68]330 if (icr.delivs == DELIVS_PENDING) {
331#ifdef CONFIG_DEBUG
[f761f1eb]332 printf("IPI is pending.\n");
[88636f68]333#endif
334 }
[da1bafb]335
[8418c7d]336 icr.delmod = DELMOD_INIT;
337 icr.destmod = DESTMOD_PHYS;
338 icr.level = LEVEL_DEASSERT;
339 icr.shorthand = SHORTHAND_NONE;
340 icr.trigger_mode = TRIGMOD_LEVEL;
341 icr.vector = 0;
342 l_apic[ICRlo] = icr.lo;
[da1bafb]343
[f761f1eb]344 /*
345 * Wait 10ms as MP Specification specifies.
346 */
347 delay(10000);
[da1bafb]348
[c9b8c5c]349 if (!is_82489DX_apic(l_apic[LAVR])) {
350 /*
351 * If this is not 82489DX-based l_apic we must send two STARTUP IPI's.
352 */
[da1bafb]353 unsigned int i;
354 for (i = 0; i < 2; i++) {
[8418c7d]355 icr.lo = l_apic[ICRlo];
[7f043c0]356 icr.vector = (uint8_t) (((uintptr_t) ap_boot) >> 12); /* calculate the reset vector */
[8418c7d]357 icr.delmod = DELMOD_STARTUP;
358 icr.destmod = DESTMOD_PHYS;
359 icr.level = LEVEL_ASSERT;
360 icr.shorthand = SHORTHAND_NONE;
361 icr.trigger_mode = TRIGMOD_LEVEL;
362 l_apic[ICRlo] = icr.lo;
[c9b8c5c]363 delay(200);
364 }
[f761f1eb]365 }
366
367 return apic_poll_errors();
368}
369
[f701b236]370/** Initialize Local APIC. */
[f761f1eb]371void l_apic_init(void)
372{
[8418c7d]373 /* Initialize LVT Error register. */
[da1bafb]374 lvt_error_t error;
375
[8418c7d]376 error.value = l_apic[LVT_Err];
377 error.masked = true;
378 l_apic[LVT_Err] = error.value;
[da1bafb]379
[8418c7d]380 /* Initialize LVT LINT0 register. */
[da1bafb]381 lvt_lint_t lint;
382
[8418c7d]383 lint.value = l_apic[LVT_LINT0];
384 lint.masked = true;
385 l_apic[LVT_LINT0] = lint.value;
[da1bafb]386
[8418c7d]387 /* Initialize LVT LINT1 register. */
388 lint.value = l_apic[LVT_LINT1];
389 lint.masked = true;
390 l_apic[LVT_LINT1] = lint.value;
[da1bafb]391
[d0780b4c]392 /* Task Priority Register initialization. */
[da1bafb]393 tpr_t tpr;
394
[d0780b4c]395 tpr.value = l_apic[TPR];
396 tpr.pri_sc = 0;
397 tpr.pri = 0;
398 l_apic[TPR] = tpr.value;
[8418c7d]399
400 /* Spurious-Interrupt Vector Register initialization. */
[da1bafb]401 svr_t svr;
402
[8418c7d]403 svr.value = l_apic[SVR];
404 svr.vector = VECTOR_APIC_SPUR;
405 svr.lapic_enabled = true;
[d0780b4c]406 svr.focus_checking = true;
[8418c7d]407 l_apic[SVR] = svr.value;
[da1bafb]408
[434f700]409 if (CPU->arch.family >= 6)
410 enable_l_apic_in_msr();
[f761f1eb]411
[8418c7d]412 /* Interrupt Command Register initialization. */
[da1bafb]413 icr_t icr;
414
[8418c7d]415 icr.lo = l_apic[ICRlo];
416 icr.delmod = DELMOD_INIT;
417 icr.destmod = DESTMOD_PHYS;
418 icr.level = LEVEL_DEASSERT;
419 icr.shorthand = SHORTHAND_ALL_INCL;
420 icr.trigger_mode = TRIGMOD_LEVEL;
421 l_apic[ICRlo] = icr.lo;
[f761f1eb]422
[f701b236]423 /* Timer Divide Configuration Register initialization. */
[da1bafb]424 tdcr_t tdcr;
425
[f701b236]426 tdcr.value = l_apic[TDCR];
427 tdcr.div_value = DIVIDE_1;
428 l_apic[TDCR] = tdcr.value;
[da1bafb]429
[f701b236]430 /* Program local timer. */
[da1bafb]431 lvt_tm_t tm;
432
[8418c7d]433 tm.value = l_apic[LVT_Tm];
434 tm.vector = VECTOR_CLK;
435 tm.mode = TIMER_PERIODIC;
436 tm.masked = false;
437 l_apic[LVT_Tm] = tm.value;
[da1bafb]438
[e20de55]439 /*
440 * Measure and configure the timer to generate timer
441 * interrupt with period 1s/HZ seconds.
442 */
[da1bafb]443 uint32_t t1 = l_apic[CCRT];
[f761f1eb]444 l_apic[ICRT] = 0xffffffff;
[da1bafb]445
446 while (l_apic[CCRT] == t1);
447
[f761f1eb]448 t1 = l_apic[CCRT];
[da1bafb]449 delay(1000000 / HZ);
450 uint32_t t2 = l_apic[CCRT];
[f761f1eb]451
[da1bafb]452 l_apic[ICRT] = t1 - t2;
[93e90c7]453
454 /* Program Logical Destination Register. */
[5f0e39e8]455 ASSERT(CPU->id < 8);
[da1bafb]456 ldr_t ldr;
457
[93e90c7]458 ldr.value = l_apic[LDR];
[7f043c0]459 ldr.id = (uint8_t) (1 << CPU->id);
[93e90c7]460 l_apic[LDR] = ldr.value;
461
462 /* Program Destination Format Register for Flat mode. */
[da1bafb]463 dfr_t dfr;
464
[93e90c7]465 dfr.value = l_apic[DFR];
466 dfr.model = MODEL_FLAT;
467 l_apic[DFR] = dfr.value;
[f761f1eb]468}
469
[f701b236]470/** Local APIC End of Interrupt. */
[f761f1eb]471void l_apic_eoi(void)
472{
473 l_apic[EOI] = 0;
474}
475
[f701b236]476/** Dump content of Local APIC registers. */
[f761f1eb]477void l_apic_debug(void)
478{
479#ifdef LAPIC_VERBOSE
[7e752b2]480 printf("LVT on cpu%u, LAPIC ID: %" PRIu8 "\n",
[99718a2e]481 CPU->id, l_apic_id());
[f761f1eb]482
[da1bafb]483 lvt_tm_t tm;
[f701b236]484 tm.value = l_apic[LVT_Tm];
[99718a2e]485 printf("LVT Tm: vector=%" PRIu8 ", %s, %s, %s\n",
486 tm.vector, delivs_str[tm.delivs], mask_str[tm.masked],
487 tm_mode_str[tm.mode]);
[da1bafb]488
489 lvt_lint_t lint;
[f701b236]490 lint.value = l_apic[LVT_LINT0];
[99718a2e]491 printf("LVT LINT0: vector=%" PRIu8 ", %s, %s, %s, irr=%u, %s, %s\n",
492 tm.vector, delmod_str[lint.delmod], delivs_str[lint.delivs],
493 intpol_str[lint.intpol], lint.irr, trigmod_str[lint.trigger_mode],
494 mask_str[lint.masked]);
495
496 lint.value = l_apic[LVT_LINT1];
497 printf("LVT LINT1: vector=%" PRIu8 ", %s, %s, %s, irr=%u, %s, %s\n",
498 tm.vector, delmod_str[lint.delmod], delivs_str[lint.delivs],
499 intpol_str[lint.intpol], lint.irr, trigmod_str[lint.trigger_mode],
500 mask_str[lint.masked]);
[da1bafb]501
502 lvt_error_t error;
[f701b236]503 error.value = l_apic[LVT_Err];
[99718a2e]504 printf("LVT Err: vector=%" PRIu8 ", %s, %s\n", error.vector,
505 delivs_str[error.delivs], mask_str[error.masked]);
[f761f1eb]506#endif
507}
508
[f701b236]509/** Read from IO APIC register.
510 *
511 * @param address IO APIC register address.
512 *
513 * @return Content of the addressed IO APIC register.
[da1bafb]514 *
[f701b236]515 */
[7f1c620]516uint32_t io_apic_read(uint8_t address)
[f761f1eb]517{
[f701b236]518 io_regsel_t regsel;
[f761f1eb]519
[f701b236]520 regsel.value = io_apic[IOREGSEL];
521 regsel.reg_addr = address;
522 io_apic[IOREGSEL] = regsel.value;
[f761f1eb]523 return io_apic[IOWIN];
524}
525
[f701b236]526/** Write to IO APIC register.
527 *
528 * @param address IO APIC register address.
[da1bafb]529 * @param val Content to be written to the addressed IO APIC register.
530 *
[f701b236]531 */
[da1bafb]532void io_apic_write(uint8_t address, uint32_t val)
[f761f1eb]533{
[f701b236]534 io_regsel_t regsel;
535
536 regsel.value = io_apic[IOREGSEL];
537 regsel.reg_addr = address;
538 io_apic[IOREGSEL] = regsel.value;
[da1bafb]539 io_apic[IOWIN] = val;
[f761f1eb]540}
541
[f701b236]542/** Change some attributes of one item in I/O Redirection Table.
543 *
[da1bafb]544 * @param pin IO APIC pin number.
545 * @param dest Interrupt destination address.
546 * @param vec Interrupt vector to trigger.
[f701b236]547 * @param flags Flags.
[da1bafb]548 *
[f701b236]549 */
[da1bafb]550void io_apic_change_ioredtbl(uint8_t pin, uint8_t dest, uint8_t vec,
551 unsigned int flags)
[f761f1eb]552{
[da1bafb]553 unsigned int dlvr;
[f761f1eb]554
555 if (flags & LOPRI)
[a83a802]556 dlvr = DELMOD_LOWPRI;
[da1bafb]557 else
558 dlvr = DELMOD_FIXED;
559
560 io_redirection_reg_t reg;
[7f043c0]561 reg.lo = io_apic_read((uint8_t) (IOREDTBL + pin * 2));
562 reg.hi = io_apic_read((uint8_t) (IOREDTBL + pin * 2 + 1));
[f761f1eb]563
[93e90c7]564 reg.dest = dest;
[a83a802]565 reg.destmod = DESTMOD_LOGIC;
566 reg.trigger_mode = TRIGMOD_EDGE;
567 reg.intpol = POLARITY_HIGH;
568 reg.delmod = dlvr;
[da1bafb]569 reg.intvec = vec;
570
[7f043c0]571 io_apic_write((uint8_t) (IOREDTBL + pin * 2), reg.lo);
572 io_apic_write((uint8_t) (IOREDTBL + pin * 2 + 1), reg.hi);
[f761f1eb]573}
574
[f701b236]575/** Mask IRQs in IO APIC.
576 *
577 * @param irqmask Bitmask of IRQs to be masked (0 = do not mask, 1 = mask).
[da1bafb]578 *
[f701b236]579 */
[7f1c620]580void io_apic_disable_irqs(uint16_t irqmask)
[f761f1eb]581{
[623b49f1]582 unsigned int i;
583 for (i = 0; i < 16; i++) {
584 if (irqmask & (1 << i)) {
[f761f1eb]585 /*
586 * Mask the signal input in IO APIC if there is a
587 * mapping for the respective IRQ number.
588 */
[da1bafb]589 int pin = smp_irq_to_pin(i);
[f761f1eb]590 if (pin != -1) {
[da1bafb]591 io_redirection_reg_t reg;
592
[7f043c0]593 reg.lo = io_apic_read((uint8_t) (IOREDTBL + pin * 2));
[a83a802]594 reg.masked = true;
[7f043c0]595 io_apic_write((uint8_t) (IOREDTBL + pin * 2), reg.lo);
[f761f1eb]596 }
597
598 }
599 }
600}
601
[f701b236]602/** Unmask IRQs in IO APIC.
603 *
604 * @param irqmask Bitmask of IRQs to be unmasked (0 = do not unmask, 1 = unmask).
[da1bafb]605 *
[f701b236]606 */
[7f1c620]607void io_apic_enable_irqs(uint16_t irqmask)
[f761f1eb]608{
[623b49f1]609 unsigned int i;
[7f043c0]610 for (i = 0; i < 16; i++) {
[623b49f1]611 if (irqmask & (1 << i)) {
[f761f1eb]612 /*
613 * Unmask the signal input in IO APIC if there is a
614 * mapping for the respective IRQ number.
615 */
[da1bafb]616 int pin = smp_irq_to_pin(i);
[f761f1eb]617 if (pin != -1) {
[da1bafb]618 io_redirection_reg_t reg;
619
[7f043c0]620 reg.lo = io_apic_read((uint8_t) (IOREDTBL + pin * 2));
[a83a802]621 reg.masked = false;
[7f043c0]622 io_apic_write((uint8_t) (IOREDTBL + pin * 2), reg.lo);
[f761f1eb]623 }
624
625 }
626 }
627}
628
[5f85c91]629#endif /* CONFIG_SMP */
[b45c443]630
[06e1e95]631/** @}
[b45c443]632 */
Note: See TracBrowser for help on using the repository browser.