forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.2 KiB
133 lines
3.2 KiB
// SPDX-License-Identifier: GPL-2.0+ |
|
/* |
|
* Copyright (C) 2015, Bin Meng <[email protected]> |
|
* |
|
* Part of this file is ported from coreboot src/arch/x86/boot/pirq_routing.c |
|
*/ |
|
|
|
#include <common.h> |
|
#include <pci.h> |
|
#include <asm/pci.h> |
|
#include <asm/pirq_routing.h> |
|
|
|
static u8 pirq_get_next_free_irq(struct udevice *dev, u8 *pirq, u16 bitmap, |
|
bool irq_already_routed[]) |
|
{ |
|
int i, link; |
|
u8 irq = 0; |
|
|
|
/* IRQ sharing starts from IRQ#3 */ |
|
for (i = 3; i < 16; i++) { |
|
/* Can we assign this IRQ? */ |
|
if (!((bitmap >> i) & 1)) |
|
continue; |
|
|
|
/* We can, now let's assume we can use this IRQ */ |
|
irq = i; |
|
|
|
/* Have we already routed it? */ |
|
if (irq_already_routed[irq]) |
|
continue; |
|
|
|
for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) { |
|
if (pirq_check_irq_routed(dev, link, irq)) { |
|
irq_already_routed[irq] = true; |
|
break; |
|
} |
|
} |
|
|
|
/* If it's not yet routed, use it */ |
|
if (!irq_already_routed[irq]) { |
|
irq_already_routed[irq] = true; |
|
break; |
|
} |
|
|
|
/* But if it was already routed, try the next one */ |
|
} |
|
|
|
/* Now we get our IRQ */ |
|
return irq; |
|
} |
|
|
|
void pirq_route_irqs(struct udevice *dev, struct irq_info *irq, int num) |
|
{ |
|
unsigned char irq_slot[MAX_INTX_ENTRIES]; |
|
unsigned char pirq[CONFIG_MAX_PIRQ_LINKS]; |
|
bool irq_already_routed[16]; |
|
int i, intx; |
|
|
|
memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS); |
|
memset(irq_already_routed, '\0', sizeof(irq_already_routed)); |
|
|
|
/* Set PCI IRQs */ |
|
for (i = 0; i < num; i++) { |
|
debug("PIRQ Entry %d Dev: %d.%x.%d\n", i, |
|
irq->bus, irq->devfn >> 3, irq->devfn & 7); |
|
|
|
for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) { |
|
int link = irq->irq[intx].link; |
|
int bitmap = irq->irq[intx].bitmap; |
|
int irq = 0; |
|
|
|
debug("INT%c link: %x bitmap: %x ", |
|
'A' + intx, link, bitmap); |
|
|
|
if (!bitmap || !link) { |
|
debug("not routed\n"); |
|
irq_slot[intx] = irq; |
|
continue; |
|
} |
|
|
|
/* translate link value to link number */ |
|
link = pirq_translate_link(dev, link); |
|
|
|
/* yet not routed */ |
|
if (!pirq[link]) { |
|
irq = pirq_get_next_free_irq(dev, pirq, bitmap, |
|
irq_already_routed); |
|
pirq[link] = irq; |
|
} else { |
|
irq = pirq[link]; |
|
} |
|
|
|
debug("IRQ: %d\n", irq); |
|
irq_slot[intx] = irq; |
|
|
|
/* Assign IRQ in the interrupt router */ |
|
pirq_assign_irq(dev, link, irq); |
|
} |
|
|
|
/* Bus, device, slots IRQs for {A,B,C,D} */ |
|
pci_assign_irqs(irq->bus, irq->devfn >> 3, irq_slot); |
|
|
|
irq++; |
|
} |
|
|
|
for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++) |
|
debug("PIRQ%c: %d\n", 'A' + i, pirq[i]); |
|
} |
|
|
|
u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt) |
|
{ |
|
struct irq_routing_table *rom_rt; |
|
|
|
/* Align the table to be 16 byte aligned */ |
|
addr = ALIGN(addr, 16); |
|
|
|
debug("Copying Interrupt Routing Table to 0x%x\n", addr); |
|
memcpy((void *)(uintptr_t)addr, rt, rt->size); |
|
|
|
/* |
|
* We do the sanity check here against the copied table after memcpy, |
|
* as something might go wrong after the memcpy, which is normally |
|
* due to the F segment decode is not turned on to systeam RAM. |
|
*/ |
|
rom_rt = (struct irq_routing_table *)(uintptr_t)addr; |
|
if (rom_rt->signature != PIRQ_SIGNATURE || |
|
rom_rt->version != PIRQ_VERSION || rom_rt->size % 16) { |
|
printf("Interrupt Routing Table not valid\n"); |
|
return addr; |
|
} |
|
|
|
return addr + rt->size; |
|
}
|
|
|