blob: e6f3b805ff0283eaeb1ea8c4c7fde3714b7d3856 [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 <arch/pirq_routing.h>
Elyes HAOUASe2d152c2019-06-21 07:06:50 +02004#include <commonlib/helpers.h>
Elyes Haouas9523e3b2022-11-08 14:38:41 +01005#include <console/console.h>
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +00006#include <device/pci.h>
Elyes Haouas9523e3b2022-11-08 14:38:41 +01007#include <string.h>
8#include <types.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +00009
Stefan Reinauer0b607b32004-06-07 10:25:42 +000010static void check_pirq_routing_table(struct irq_routing_table *rt)
Eric Biederman8ca8d762003-04-22 19:02:15 +000011{
Stefan Reinauer0b607b32004-06-07 10:25:42 +000012 uint8_t *addr = (uint8_t *)rt;
Lee Leahy024b13d2017-03-16 13:41:11 -070013 uint8_t sum = 0;
Eric Biederman8ca8d762003-04-22 19:02:15 +000014 int i;
Eric Biederman8ca8d762003-04-22 19:02:15 +000015
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000016 printk(BIOS_INFO, "Checking Interrupt Routing Table consistency...\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000017
Stefan Reinauer0b607b32004-06-07 10:25:42 +000018 if (sizeof(struct irq_routing_table) != rt->size) {
Lee Leahy6f80ccc2017-03-16 15:18:22 -070019 printk(BIOS_WARNING,
20 "Inconsistent Interrupt Routing Table size (0x%x/0x%x).\n",
Elyes Haouas2ba796e2022-11-18 15:21:37 +010021 (unsigned int)sizeof(struct irq_routing_table),
Lee Leahy6f80ccc2017-03-16 15:18:22 -070022 rt->size);
Lee Leahy024b13d2017-03-16 13:41:11 -070023 rt->size = sizeof(struct irq_routing_table);
Eric Biederman8ca8d762003-04-22 19:02:15 +000024 }
Eric Biederman8ca8d762003-04-22 19:02:15 +000025
Eric Biederman8ca8d762003-04-22 19:02:15 +000026 for (i = 0; i < rt->size; i++)
27 sum += addr[i];
28
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000029 printk(BIOS_DEBUG, "%s(): Interrupt Routing Table located at %p.\n",
Myles Watson552b3272009-02-12 21:30:06 +000030 __func__, addr);
Eric Biederman8ca8d762003-04-22 19:02:15 +000031
Eric Biedermaneb00fa52003-04-25 02:02:25 +000032 sum = rt->checksum - sum;
Eric Biederman8ca8d762003-04-22 19:02:15 +000033
34 if (sum != rt->checksum) {
Lee Leahy6f80ccc2017-03-16 15:18:22 -070035 printk(BIOS_WARNING,
36 "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n",
37 rt->checksum, sum);
Stefan Reinauer40cba392003-10-28 17:02:10 +000038 rt->checksum = sum;
Eric Biederman8ca8d762003-04-22 19:02:15 +000039 }
40
41 if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
Lee Leahy024b13d2017-03-16 13:41:11 -070042 rt->size % 16) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000043 printk(BIOS_WARNING, "Interrupt Routing Table not valid.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000044 return;
45 }
46
47 sum = 0;
Lee Leahy024b13d2017-03-16 13:41:11 -070048 for (i = 0; i < rt->size; i++)
Eric Biederman8ca8d762003-04-22 19:02:15 +000049 sum += addr[i];
50
Stefan Reinauer94f17772009-01-20 19:21:47 +000051 /* We're manually fixing the checksum above. This warning can probably
52 * never happen because if the target location is read-only this
53 * function would have bailed out earlier.
54 */
Eric Biederman8ca8d762003-04-22 19:02:15 +000055 if (sum) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000056 printk(BIOS_WARNING, "Checksum error in Interrupt Routing Table "
Myles Watson80e914ff2010-06-01 19:25:31 +000057 "could not be fixed.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000058 }
59
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000060 printk(BIOS_INFO, "done.\n");
Eric Biederman8ca8d762003-04-22 19:02:15 +000061}
62
Elyes Haouas9523e3b2022-11-08 14:38:41 +010063static enum cb_err verify_copy_pirq_routing_table(unsigned long addr,
Lee Leahy6f80ccc2017-03-16 15:18:22 -070064 const struct irq_routing_table *routing_table)
Eric Biederman8ca8d762003-04-22 19:02:15 +000065{
66 int i;
Eric Biederman8cd55d72003-04-24 06:56:37 +000067 uint8_t *rt_orig, *rt_curr;
Eric Biederman8ca8d762003-04-22 19:02:15 +000068
Lee Leahy024b13d2017-03-16 13:41:11 -070069 rt_curr = (uint8_t *)addr;
70 rt_orig = (uint8_t *)routing_table;
Lee Leahy6f80ccc2017-03-16 15:18:22 -070071 printk(BIOS_INFO,
72 "Verifying copy of Interrupt Routing Table at 0x%08lx... ",
73 addr);
Stefan Reinauera47bd912012-11-15 15:15:15 -080074 for (i = 0; i < routing_table->size; i++) {
Eric Biederman8ca8d762003-04-22 19:02:15 +000075 if (*(rt_curr + i) != *(rt_orig + i)) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000076 printk(BIOS_INFO, "failed\n");
Elyes Haouas9523e3b2022-11-08 14:38:41 +010077 return CB_ERR;
Eric Biederman8ca8d762003-04-22 19:02:15 +000078 }
79 }
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000080 printk(BIOS_INFO, "done\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +000081
Stefan Reinauer0b607b32004-06-07 10:25:42 +000082 check_pirq_routing_table((struct irq_routing_table *)addr);
Stefan Reinauer14e22772010-04-27 06:56:47 +000083
Elyes Haouas9523e3b2022-11-08 14:38:41 +010084 return CB_SUCCESS;
Eric Biederman8ca8d762003-04-22 19:02:15 +000085}
Eric Biederman8ca8d762003-04-22 19:02:15 +000086
Lee Leahy024b13d2017-03-16 13:41:11 -070087static u8 pirq_get_next_free_irq(u8 *pirq, u16 bitmap)
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +000088{
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -050089 int i, link;
90 u8 irq = 0;
Lee Leahy9c7c6f72017-03-16 11:24:09 -070091 for (i = 2; i <= 15; i++) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -050092 /* Can we assign this IRQ ? */
93 if (!((bitmap >> i) & 1))
94 continue;
95 /* We can, Now let's assume we can use this IRQ */
96 irq = i;
97 /* And assume we have not yet routed it */
98 int already_routed = 0;
99 /* Have we already routed it ? */
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200100 for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500101 if (pirq[link] == irq) {
102 already_routed = 1;
103 break;
104 }
105 }
106 /* If it's not yet routed, use it */
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200107 if (!already_routed)
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500108 break;
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500109 }
110 /* Now we got our IRQ */
111 return irq;
112}
113
Patrick Georgi95efb562012-10-08 09:33:38 +0200114static void pirq_route_irqs(unsigned long addr)
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500115{
116 int i, intx, num_entries;
117 unsigned char irq_slot[MAX_INTX_ENTRIES];
118 unsigned char pirq[CONFIG_MAX_PIRQ_LINKS];
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000119 struct irq_routing_table *pirq_tbl;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000120
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500121 memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS);
122
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000123 pirq_tbl = (struct irq_routing_table *)(addr);
124 num_entries = (pirq_tbl->size - 32) / 16;
125
126 /* Set PCI IRQs. */
127 for (i = 0; i < num_entries; i++) {
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++) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500135 int link = pirq_tbl->slots[i].irq[intx].link;
136 int bitmap = pirq_tbl->slots[i].irq[intx].bitmap;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000137 int irq = 0;
138
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000139 printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ",
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500140 'A' + intx, link, bitmap);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000141
Lee Leahy024b13d2017-03-16 13:41:11 -0700142 if (!bitmap || !link || link > CONFIG_MAX_PIRQ_LINKS) {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000143 printk(BIOS_DEBUG, "not routed\n");
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500144 irq_slot[intx] = irq;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000145 continue;
146 }
147
148 /* yet not routed */
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700149 if (!pirq[link - 1]) {
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500150 irq = pirq_get_next_free_irq(pirq, bitmap);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000151 if (irq)
152 pirq[link - 1] = irq;
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700153 } else
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000154 irq = pirq[link - 1];
155
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000156 printk(BIOS_DEBUG, "IRQ: %d\n", irq);
Alexandru Gagniuc70c660f2012-08-23 02:32:58 -0500157 irq_slot[intx] = irq;
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000158 }
159
160 /* Bus, device, slots IRQs for {A,B,C,D}. */
Kyösti Mälkkic19d6a62019-07-04 21:39:28 +0300161 pci_assign_irqs(pcidev_path_on_bus(bus, devfn), irq_slot);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000162 }
163
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200164 for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++)
Elyes Haouas8b8ada62022-11-22 17:36:02 +0100165 printk(BIOS_DEBUG, "PIRQ%c: %d\n", i + 'A', pirq[i]);
Nikolay Petukhov9c2255c2008-03-29 16:59:27 +0000166
167 pirq_assign_irqs(pirq);
168}
Patrick Georgi95efb562012-10-08 09:33:38 +0200169
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700170unsigned long copy_pirq_routing_table(unsigned long addr,
171 const struct irq_routing_table *routing_table)
Patrick Georgi95efb562012-10-08 09:33:38 +0200172{
173 /* Align the table to be 16 byte aligned. */
Felix Held84b5aa32019-06-20 14:14:51 +0200174 addr = ALIGN_UP(addr, 16);
Patrick Georgi95efb562012-10-08 09:33:38 +0200175
Kyösti Mälkki9533d832014-06-26 05:30:54 +0300176 /* This table must be between 0xf0000 & 0x100000 */
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700177 printk(BIOS_INFO, "Copying Interrupt Routing Table to 0x%08lx... ",
178 addr);
Patrick Georgi95efb562012-10-08 09:33:38 +0200179 memcpy((void *)addr, routing_table, routing_table->size);
180 printk(BIOS_INFO, "done.\n");
Julius Wernercd49cce2019-03-05 16:53:33 -0800181 if (CONFIG(DEBUG_PIRQ))
Martin Roth898a7752017-06-01 11:39:59 -0600182 verify_copy_pirq_routing_table(addr, routing_table);
Julius Wernercd49cce2019-03-05 16:53:33 -0800183 if (CONFIG(PIRQ_ROUTE))
Martin Roth898a7752017-06-01 11:39:59 -0600184 pirq_route_irqs(addr);
185
Patrick Georgi95efb562012-10-08 09:33:38 +0200186 return addr + routing_table->size;
187}