1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <arch/pirq_routing.h>
4 #include <commonlib/helpers.h>
5 #include <console/console.h>
6 #include <device/pci.h>
10 static void check_pirq_routing_table(struct irq_routing_table
*rt
)
12 uint8_t *addr
= (uint8_t *)rt
;
16 printk(BIOS_INFO
, "Checking Interrupt Routing Table consistency...\n");
18 if (sizeof(struct irq_routing_table
) != rt
->size
) {
20 "Inconsistent Interrupt Routing Table size (0x%x/0x%x).\n",
21 (unsigned int)sizeof(struct irq_routing_table
),
23 rt
->size
= sizeof(struct irq_routing_table
);
26 for (i
= 0; i
< rt
->size
; i
++)
29 printk(BIOS_DEBUG
, "%s(): Interrupt Routing Table located at %p.\n",
32 sum
= rt
->checksum
- sum
;
34 if (sum
!= rt
->checksum
) {
36 "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n",
41 if (rt
->signature
!= PIRQ_SIGNATURE
|| rt
->version
!= PIRQ_VERSION
||
43 printk(BIOS_WARNING
, "Interrupt Routing Table not valid.\n");
48 for (i
= 0; i
< rt
->size
; i
++)
51 /* 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.
56 printk(BIOS_WARNING
, "Checksum error in Interrupt Routing Table "
57 "could not be fixed.\n");
60 printk(BIOS_INFO
, "done.\n");
63 static enum cb_err
verify_copy_pirq_routing_table(unsigned long addr
,
64 const struct irq_routing_table
*routing_table
)
67 uint8_t *rt_orig
, *rt_curr
;
69 rt_curr
= (uint8_t *)addr
;
70 rt_orig
= (uint8_t *)routing_table
;
72 "Verifying copy of Interrupt Routing Table at 0x%08lx... ",
74 for (i
= 0; i
< routing_table
->size
; i
++) {
75 if (*(rt_curr
+ i
) != *(rt_orig
+ i
)) {
76 printk(BIOS_INFO
, "failed\n");
80 printk(BIOS_INFO
, "done\n");
82 check_pirq_routing_table((struct irq_routing_table
*)addr
);
87 static u8
pirq_get_next_free_irq(u8
*pirq
, u16 bitmap
)
91 for (i
= 2; i
<= 15; i
++) {
92 /* Can we assign this IRQ ? */
93 if (!((bitmap
>> i
) & 1))
95 /* We can, Now let's assume we can use this IRQ */
97 /* And assume we have not yet routed it */
98 int already_routed
= 0;
99 /* Have we already routed it ? */
100 for (link
= 0; link
< CONFIG_MAX_PIRQ_LINKS
; link
++) {
101 if (pirq
[link
] == irq
) {
106 /* If it's not yet routed, use it */
110 /* Now we got our IRQ */
114 static void pirq_route_irqs(unsigned long addr
)
116 int i
, intx
, num_entries
;
117 unsigned char irq_slot
[MAX_INTX_ENTRIES
];
118 unsigned char pirq
[CONFIG_MAX_PIRQ_LINKS
];
119 struct irq_routing_table
*pirq_tbl
;
121 memset(pirq
, 0, CONFIG_MAX_PIRQ_LINKS
);
123 pirq_tbl
= (struct irq_routing_table
*)(addr
);
124 num_entries
= (pirq_tbl
->size
- 32) / 16;
127 for (i
= 0; i
< num_entries
; i
++) {
128 u8 bus
= pirq_tbl
->slots
[i
].bus
;
129 u8 devfn
= pirq_tbl
->slots
[i
].devfn
;
131 printk(BIOS_DEBUG
, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i
,
132 devfn
>> 3, pirq_tbl
->slots
[i
].slot
);
134 for (intx
= 0; intx
< MAX_INTX_ENTRIES
; intx
++) {
135 int link
= pirq_tbl
->slots
[i
].irq
[intx
].link
;
136 int bitmap
= pirq_tbl
->slots
[i
].irq
[intx
].bitmap
;
139 printk(BIOS_DEBUG
, "INT: %c link: %x bitmap: %x ",
140 'A' + intx
, link
, bitmap
);
142 if (!bitmap
|| !link
|| link
> CONFIG_MAX_PIRQ_LINKS
) {
143 printk(BIOS_DEBUG
, "not routed\n");
144 irq_slot
[intx
] = irq
;
149 if (!pirq
[link
- 1]) {
150 irq
= pirq_get_next_free_irq(pirq
, bitmap
);
152 pirq
[link
- 1] = irq
;
154 irq
= pirq
[link
- 1];
156 printk(BIOS_DEBUG
, "IRQ: %d\n", irq
);
157 irq_slot
[intx
] = irq
;
160 /* Bus, device, slots IRQs for {A,B,C,D}. */
161 pci_assign_irqs(pcidev_path_on_bus(bus
, devfn
), irq_slot
);
164 for (i
= 0; i
< CONFIG_MAX_PIRQ_LINKS
; i
++)
165 printk(BIOS_DEBUG
, "PIRQ%c: %d\n", i
+ 'A', pirq
[i
]);
167 pirq_assign_irqs(pirq
);
170 unsigned long copy_pirq_routing_table(unsigned long addr
,
171 const struct irq_routing_table
*routing_table
)
173 /* Align the table to be 16 byte aligned. */
174 addr
= ALIGN_UP(addr
, 16);
176 /* This table must be between 0xf0000 & 0x100000 */
177 printk(BIOS_INFO
, "Copying Interrupt Routing Table to 0x%08lx... ",
179 memcpy((void *)addr
, routing_table
, routing_table
->size
);
180 printk(BIOS_INFO
, "done.\n");
181 if (CONFIG(DEBUG_PIRQ
))
182 verify_copy_pirq_routing_table(addr
, routing_table
);
183 if (CONFIG(PIRQ_ROUTE
))
184 pirq_route_irqs(addr
);
186 return addr
+ routing_table
->size
;