1/**
2 * \file
3 * \brief I/O APIC driver.
4 *
5 * Barrelfish only supports edge triggered interrupts.
6 */
7
8/*
9 * Copyright (c) 2007, 2008, 2009, ETH Zurich.
10 * All rights reserved.
11 *
12 * This file is distributed under the terms in the attached LICENSE file.
13 * If you do not find this file, copies can be found by writing to:
14 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
15 */
16
17#include <stdio.h>
18#include <barrelfish/barrelfish.h>
19#include <mm/mm.h>
20
21#include "ioapic.h"
22
23#include "acpi_debug.h"
24
25/**
26 * \brief Initialize I/O APIC.
27 *
28 * Initializes the I/O APIC pointed to by 'a', with virtual base
29 * address 'base', ID 'id' and INTI base 'irqbase'. All interrupts are
30 * masked initially and have to be unmasked individually upon use.
31 *
32 * \param a             Pointer to I/O APIC structure.
33 * \param base          Virtual base address for I/O APIC registers.
34 * \param id            ID of I/O APIC (from ACPI).
35 * \param irqbase       INTI base (from ACPI).
36 *
37 * \return 0 on success.
38 */
39errval_t ioapic_init(struct ioapic *a, lvaddr_t base, uint8_t id,
40                     uint32_t irqbase)
41{
42    lpc_ioapic_initialize(&a->dev, (void *)base);
43
44    a->irqbase = irqbase;
45    a->initialized = 1;
46
47    // Write I/O APIC ID
48    lpc_ioapic_id_wr(&a->dev, (lpc_ioapic_id_t) { .id = id });
49
50    // Check number of supported IRQs
51    a->nintis = lpc_ioapic_ver_rd(&a->dev).mre + 1;
52    if (a->nintis == 1) {
53        ACPI_DEBUG("Warning: I/O APIC claims only to support a single interrupt!"
54                  " This is probably going to break...\n");
55    } else {
56        ACPI_DEBUG("I/O APIC supports %d interrupts\n", a->nintis);
57    }
58
59    // Mask out all interrupts
60    for(int i = 0; i < a->nintis; i++) {
61        ioapic_toggle_inti(a, i, false);
62    }
63
64    return SYS_ERR_OK;
65}
66
67void ioapic_toggle_inti(struct ioapic *a, int inti, bool enable)
68{
69    assert(inti >= 0 && inti < a->nintis);
70    lpc_ioapic_redir_tbl_t tbl = lpc_ioapic_redirtbl_rd(&a->dev, inti);
71    tbl.mask = enable ? 0 : 1;
72    lpc_ioapic_redirtbl_wr(&a->dev, inti, tbl);
73}
74
75void ioapic_setup_inti(struct ioapic *a, int inti, lpc_ioapic_redir_tbl_t entry)
76{
77    assert(inti >= 0 && inti < a->nintis);
78    lpc_ioapic_redirtbl_wr(&a->dev, inti, entry);
79}
80
81void ioapic_route_inti(struct ioapic *a, int inti, uint8_t vector, uint8_t dest)
82{
83    assert(inti >= 0 && inti < a->nintis);
84    lpc_ioapic_redir_tbl_t tbl = lpc_ioapic_redirtbl_rd(&a->dev, inti);
85    tbl.vector = vector;
86    tbl.dest = dest;
87    lpc_ioapic_redirtbl_wr(&a->dev, inti, tbl);
88}
89