~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to kernel/arch/ia32/src/smp/apic.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

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