From 70c660fd1473b8c6ca7b71276b9552ee2205c99a Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Thu, 23 Aug 2012 02:32:58 -0500 Subject: pirq_routing: Allow routing with more than 4 PIRQ links pirq_routing_irqs assumed that only four links are available for PIRQ routing, INTA to INTD. Some chipsets provide more, up to INTH. When pirq_routing_irqs found a link number greater than 4 in the pirq table, it would not assign that IRQ. This is a shame, as it limits the flexibility of routing IRQs. Make the maximum number of links a Kconfig variable, and modify the code to respect it. This works beatifully on the VX900, which provides 8 routable interrupts. While we're at it, also refactor pirq_routing_irqs, and add some much needed comments. Rename pirq_routing_irqs to pirq_route_irqs to demistify the role of this function. The copyrights added were determined from git log filename. Change-Id: I4b565315404c65b871406f616474e2cc9e6e013e Signed-off-by: Alexandru Gagniuc Reviewed-on: http://review.coreboot.org/1482 Tested-by: build bot (Jenkins) --- src/Kconfig | 12 ++++ src/arch/x86/boot/pirq_routing.c | 98 ++++++++++++++++++++++---------- src/arch/x86/include/arch/pirq_routing.h | 35 +++++++++++- 3 files changed, 112 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/Kconfig b/src/Kconfig index 469266dde9..e0062dde6e 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -1,6 +1,7 @@ ## ## This file is part of the coreboot project. ## +## Copyright (C) 2012 Alexandru Gagniuc ## Copyright (C) 2009-2010 coresystems GmbH ## ## This program is free software; you can redistribute it and/or modify @@ -374,6 +375,17 @@ config HAVE_PIRQ_TABLE Whether or not the PIRQ table is actually generated by coreboot is configurable by the user via GENERATE_PIRQ_TABLE. +config MAX_PIRQ_LINKS + int + default 4 + help + This variable specifies the number of PIRQ interrupt links which are + routable. On most chipsets, this is 4, INTA through INTD. Some + chipsets offer more than four links, commonly up to INTH. They may + also have a separate link for ATA or IOAPIC interrupts. When the PIRQ + table specifies links greater than 4, pirq_route_irqs will not + function properly, unless this variable is correctly set. + #These Options are here to avoid "undefined" warnings. #The actual selection and help texts are in the following menu. diff --git a/src/arch/x86/boot/pirq_routing.c b/src/arch/x86/boot/pirq_routing.c index bb8a7b605a..357500c07e 100644 --- a/src/arch/x86/boot/pirq_routing.c +++ b/src/arch/x86/boot/pirq_routing.c @@ -1,3 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * Copyright (C) 2010 Stefan Reinauer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #include #include #include @@ -92,18 +111,50 @@ unsigned long copy_pirq_routing_table(unsigned long addr) #if CONFIG_DEBUG_PIRQ verify_copy_pirq_routing_table(addr); #endif - pirq_routing_irqs(addr); + pirq_route_irqs(addr); return addr + intel_irq_routing_table.size; } #if CONFIG_PIRQ_ROUTE -void pirq_routing_irqs(unsigned long addr) +static u8 pirq_get_next_free_irq(u8* pirq, u16 bitmap) { - int i, j, k, num_entries; - unsigned char irq_slot[4]; - unsigned char pirq[4] = {0, 0, 0, 0}; + int i, link; + u8 irq = 0; + for (i = 2; i <= 15; i++) + { + /* Can we assign this IRQ ? */ + if (!((bitmap >> i) & 1)) + continue; + /* We can, Now let's assume we can use this IRQ */ + irq = i; + /* And assume we have not yet routed it */ + int already_routed = 0; + /* Have we already routed it ? */ + for(link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) { + if (pirq[link] == irq) { + already_routed = 1; + break; + } + } + /* If it's not yet routed, use it */ + if(!already_routed) + break; + /* But if it was already routed, try the next one */ + continue; + } + /* Now we got our IRQ */ + return irq; +} + +void pirq_route_irqs(unsigned long addr) +{ + int i, intx, num_entries; + unsigned char irq_slot[MAX_INTX_ENTRIES]; + unsigned char pirq[CONFIG_MAX_PIRQ_LINKS]; struct irq_routing_table *pirq_tbl; + memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS); + pirq_tbl = (struct irq_routing_table *)(addr); num_entries = (pirq_tbl->size - 32) / 16; @@ -113,37 +164,26 @@ void pirq_routing_irqs(unsigned long addr) printk(BIOS_DEBUG, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i, pirq_tbl->slots[i].devfn >> 3, pirq_tbl->slots[i].slot); - for (j = 0; j < 4; j++) { + for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) { - int link = pirq_tbl->slots[i].irq[j].link; - int bitmap = pirq_tbl->slots[i].irq[j].bitmap; + int link = pirq_tbl->slots[i].irq[intx].link; + int bitmap = pirq_tbl->slots[i].irq[intx].bitmap; int irq = 0; printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ", - 'A' + j, link, bitmap); + 'A' + intx, link, bitmap); - if (!bitmap|| !link || link > 4) { + if (!bitmap|| !link || link > CONFIG_MAX_PIRQ_LINKS) { printk(BIOS_DEBUG, "not routed\n"); - irq_slot[j] = irq; + irq_slot[intx] = irq; continue; } /* yet not routed */ - if (!pirq[link - 1]) { - - for (k = 2; k <= 15; k++) { - - if (!((bitmap >> k) & 1)) - continue; - - irq = k; - - /* yet not routed */ - if (pirq[0] != irq && pirq[1] != irq && pirq[2] != irq && pirq[3] != irq) - break; - } - + if (!pirq[link - 1]) + { + irq = pirq_get_next_free_irq(pirq, bitmap); if (irq) pirq[link - 1] = irq; } @@ -151,7 +191,7 @@ void pirq_routing_irqs(unsigned long addr) irq = pirq[link - 1]; printk(BIOS_DEBUG, "IRQ: %d\n", irq); - irq_slot[j] = irq; + irq_slot[intx] = irq; } /* Bus, device, slots IRQs for {A,B,C,D}. */ @@ -159,10 +199,8 @@ void pirq_routing_irqs(unsigned long addr) pirq_tbl->slots[i].devfn >> 3, irq_slot); } - printk(BIOS_DEBUG, "PIRQ1: %d\n", pirq[0]); - printk(BIOS_DEBUG, "PIRQ2: %d\n", pirq[1]); - printk(BIOS_DEBUG, "PIRQ3: %d\n", pirq[2]); - printk(BIOS_DEBUG, "PIRQ4: %d\n", pirq[3]); + for(i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++) + printk(BIOS_DEBUG, "PIRQ%c: %d\n", i + 'A', pirq[i]); pirq_assign_irqs(pirq); } diff --git a/src/arch/x86/include/arch/pirq_routing.h b/src/arch/x86/include/arch/pirq_routing.h index 08ba53506d..c5be5f49ae 100644 --- a/src/arch/x86/include/arch/pirq_routing.h +++ b/src/arch/x86/include/arch/pirq_routing.h @@ -1,6 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * Copyright (C) 2012 Patrick Georgi + * Copyright (C) 2010 Stefan Reinauer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #ifndef ARCH_PIRQ_ROUTING_H #define ARCH_PIRQ_ROUTING_H +/* This is the maximum number on interrupt entries that a PCI device may have. + * This is NOT the number of slots or devices in the system + * This is NOT the number of entries in the PIRQ table + * This tells us that in the PIRQ table, we are going to have 4 link-bitmap + * entries per PCI device + * It is fixed at 4: INTA, INTB, INTC, and INTD + * CAUTION: If you change this, pirq_routing will not work correctly*/ +#define MAX_INTX_ENTRIES 4 + #if CONFIG_GENERATE_PIRQ_TABLE #include @@ -40,10 +69,10 @@ unsigned long copy_pirq_routing_table(unsigned long start); unsigned long write_pirq_routing_table(unsigned long start); #if CONFIG_PIRQ_ROUTE -void pirq_routing_irqs(unsigned long start); -void pirq_assign_irqs(const unsigned char pIntAtoD[4]); +void pirq_route_irqs(unsigned long start); +void pirq_assign_irqs(const unsigned char pirq[CONFIG_MAX_PIRQ_LINKS]); #else -#define pirq_routing_irqs(start) {} +#define pirq_route_irqs(start) {} #endif #else -- cgit v1.2.3