coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
ioapic.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <device/mmio.h>
5 #include <arch/ioapic.h>
6 #include <console/console.h>
7 #include <cpu/x86/lapic.h>
8 
9 u32 io_apic_read(void *ioapic_base, u32 reg)
10 {
11  write32(ioapic_base, reg);
12  return read32(ioapic_base + 0x10);
13 }
14 
15 void io_apic_write(void *ioapic_base, u32 reg, u32 value)
16 {
17  write32(ioapic_base, reg);
18  write32(ioapic_base + 0x10, value);
19 }
20 
21 static void write_vector(void *ioapic_base, u8 vector, u32 high, u32 low)
22 {
23  io_apic_write(ioapic_base, vector * 2 + 0x10, low);
24  io_apic_write(ioapic_base, vector * 2 + 0x11, high);
25 
26  printk(BIOS_SPEW, "IOAPIC: vector 0x%02x value 0x%08x 0x%08x\n",
27  vector, high, low);
28 }
29 
30 /* Bits 23-16 of register 0x01 specify the maximum redirection entry, which
31  * is the number of interrupts minus 1. */
32 unsigned int ioapic_get_max_vectors(void *ioapic_base)
33 {
34  u32 reg;
35  u8 count;
36 
37  reg = io_apic_read(ioapic_base, 0x01);
38  count = (reg >> 16) & 0xff;
39 
40  if (count == 0xff)
41  count = 23;
42  count++;
43 
44  printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", count);
45  return count;
46 }
47 
48 /* Set maximum number of redirection entries (MRE). It is write-once register
49  * for some chipsets, and a negative mre_count will lock it to the number
50  * of vectors read from the register. */
51 void ioapic_set_max_vectors(void *ioapic_base, int mre_count)
52 {
53  u32 reg;
54  u8 count;
55 
56  reg = io_apic_read(ioapic_base, 0x01);
57  count = (reg >> 16) & 0xff;
58  if (mre_count > 0)
59  count = mre_count - 1;
60  reg &= ~(0xff << 16);
61  reg |= count << 16;
62  io_apic_write(ioapic_base, 0x01, reg);
63 }
64 
65 void ioapic_lock_max_vectors(void *ioapic_base)
66 {
67  ioapic_set_max_vectors(ioapic_base, -1);
68 }
69 
70 static void clear_vectors(void *ioapic_base, u8 first, u8 last)
71 {
72  u32 low, high;
73  u8 i;
74 
75  printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base);
76 
77  low = INT_DISABLED;
78  high = NONE;
79 
80  for (i = first; i <= last; i++)
81  write_vector(ioapic_base, i, high, low);
82 
83  if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
84  printk(BIOS_WARNING, "IOAPIC not responding.\n");
85  return;
86  }
87 }
88 
89 static void route_i8259_irq0(void *ioapic_base)
90 {
91  u32 bsp_lapicid = lapicid();
92  u32 low, high;
93 
94  ASSERT(bsp_lapicid < 255);
95 
96  printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
97  bsp_lapicid);
98 
99  /* Enable Virtual Wire Mode. Should this be LOGICAL_DEST instead? */
101  high = bsp_lapicid << (56 - 32);
102 
103  write_vector(ioapic_base, 0, high, low);
104 
105  if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
106  printk(BIOS_WARNING, "IOAPIC not responding.\n");
107  return;
108  }
109 }
110 
111 void set_ioapic_id(void *ioapic_base, u8 ioapic_id)
112 {
113  int i;
114 
115  printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at %p\n",
116  ioapic_base);
117 
118  if (ioapic_id) {
119  printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
120  /* Set IOAPIC ID if it has been specified. */
121  io_apic_write(ioapic_base, 0x00,
122  (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
123  (ioapic_id << 24));
124  }
125 
126  printk(BIOS_SPEW, "IOAPIC: Dumping registers\n");
127  for (i = 0; i < 3; i++)
128  printk(BIOS_SPEW, " reg 0x%04x: 0x%08x\n", i,
129  io_apic_read(ioapic_base, i));
130 
131 }
132 
133 u8 get_ioapic_id(void *ioapic_base)
134 {
135  return (io_apic_read(ioapic_base, 0x00) >> 24) & 0x0f;
136 }
137 
138 u8 get_ioapic_version(void *ioapic_base)
139 {
140  return io_apic_read(ioapic_base, 0x01) & 0xff;
141 }
142 
143 void ioapic_set_boot_config(void *ioapic_base, bool irq_on_fsb)
144 {
145  if (irq_on_fsb) {
146  /*
147  * For the Pentium 4 and above APICs deliver their interrupts
148  * on the front side bus, enable that.
149  */
150  printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
151  io_apic_write(ioapic_base, 0x03,
152  io_apic_read(ioapic_base, 0x03) | (1 << 0));
153  } else {
155  "IOAPIC: Enabling interrupts on APIC serial bus\n");
156  io_apic_write(ioapic_base, 0x03, 0);
157  }
158 }
159 
160 void setup_ioapic(void *ioapic_base, u8 ioapic_id)
161 {
162  set_ioapic_id(ioapic_base, ioapic_id);
163  clear_vectors(ioapic_base, 0, ioapic_get_max_vectors(ioapic_base) - 1);
164  route_i8259_irq0(ioapic_base);
165 }
pte_t value
Definition: mmu.c:91
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
#define ExtINT
Definition: ioapic.h:24
#define INT_ENABLED
Definition: ioapic.h:17
#define INT_DISABLED
Definition: ioapic.h:16
#define PHYSICAL_DEST
Definition: ioapic.h:22
#define POLARITY_HIGH
Definition: ioapic.h:20
#define TRIGGER_EDGE
Definition: ioapic.h:18
u8 get_ioapic_id(void *ioapic_base)
Definition: ioapic.c:133
static void route_i8259_irq0(void *ioapic_base)
Definition: ioapic.c:89
u32 io_apic_read(void *ioapic_base, u32 reg)
Definition: ioapic.c:9
unsigned int ioapic_get_max_vectors(void *ioapic_base)
Definition: ioapic.c:32
void io_apic_write(void *ioapic_base, u32 reg, u32 value)
Definition: ioapic.c:15
void ioapic_set_boot_config(void *ioapic_base, bool irq_on_fsb)
Definition: ioapic.c:143
void setup_ioapic(void *ioapic_base, u8 ioapic_id)
Definition: ioapic.c:160
u8 get_ioapic_version(void *ioapic_base)
Definition: ioapic.c:138
void ioapic_lock_max_vectors(void *ioapic_base)
Definition: ioapic.c:65
void ioapic_set_max_vectors(void *ioapic_base, int mre_count)
Definition: ioapic.c:51
static void write_vector(void *ioapic_base, u8 vector, u32 high, u32 low)
Definition: ioapic.c:21
static void clear_vectors(void *ioapic_base, u8 first, u8 last)
Definition: ioapic.c:70
void set_ioapic_id(void *ioapic_base, u8 ioapic_id)
Definition: ioapic.c:111
#define ASSERT(x)
Definition: assert.h:44
#define printk(level,...)
Definition: stdlib.h:16
static __always_inline unsigned int lapicid(void)
Definition: lapic.h:136
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
uint32_t u32
Definition: stdint.h:51
uint8_t u8
Definition: stdint.h:45
#define count