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,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