blob: 362650dea9ead7e80b2eb99f545cea430b680612 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-or-later */
Patrick Georgi11f00792020-03-04 15:10:45 +01002
Eric Biederman8ca8d762003-04-22 19:02:15 +00003#include <console/console.h>
4#include <arch/pirq_routing.h>
Elyes HAOUASe2d152c2019-06-21 07:06:50 +02005#include <commonlib/helpers.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +00006#include <string.h>
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +00007#include <device/pci.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +00008
Stefan Reinauer0b607b32004-06-07 10:25:42 +00009static void check_pirq_routing_table(struct irq_routing_table *rt)
Eric Biederman8ca8d762003-04-22 19:02:15 +000010{
Stefan Reinauer0b607b32004-06-07 10:25:42 +000011 uint8_t *addr = (uint8_t *)rt;
Lee Leahy024b13d2017-03-16 13:41:11 -070012 uint8_t sum = 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +000013 int i;
Eric Biederman8ca8d762003-04-22 19:02:15 +000014
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000015 printk(BIOS_INFO, "Checking Interrupt Routing Table consistency...\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000016
Stefan Reinauer0b607b32004-06-07 10:25:42 +000017 if (sizeof(struct irq_routing_table) != rt->size) {
Lee Leahy6f80ccc2017-03-16 15:18:22 -070018 printk(BIOS_WARNING,
19 "Inconsistent Interrupt Routing Table size (0x%x/0x%x).\n",
20 (unsigned int) sizeof(struct irq_routing_table),
21 rt->size);
Lee Leahy024b13d2017-03-16 13:41:11 -070022 rt->size = sizeof(struct irq_routing_table);
Eric Biederman8ca8d762003-04-22 19:02:15 +000023 }
Eric Biederman8ca8d762003-04-22 19:02:15 +000024
Eric Biederman8ca8d762003-04-22 19:02:15 +000025 for (i = 0; i < rt->size; i++)
26 sum += addr[i];
27
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000028 printk(BIOS_DEBUG, "%s(): Interrupt Routing Table located at %p.\n",
Myles Watson552b3272009-02-12 21:30:06 +000029 __func__, addr);
Eric Biederman8ca8d762003-04-22 19:02:15 +000030
Eric Biedermaneb00fa52003-04-25 02:02:25 +000031 sum = rt->checksum - sum;
Eric Biederman8ca8d762003-04-22 19:02:15 +000032
33 if (sum != rt->checksum) {
Lee Leahy6f80ccc2017-03-16 15:18:22 -070034 printk(BIOS_WARNING,
35 "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n",
36 rt->checksum, sum);
Stefan Reinauer40cba392003-10-28 17:02:10 +000037 rt->checksum = sum;
Eric Biederman8ca8d762003-04-22 19:02:15 +000038 }
39
40 if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
Lee Leahy024b13d2017-03-16 13:41:11 -070041 rt->size % 16) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000042 printk(BIOS_WARNING, "Interrupt Routing Table not valid.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000043 return;
44 }
45
46 sum = 0;
Lee Leahy024b13d2017-03-16 13:41:11 -070047 for (i = 0; i < rt->size; i++)
Eric Biederman8ca8d762003-04-22 19:02:15 +000048 sum += addr[i];
49
Stefan Reinauer94f17772009-01-20 19:21:47 +000050 /* We're manually fixing the checksum above. This warning can probably
51 * never happen because if the target location is read-only this
52 * function would have bailed out earlier.
53 */
Eric Biederman8ca8d762003-04-22 19:02:15 +000054 if (sum) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000055 printk(BIOS_WARNING, "Checksum error in Interrupt Routing Table "
Myles Watson80e914ff2010-06-01 19:25:31 +000056 "could not be fixed.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000057 }
58
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000059 printk(BIOS_INFO, "done.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000060}
61
Lee Leahy6f80ccc2017-03-16 15:18:22 -070062static int verify_copy_pirq_routing_table(unsigned long addr,
63 const struct irq_routing_table *routing_table)
Eric Biederman8ca8d762003-04-22 19:02:15 +000064{
65 int i;
Eric Biederman8cd55d72003-04-24 06:56:37 +000066 uint8_t *rt_orig, *rt_curr;
Eric Biederman8ca8d762003-04-22 19:02:15 +000067
Lee Leahy024b13d2017-03-16 13:41:11 -070068 rt_curr = (uint8_t *)addr;
69 rt_orig = (uint8_t *)routing_table;
Lee Leahy6f80ccc2017-03-16 15:18:22 -070070 printk(BIOS_INFO,
71 "Verifying copy of Interrupt Routing Table at 0x%08lx... ",
72 addr);
Stefan Reinauera47bd912012-11-15 15:15:15 -080073 for (i = 0; i < routing_table->size; i++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +000074 if (*(rt_curr + i) != *(rt_orig + i)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000075 printk(BIOS_INFO, "failed\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000076 return -1;
77 }
78 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000079 printk(BIOS_INFO, "done\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +000080
Stefan Reinauer0b607b32004-06-07 10:25:42 +000081 check_pirq_routing_table((struct irq_routing_table *)addr);
Stefan Reinauer14e22772010-04-27 06:56:47 +000082
Eric Biederman8ca8d762003-04-22 19:02:15 +000083 return 0;
84}
Eric Biederman8ca8d762003-04-22 19:02:15 +000085
Lee Leahy024b13d2017-03-16 13:41:11 -070086static u8 pirq_get_next_free_irq(u8 *pirq, u16 bitmap)
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +000087{
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -050088 int i, link;
89 u8 irq = 0;
Lee Leahy9c7c6f72017-03-16 11:24:09 -070090 for (i = 2; i <= 15; i++) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -050091 /* Can we assign this IRQ ? */
92 if (!((bitmap >> i) & 1))
93 continue;
94 /* We can, Now let's assume we can use this IRQ */
95 irq = i;
96 /* And assume we have not yet routed it */
97 int already_routed = 0;
98 /* Have we already routed it ? */
Elyes HAOUASdbf30672016-08-21 17:37:15 +020099 for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500100 if (pirq[link] == irq) {
101 already_routed = 1;
102 break;
103 }
104 }
105 /* If it's not yet routed, use it */
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200106 if (!already_routed)
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500107 break;
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500108 }
109 /* Now we got our IRQ */
110 return irq;
111}
112
Patrick Georgi95efb562012-10-08 09:33:38 +0200113static void pirq_route_irqs(unsigned long addr)
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500114{
115 int i, intx, num_entries;
116 unsigned char irq_slot[MAX_INTX_ENTRIES];
117 unsigned char pirq[CONFIG_MAX_PIRQ_LINKS];
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000118 struct irq_routing_table *pirq_tbl;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000119
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500120 memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS);
121
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000122 pirq_tbl = (struct irq_routing_table *)(addr);
123 num_entries = (pirq_tbl->size - 32) / 16;
124
125 /* Set PCI IRQs. */
126 for (i = 0; i < num_entries; i++) {
127
Kyösti Mälkkib72b5d92019-07-04 21:08:17 +0300128 u8 bus = pirq_tbl->slots[i].bus;
129 u8 devfn = pirq_tbl->slots[i].devfn;
130
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000131 printk(BIOS_DEBUG, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i,
Kyösti Mälkkib72b5d92019-07-04 21:08:17 +0300132 devfn >> 3, pirq_tbl->slots[i].slot);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000133
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500134 for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) {
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000135
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500136 int link = pirq_tbl->slots[i].irq[intx].link;
137 int bitmap = pirq_tbl->slots[i].irq[intx].bitmap;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000138 int irq = 0;
139
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000140 printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ",
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500141 'A' + intx, link, bitmap);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000142
Lee Leahy024b13d2017-03-16 13:41:11 -0700143 if (!bitmap || !link || link > CONFIG_MAX_PIRQ_LINKS) {
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000144
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000145 printk(BIOS_DEBUG, "not routed\n");
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500146 irq_slot[intx] = irq;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000147 continue;
148 }
149
150 /* yet not routed */
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700151 if (!pirq[link - 1]) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500152 irq = pirq_get_next_free_irq(pirq, bitmap);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000153 if (irq)
154 pirq[link - 1] = irq;
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700155 } else
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000156 irq = pirq[link - 1];
157
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000158 printk(BIOS_DEBUG, "IRQ: %d\n", irq);
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500159 irq_slot[intx] = irq;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000160 }
161
162 /* Bus, device, slots IRQs for {A,B,C,D}. */
Kyösti Mälkkic19d6a62019-07-04 21:39:28 +0300163 pci_assign_irqs(pcidev_path_on_bus(bus, devfn), irq_slot);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000164 }
165
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200166 for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++)
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500167 printk(BIOS_DEBUG, "PIRQ%c: %d\n", i + 'A', pirq[i]);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000168
169 pirq_assign_irqs(pirq);
170}
Patrick Georgi95efb562012-10-08 09:33:38 +0200171
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700172unsigned long copy_pirq_routing_table(unsigned long addr,
173 const struct irq_routing_table *routing_table)
Patrick Georgi95efb562012-10-08 09:33:38 +0200174{
175 /* Align the table to be 16 byte aligned. */
Felix Held84b5aa32019-06-20 14:14:51 +0200176 addr = ALIGN_UP(addr, 16);
Patrick Georgi95efb562012-10-08 09:33:38 +0200177
Kyösti Mälkki9533d832014-06-26 05:30:54 +0300178 /* This table must be between 0xf0000 & 0x100000 */
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700179 printk(BIOS_INFO, "Copying Interrupt Routing Table to 0x%08lx... ",
180 addr);
Patrick Georgi95efb562012-10-08 09:33:38 +0200181 memcpy((void *)addr, routing_table, routing_table->size);
182 printk(BIOS_INFO, "done.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800183 if (CONFIG(DEBUG_PIRQ))
Martin Roth898a7752017-06-01 11:39:59 -0600184 verify_copy_pirq_routing_table(addr, routing_table);
Julius Wernercd49cce2019-03-05 16:53:33 -0800185 if (CONFIG(PIRQ_ROUTE))
Martin Roth898a7752017-06-01 11:39:59 -0600186 pirq_route_irqs(addr);
187
Patrick Georgi95efb562012-10-08 09:33:38 +0200188 return addr + routing_table->size;
189}