blob: c148534351ef57cb52ffd9e4bf05ad44867624c6 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Eric Biederman5899fd82003-04-24 06:25:08 +00002
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +03003#include <assert.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02004#include <device/mmio.h>
Stefan Reinauer0401bd82010-01-16 18:31:34 +00005#include <arch/ioapic.h>
6#include <console/console.h>
7#include <cpu/x86/lapic.h>
8
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08009u32 io_apic_read(void *ioapic_base, u32 reg)
Eric Biederman5899fd82003-04-24 06:25:08 +000010{
Stefan Reinauer0401bd82010-01-16 18:31:34 +000011 write32(ioapic_base, reg);
12 return read32(ioapic_base + 0x10);
13}
Eric Biederman5899fd82003-04-24 06:25:08 +000014
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080015void io_apic_write(void *ioapic_base, u32 reg, u32 value)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000016{
17 write32(ioapic_base, reg);
18 write32(ioapic_base + 0x10, value);
19}
20
Kyösti Mälkki93c1eef2021-06-03 23:14:05 +030021static 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
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080030static int ioapic_interrupt_count(void *ioapic_base)
Patrick Georgid1de45e2013-01-23 13:45:23 +010031{
32 /* Read the available number of interrupts. */
33 int ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030034 if (!ioapic_interrupts || ioapic_interrupts == 0xff)
Patrick Georgid1de45e2013-01-23 13:45:23 +010035 ioapic_interrupts = 23;
36 ioapic_interrupts += 1; /* Bits 23-16 specify the maximum redirection
37 entry, which is the number of interrupts
38 minus 1. */
39 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
40
41 return ioapic_interrupts;
42}
43
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030044static void clear_vectors(void *ioapic_base, u8 first, u8 last)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000045{
46 u32 low, high;
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030047 u8 i;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000048
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080049 printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000050
Marc Jonesf7dc9722018-03-31 22:45:35 -060051 low = INT_DISABLED;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000052 high = NONE;
53
Kyösti Mälkki93c1eef2021-06-03 23:14:05 +030054 for (i = first; i <= last; i++)
55 write_vector(ioapic_base, i, high, low);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000056
57 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
Uwe Hermanne49903652010-10-14 23:40:10 +000058 printk(BIOS_WARNING, "IOAPIC not responding.\n");
Stefan Reinauer0401bd82010-01-16 18:31:34 +000059 return;
60 }
61}
62
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030063void clear_ioapic(void *ioapic_base)
64{
65 clear_vectors(ioapic_base, 0, ioapic_interrupt_count(ioapic_base) - 1);
66}
67
68static void route_i8259_irq0(void *ioapic_base)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000069{
70 u32 bsp_lapicid = lapicid();
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030071 u32 low, high;
72
73 ASSERT(bsp_lapicid < 255);
74
75 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
76 bsp_lapicid);
77
78 /* Enable Virtual Wire Mode. Should this be LOGICAL_DEST instead? */
79 low = INT_ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
80 high = bsp_lapicid << (56 - 32);
81
Kyösti Mälkki93c1eef2021-06-03 23:14:05 +030082 write_vector(ioapic_base, 0, high, low);
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030083
84 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
85 printk(BIOS_WARNING, "IOAPIC not responding.\n");
86 return;
87 }
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030088}
89
90void set_ioapic_id(void *ioapic_base, u8 ioapic_id)
91{
Paul Menzel1b3e1762013-04-23 14:49:41 +020092 int i;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000093
Julius Werner540a9802019-12-09 13:03:29 -080094 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at %p\n",
Uwe Hermanne49903652010-10-14 23:40:10 +000095 ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000096
97 if (ioapic_id) {
Stefan Reinauer14e22772010-04-27 06:56:47 +000098 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
Uwe Hermanne49903652010-10-14 23:40:10 +000099 /* Set IOAPIC ID if it has been specified. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000100 io_apic_write(ioapic_base, 0x00,
Kyösti Mälkki939103c2011-10-19 07:23:51 +0300101 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
Uwe Hermanne49903652010-10-14 23:40:10 +0000102 (ioapic_id << 24));
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000103 }
Paul Menzel1b3e1762013-04-23 14:49:41 +0200104
105 printk(BIOS_SPEW, "IOAPIC: Dumping registers\n");
106 for (i = 0; i < 3; i++)
107 printk(BIOS_SPEW, " reg 0x%04x: 0x%08x\n", i,
108 io_apic_read(ioapic_base, i));
109
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200110}
111
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300112void setup_ioapic_helper(void *ioapic_base, u8 ioapic_id, bool irq_on_fsb,
113 bool enable_virtual_wire)
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200114{
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300115 int first = 0, last;
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000116
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300117 set_ioapic_id(ioapic_base, ioapic_id);
118
119 if (irq_on_fsb) {
Martin Roth898a7752017-06-01 11:39:59 -0600120 /*
121 * For the Pentium 4 and above APICs deliver their interrupts
122 * on the front side bus, enable that.
123 */
124 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
125 io_apic_write(ioapic_base, 0x03,
126 io_apic_read(ioapic_base, 0x03) | (1 << 0));
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300127 } else {
Martin Roth898a7752017-06-01 11:39:59 -0600128 printk(BIOS_DEBUG,
129 "IOAPIC: Enabling interrupts on APIC serial bus\n");
130 io_apic_write(ioapic_base, 0x03, 0);
131 }
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000132
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300133 if (enable_virtual_wire) {
134 route_i8259_irq0(ioapic_base);
135 first = 1;
136 }
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000137
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +0300138 last = ioapic_interrupt_count(ioapic_base) - 1;
139 clear_vectors(ioapic_base, first, last);
Eric Biederman5899fd82003-04-24 06:25:08 +0000140}
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200141
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300142
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800143void setup_ioapic(void *ioapic_base, u8 ioapic_id)
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200144{
Kyösti Mälkki8cc25d22021-06-03 18:36:05 +0300145 setup_ioapic_helper(ioapic_base, ioapic_id,
146 CONFIG(IOAPIC_INTERRUPTS_ON_FSB), true);
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200147}