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 <mr.nuke.me@gmail.com>
Reviewed-on: http://review.coreboot.org/1482
Tested-by: build bot (Jenkins)
This commit is contained in:
Alexandru Gagniuc 2012-08-23 02:32:58 -05:00
parent 93a8b27cbe
commit 70c660fd14
3 changed files with 112 additions and 33 deletions

View File

@ -1,6 +1,7 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
## 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.

View File

@ -1,3 +1,22 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2010 Stefan Reinauer <stepan@coreboot.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <console/console.h>
#include <arch/pirq_routing.h>
#include <string.h>
@ -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);
}

View File

@ -1,6 +1,35 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2012 Patrick Georgi <patrick@georgi-clan.de>
* Copyright (C) 2010 Stefan Reinauer <stepan@coreboot.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 <stdint.h>
@ -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