blob: 1a8b489ed3a2dc10dca2a5ebd910f0369d8b6dd4 [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
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080021static int ioapic_interrupt_count(void *ioapic_base)
Patrick Georgid1de45e2013-01-23 13:45:23 +010022{
23 /* Read the available number of interrupts. */
24 int ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030025 if (!ioapic_interrupts || ioapic_interrupts == 0xff)
Patrick Georgid1de45e2013-01-23 13:45:23 +010026 ioapic_interrupts = 23;
27 ioapic_interrupts += 1; /* Bits 23-16 specify the maximum redirection
28 entry, which is the number of interrupts
29 minus 1. */
30 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
31
32 return ioapic_interrupts;
33}
34
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030035static void clear_vectors(void *ioapic_base, u8 first, u8 last)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000036{
37 u32 low, high;
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030038 u8 i;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000039
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080040 printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000041
Marc Jonesf7dc9722018-03-31 22:45:35 -060042 low = INT_DISABLED;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000043 high = NONE;
44
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030045 for (i = first; i <= last; i++) {
Stefan Reinauer0401bd82010-01-16 18:31:34 +000046 io_apic_write(ioapic_base, i * 2 + 0x10, low);
47 io_apic_write(ioapic_base, i * 2 + 0x11, high);
48
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030049 printk(BIOS_SPEW, "IOAPIC: vector 0x%02x value 0x%08x 0x%08x\n",
Uwe Hermanne49903652010-10-14 23:40:10 +000050 i, high, low);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000051 }
52
53 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
Uwe Hermanne49903652010-10-14 23:40:10 +000054 printk(BIOS_WARNING, "IOAPIC not responding.\n");
Stefan Reinauer0401bd82010-01-16 18:31:34 +000055 return;
56 }
57}
58
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030059void clear_ioapic(void *ioapic_base)
60{
61 clear_vectors(ioapic_base, 0, ioapic_interrupt_count(ioapic_base) - 1);
62}
63
64static void route_i8259_irq0(void *ioapic_base)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000065{
66 u32 bsp_lapicid = lapicid();
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +030067 u32 low, high;
68
69 ASSERT(bsp_lapicid < 255);
70
71 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
72 bsp_lapicid);
73
74 /* Enable Virtual Wire Mode. Should this be LOGICAL_DEST instead? */
75 low = INT_ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
76 high = bsp_lapicid << (56 - 32);
77
78 io_apic_write(ioapic_base, 0x10, low);
79 io_apic_write(ioapic_base, 0x11, high);
80
81 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
82 printk(BIOS_WARNING, "IOAPIC not responding.\n");
83 return;
84 }
85
86 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", 0, high, low);
87}
88
89void set_ioapic_id(void *ioapic_base, u8 ioapic_id)
90{
Paul Menzel1b3e1762013-04-23 14:49:41 +020091 int i;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000092
Julius Werner540a9802019-12-09 13:03:29 -080093 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at %p\n",
Uwe Hermanne49903652010-10-14 23:40:10 +000094 ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000095
96 if (ioapic_id) {
Stefan Reinauer14e22772010-04-27 06:56:47 +000097 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
Uwe Hermanne49903652010-10-14 23:40:10 +000098 /* Set IOAPIC ID if it has been specified. */
Stefan Reinauer14e22772010-04-27 06:56:47 +000099 io_apic_write(ioapic_base, 0x00,
Kyösti Mälkki939103c2011-10-19 07:23:51 +0300100 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
Uwe Hermanne49903652010-10-14 23:40:10 +0000101 (ioapic_id << 24));
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000102 }
Paul Menzel1b3e1762013-04-23 14:49:41 +0200103
104 printk(BIOS_SPEW, "IOAPIC: Dumping registers\n");
105 for (i = 0; i < 3; i++)
106 printk(BIOS_SPEW, " reg 0x%04x: 0x%08x\n", i,
107 io_apic_read(ioapic_base, i));
108
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200109}
110
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800111static void load_vectors(void *ioapic_base)
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200112{
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +0300113 int first = 1, last;
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000114
Julius Wernercd49cce2019-03-05 16:53:33 -0800115 if (CONFIG(IOAPIC_INTERRUPTS_ON_FSB)) {
Martin Roth898a7752017-06-01 11:39:59 -0600116 /*
117 * For the Pentium 4 and above APICs deliver their interrupts
118 * on the front side bus, enable that.
119 */
120 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
121 io_apic_write(ioapic_base, 0x03,
122 io_apic_read(ioapic_base, 0x03) | (1 << 0));
Julius Wernercd49cce2019-03-05 16:53:33 -0800123 } else if (CONFIG(IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS)) {
Martin Roth898a7752017-06-01 11:39:59 -0600124 printk(BIOS_DEBUG,
125 "IOAPIC: Enabling interrupts on APIC serial bus\n");
126 io_apic_write(ioapic_base, 0x03, 0);
127 }
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000128
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +0300129 route_i8259_irq0(ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000130
Kyösti Mälkkiea2fb8d2021-06-03 23:12:09 +0300131 last = ioapic_interrupt_count(ioapic_base) - 1;
132 clear_vectors(ioapic_base, first, last);
Eric Biederman5899fd82003-04-24 06:25:08 +0000133}
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200134
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800135void setup_ioapic(void *ioapic_base, u8 ioapic_id)
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200136{
137 set_ioapic_id(ioapic_base, ioapic_id);
138 load_vectors(ioapic_base);
139}