Skip to content

Commit

Permalink
ioapic: add irq overrides detection and handling
Browse files Browse the repository at this point in the history
Detect ACPI and MP tables provided IRQ and NMI overrides for IOAPIC
and LAPIC.  Store them on their bus's overrides list.  Add interface
functions to obtain ISA and PCI bus IRQ overrides.

Signed-off-by: Pawel Wieczorkiewicz <[email protected]>
  • Loading branch information
wipawel committed Oct 22, 2020
1 parent 173e815 commit 252be82
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 2 deletions.
56 changes: 56 additions & 0 deletions arch/x86/ioapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <console.h>
#include <errno.h>
#include <ioapic.h>
#include <ktf.h>
#include <list.h>
Expand Down Expand Up @@ -108,3 +109,58 @@ bus_t *add_system_bus(uint8_t id, const char *name, size_t namelen) {
bus = __add_system_bus(id, bus_name);
return bus;
}

int add_system_bus_irq_override(uint8_t bus_id, irq_override_t *override) {
irq_override_t *new_override;
bus_t *bus;

bus = get_system_bus_by_id(bus_id);
if (!bus)
return -ENODEV;

new_override = ktf_alloc(sizeof(*new_override));
if (!new_override)
return -ENOMEM;

memcpy(new_override, override, sizeof(*new_override));
list_add_tail(&new_override->list, &bus->irq_overrides);
return 0;
}

static irq_override_t *__get_irq_override(bus_t *bus, uint8_t irq_type,
uint32_t irq_src) {
irq_override_t *override;

if (!bus)
return NULL;

list_for_each_entry (override, &bus->irq_overrides, list) {
if (override->type == irq_type && override->src == irq_src)
return override;
}

return NULL;
}

irq_override_t *get_system_isa_bus_irq(uint8_t irq_type, uint32_t irq_src) {
bus_t *bus;

bus = get_system_bus_by_name(IOAPIC_SYSTEM_ISA_BUS_NAME,
strlen(IOAPIC_SYSTEM_ISA_BUS_NAME));
if (!bus)
return NULL;

return __get_irq_override(bus, irq_type, irq_src);
}

irq_override_t *get_system_pci_bus_irq(uint8_t irq_type, uint32_t irq_src) {
bus_t *bus;

bus = get_system_bus_by_name(IOAPIC_SYSTEM_PCI_BUS_NAME,
strlen(IOAPIC_SYSTEM_PCI_BUS_NAME));
if (!bus)
return NULL;

return __get_irq_override(bus, irq_type, irq_src);
}

29 changes: 29 additions & 0 deletions common/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,18 @@ static int process_madt_entries(void) {
}
case ACPI_MADT_TYPE_IRQ_SRC: {
acpi_madt_irq_src_t *madt_irq_src = (acpi_madt_irq_src_t *) entry->data;
irq_override_t override;

memset(&override, 0, sizeof(override));
override.type = ACPI_MADT_IRQ_TYPE_INT;
override.src = madt_irq_src->irq_src;
override.dst = madt_irq_src->gsi;
/* Destination to be found. Each IOAPIC has GSI base and Max Redir Entry
* register */
override.dst_id = IOAPIC_DEST_ID_UNKNOWN;
override.polarity = madt_irq_src->polarity;
override.trigger_mode = madt_irq_src->trigger_mode;
add_system_bus_irq_override(madt_irq_src->bus, &override);

printk("ACPI: [MADT] IRQ Src Override: Bus: %3s, IRQ: 0x%02x, GSI: 0x%08x, "
"Polarity: %11s, Trigger: %9s\n",
Expand All @@ -280,6 +292,14 @@ static int process_madt_entries(void) {
}
case ACPI_MADT_TYPE_NMI_SRC: {
acpi_madt_nmi_src_t *madt_nmi_src = (acpi_madt_nmi_src_t *) entry->data;
irq_override_t override;

memset(&override, 0, sizeof(override));
override.type = ACPI_MADT_IRQ_TYPE_NMI;
override.src = madt_nmi_src->gsi;
override.polarity = madt_nmi_src->polarity;
override.trigger_mode = madt_nmi_src->trigger_mode;
add_system_bus_irq_override(ACPI_MADT_INT_BUS_ISA, &override);

printk("ACPI: [MADT] NMI Src: GSI: 0x%08x, Polarity: %11s, Trigger: %9s\n",
madt_nmi_src->gsi, madt_int_polarity_names[madt_nmi_src->polarity],
Expand All @@ -288,6 +308,15 @@ static int process_madt_entries(void) {
}
case ACPI_MADT_TYPE_LAPIC_NMI: {
acpi_madt_lapic_nmi_t *madt_lapic_nmi = (acpi_madt_lapic_nmi_t *) entry->data;
irq_override_t override;

memset(&override, 0, sizeof(override));
override.type = ACPI_MADT_IRQ_TYPE_NMI;
override.dst_id = madt_lapic_nmi->cpu_uid;
override.dst = madt_lapic_nmi->lapic_lint;
override.polarity = madt_lapic_nmi->polarity;
override.trigger_mode = madt_lapic_nmi->trigger_mode;
add_system_bus_irq_override(ACPI_MADT_INT_BUS_ISA, &override);

printk("ACPI: [MADT] Local APIC NMI LINT#: CPU UID: %02x, Polarity: %11s, "
"Trigger: %9s, LINT#: 0x%02x\n",
Expand Down
2 changes: 0 additions & 2 deletions include/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,6 @@ typedef struct acpi_madt_iosapic acpi_madt_iosapic_t;
#define ACPI_MADT_IRQ_TYPE_INT 0
#define ACPI_MADT_IRQ_TYPE_NMI 1

#define ACPI_MADT_IRQ_DST_UNKNOWN 0xFF

#define ACPI_MADT_INT_POLARITY_BS 0x00
#define ACPI_MADT_INT_POLARITY_AH 0x01
#define ACPI_MADT_INT_POLARITY_RSVD 0x02
Expand Down
80 changes: 80 additions & 0 deletions include/arch/x86/ioapic.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,37 @@
#include <lib.h>
#include <list.h>

#define IOAPIC_DEST_ID_UNKNOWN ((uint8_t) 0xFF)

#ifndef __ASSEMBLY__

enum irq_override_polarity {
IOAPIC_IRQ_OVR_POLARITY_BS = 0x00,
IOAPIC_IRQ_OVR_POLARITY_AH = 0x01,
IOAPIC_IRQ_OVR_POLARITY_RSVD = 0x02,
IOAPIC_IRQ_OVR_POLARITY_AL = 0x03,
};
typedef enum irq_override_polarity irq_override_polarity_t;

enum irq_override_trigger_mode {
IOAPIC_IRQ_OVR_TRIGGER_BS = 0x00,
IOAPIC_IRQ_OVR_TRIGGER_ET = 0x01,
IOAPIC_IRQ_OVR_TRIGGER_RSVD = 0x02,
IOAPIC_IRQ_OVR_TRIGGER_LT = 0x03,
};
typedef enum irq_override_trigger_mode irq_override_trigger_mode_t;

struct irq_override {
list_head_t list;
uint8_t type;
uint32_t src;
uint32_t dst;
uint8_t dst_id; /* IOAPIC or LAPIC */
irq_override_polarity_t polarity;
irq_override_trigger_mode_t trigger_mode;
};
typedef struct irq_override irq_override_t;

struct bus {
list_head_t list;
uint8_t id;
Expand All @@ -39,9 +68,60 @@ struct bus {
};
typedef struct bus bus_t;

enum ioapic_irq_type {
IOAPIC_IRQ_TYPE_INT = 0x00,
IOAPIC_IRQ_TYPE_NMI = 0x01,
IOAPIC_IRQ_TYPE_SMI = 0x10,
IOAPIC_IRQ_TYPE_EXTINT = 0x11,
};
typedef enum ioapic_irq_type ioapic_irq_type_t;

enum ioapic_delivery_mode {
IOAPIC_DELIVERY_MODE_FIXED = 0x00,
IOAPIC_DELIVERY_MODE_LOWPRIO = 0x01,
IOAPIC_DELIVERY_MODE_SMI = 0x02,
IOAPIC_DELIVERY_MODE_NMI = 0x04,
IOAPIC_DELIVERY_MODE_INIT = 0x05,
IOAPIC_DELIVERY_MODE_EXTINT = 0x07,
};
typedef enum ioapic_deliver_mode ioapic_delivery_mode_t;

enum ioapic_dest_mode {
IOAPIC_DEST_MODE_PHYSICAL = 0x00,
IOAPIC_DEST_MODE_LOGICAL = 0x01,
};
typedef enum ioapic_dest_mode ioapic_dest_mode_t;

enum ioapic_delivery_status {
IOAPIC_DELIVERY_STATUS_IDLE = 0x00,
IOAPIC_DELIVERY_STATUS_PENDING = 0x01,
};
typedef enum ioapic_delivery_status ioapic_delivery_status_t;

enum ioapic_trigger_mode {
IOAPIC_TRIGGER_MODE_EDGE = 0x00,
IOAPIC_TRIGGER_MODE_LEVEL = 0x01,
};
typedef enum ioapic_trigger_mode ioapic_trigger_mode_t;

enum ioapic_polarity {
IOAPIC_POLARITY_AH = 0x00,
IOAPIC_POLARITY_AL = 0x01,
};
typedef enum ioapic_polarity ioapic_polarity_t;

enum ioapic_int_mask {
IOAPIC_INT_UNMASK = 0x00,
IOAPIC_INT_MASK = 0x01,
};
typedef enum ioapic_int_mask ioapic_int_mask_t;

/* External declarations */

extern bus_t *add_system_bus(uint8_t id, const char *name, size_t namelen);
extern int add_system_bus_irq_override(uint8_t bus_id, irq_override_t *irq_override);
extern irq_override_t *get_system_isa_bus_irq(uint8_t irq_type, uint32_t irq_src);
extern irq_override_t *get_system_pci_bus_irq(uint8_t irq_type, uint32_t irq_src);

#endif /* __ASSEMBLY__ */

Expand Down
20 changes: 20 additions & 0 deletions smp/mptables.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,33 @@ static void process_mpc_entries(mpc_hdr_t *mpc_ptr) {
}
case MPC_IO_INT_ENTRY: {
mpc_ioint_entry_t *mpc_ioint = (mpc_ioint_entry_t *) entry_ptr;
irq_override_t override;

memset(&override, 0, sizeof(override));
override.type = mpc_ioint->int_type;
override.src = mpc_ioint->src_bus_irq;
override.dst_id = mpc_ioint->dst_ioapic_id;
override.dst = mpc_ioint->dst_ioapic_intin;
override.polarity = mpc_ioint->po;
override.trigger_mode = mpc_ioint->el;
add_system_bus_irq_override(mpc_ioint->src_bus_id, &override);

dump_mpc_ioint_entry(mpc_ioint);
entry_ptr += sizeof(*mpc_ioint);
break;
}
case MPC_LOCAL_INT_ENTRY: {
mpc_lint_entry_t *mpc_lint = (mpc_lint_entry_t *) entry_ptr;
irq_override_t override;

memset(&override, 0, sizeof(override));
override.type = mpc_lint->int_type;
override.src = mpc_lint->src_bus_irq;
override.dst_id = mpc_lint->dst_lapic_id;
override.dst = mpc_lint->dst_lapic_lintin;
override.polarity = mpc_lint->po;
override.trigger_mode = mpc_lint->el;
add_system_bus_irq_override(mpc_lint->src_bus_id, &override);

dump_mpc_lint_entry(mpc_lint);
entry_ptr += sizeof(*mpc_lint);
Expand Down

0 comments on commit 252be82

Please sign in to comment.