forked from Imagelibrary/rtems
2003-06-13 Greg Menke <gregory.menke@gsfc.nasa.gov>
PR 405/bsps * bootloader/pci.c: Added support for configuring devices for pci busses > 0 * pci/pci.c, pci/pci.h: Added FixupPCI() to store vectors in the INTERRUPT_LINE register of pci devices any # of hops away from the host processor. * motorola/motorola.c, motorola/motorola.h: Added interrupt routing tables in support of FixupPCI. This is board-specific, each board will have to supply information for FixupPCI() to do anything for it. * startup/bspstart.c: Extended bat2 to cover entire PCI address space. * irq/irq.c, irq/irq.h: Added support for shared interrupts. Existing single hander vectors are undisturbed, a new function added to allow adding/removing handlers from a vector.
This commit is contained in:
@@ -1,3 +1,20 @@
|
||||
2003-06-13 Greg Menke <gregory.menke@gsfc.nasa.gov>
|
||||
|
||||
PR 405/bsps
|
||||
* bootloader/pci.c: Added support for configuring devices for pci
|
||||
busses > 0
|
||||
* pci/pci.c, pci/pci.h: Added FixupPCI() to store vectors in the
|
||||
INTERRUPT_LINE register of pci devices any # of hops away
|
||||
from the host processor.
|
||||
* motorola/motorola.c, motorola/motorola.h: Added interrupt
|
||||
routing tables in support of FixupPCI. This is board-specific,
|
||||
each board will have to supply information for FixupPCI() to do
|
||||
anything for it.
|
||||
* startup/bspstart.c: Extended bat2 to cover entire PCI address space.
|
||||
* irq/irq.c, irq/irq.h: Added support for shared interrupts.
|
||||
Existing single hander vectors are undisturbed, a new function
|
||||
added to allow adding/removing handlers from a vector.
|
||||
|
||||
2003-06-13 Till Straumann <strauman@slac.stanford.edu>
|
||||
|
||||
PR 415/bsps
|
||||
|
||||
@@ -39,3 +39,11 @@ initialization (e.g printk, ...).
|
||||
Eric Valette (valette@crf.canon.fr)
|
||||
|
||||
|
||||
**************************************************
|
||||
2003/5/7, Greg Menke, gregory.menke@gsfc.nasa.gov
|
||||
|
||||
Reworked the pci bus 0 initialization a little and added support for
|
||||
configuring an arbitrary number of other busses & their respective
|
||||
bridges. Also added support for configuring IO ranges below 0x10000,
|
||||
which I think is reasonable given this is a PowerPC bsp.
|
||||
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
#include "bootldr.h"
|
||||
#include "pci.h"
|
||||
#include <libcpu/io.h>
|
||||
#include <libcpu/page.h>
|
||||
#include <bsp/consoleIo.h>
|
||||
|
||||
|
||||
|
||||
typedef unsigned int u32;
|
||||
|
||||
/*#define DEBUG*/
|
||||
@@ -95,6 +98,7 @@ print_pci_resources(const char *s) {
|
||||
pci_resource *p;
|
||||
printk("%s", s);
|
||||
for (p=pci->resources; p; p=p->next) {
|
||||
/*
|
||||
printk(" %p:%p %06x %08lx %08lx %d\n",
|
||||
p, p->next,
|
||||
(p->dev->devfn<<8)+(p->dev->bus->number<<16)
|
||||
@@ -102,6 +106,16 @@ print_pci_resources(const char *s) {
|
||||
p->base,
|
||||
p->size,
|
||||
p->type);
|
||||
*/
|
||||
|
||||
printk(" %p:%p %d:%02x (%04x:%04x) %08lx %08lx %d\n",
|
||||
p, p->next,
|
||||
p->dev->bus->number, PCI_SLOT(p->dev->devfn),
|
||||
p->dev->vendor, p->dev->device,
|
||||
p->base,
|
||||
p->size,
|
||||
p->type);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +170,8 @@ static struct blacklist_entry blacklist[] = {
|
||||
((r->type&PCI_BASE_ADDRESS_MEM_PREFETCH) ? PCI_AREA_PREFETCHABLE :\
|
||||
PCI_AREA_MEMORY))
|
||||
|
||||
|
||||
|
||||
static int insert_before(pci_resource *e, pci_resource *t) {
|
||||
if (e->dev->bus->number != t->dev->bus->number)
|
||||
return e->dev->bus->number > t->dev->bus->number;
|
||||
@@ -163,6 +179,10 @@ static int insert_before(pci_resource *e, pci_resource *t) {
|
||||
return (e->size > t->size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void insert_resource(pci_resource *r) {
|
||||
struct blacklist_entry *b;
|
||||
pci_resource *p;
|
||||
@@ -195,12 +215,14 @@ static void insert_resource(pci_resource *r) {
|
||||
* limits have hopefully been set high enough to avoid problems.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
||||
? (r->base && r->base <0x10000)
|
||||
: (r->base && r->base <0x1000000)) {
|
||||
sfree(r);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
||||
? (r->size >= 0x10000)
|
||||
@@ -226,6 +248,10 @@ static void insert_resource(pci_resource *r) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* This version only works for bus 0. I don't have any P2P bridges to test
|
||||
* a more sophisticated version which has therefore not been implemented.
|
||||
* Prefetchable memory is not yet handled correctly either.
|
||||
@@ -240,17 +266,22 @@ static u_long find_range(u_char bus, u_char type,
|
||||
u_long total=0;
|
||||
u_int fl=0;
|
||||
|
||||
for (p=pci->resources; p; p=p->next) {
|
||||
for (p=pci->resources; p; p=p->next)
|
||||
{
|
||||
if ((p->dev->bus->number == bus) &&
|
||||
AREA(p)==type) break;
|
||||
}
|
||||
|
||||
*first = p;
|
||||
for (; p; p=p->next) {
|
||||
|
||||
for (; p; p=p->next)
|
||||
{
|
||||
if ((p->dev->bus->number != bus) ||
|
||||
AREA(p)!=type || p->size == 0) break;
|
||||
total = total+p->size;
|
||||
fl |= 1<<p->type;
|
||||
}
|
||||
|
||||
*past = p;
|
||||
/* This will be used later to tell whether there are any 32 bit
|
||||
* devices in an area which could be mapped higher than 4Gb
|
||||
@@ -260,6 +291,11 @@ static u_long find_range(u_char bus, u_char type,
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static inline void init_free_area(pci_area_head *h, u_long start,
|
||||
u_long end, u_int mask, int high) {
|
||||
pci_area *p;
|
||||
@@ -274,6 +310,11 @@ static inline void init_free_area(pci_area_head *h, u_long start,
|
||||
h->high = high;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void insert_area(pci_area_head *h, pci_area *p) {
|
||||
pci_area *q = h->head;
|
||||
if (!p) return;
|
||||
@@ -298,12 +339,18 @@ static void insert_area(pci_area_head *h, pci_area *p) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static
|
||||
void remove_area(pci_area_head *h, pci_area *p) {
|
||||
void remove_area(pci_area_head *h, pci_area *p)
|
||||
{
|
||||
pci_area *q = h->head;
|
||||
|
||||
if (!p || !q) return;
|
||||
if (q==p) {
|
||||
if (q==p)
|
||||
{
|
||||
h->head = q->next;
|
||||
return;
|
||||
}
|
||||
@@ -311,13 +358,19 @@ void remove_area(pci_area_head *h, pci_area *p) {
|
||||
if (q) q->next=p->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||
u_long required, u_long mask, u_int flags) {
|
||||
pci_area *p;
|
||||
pci_area *from, *split, *new;
|
||||
|
||||
required = (required+h->mask) & ~h->mask;
|
||||
for (p=h->head, from=NULL; p; p=p->next) {
|
||||
for (p=h->head, from=NULL; p; p=p->next)
|
||||
{
|
||||
u_long l1 = ((p->start+required+mask)&~mask)-1;
|
||||
u_long l2 = ((p->start+mask)&~mask)+required-1;
|
||||
/* Allocated areas point to the bus to which they pertain */
|
||||
@@ -339,7 +392,8 @@ static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||
new->bus = bus;
|
||||
new->flags = flags;
|
||||
/* Now allocate pci_space taking alignment into account ! */
|
||||
if (h->high) {
|
||||
if (h->high)
|
||||
{
|
||||
u_long l1 = ((from->end+1)&~mask)-required;
|
||||
u_long l2 = (from->end+1-required)&~mask;
|
||||
new->start = (l1>l2) ? l1 : l2;
|
||||
@@ -347,7 +401,9 @@ static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||
from->end = new->start-1;
|
||||
split->start = new->start+required;
|
||||
new->end = new->start+required-1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
u_long l1 = ((from->start+mask)&~mask)+required-1;
|
||||
u_long l2 = ((from->start+required+mask)&~mask)-1;
|
||||
new->end = (l1<l2) ? l1 : l2;
|
||||
@@ -358,10 +414,13 @@ static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||
}
|
||||
|
||||
if (from->end+1 == from->start) remove_area(h, from);
|
||||
if (split->end+1 != split->start) {
|
||||
if (split->end+1 != split->start)
|
||||
{
|
||||
split->bus = NULL;
|
||||
insert_area(h, split);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
sfree(split);
|
||||
}
|
||||
insert_area(h, new);
|
||||
@@ -369,8 +428,13 @@ static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static inline
|
||||
void alloc_space(pci_area *p, pci_resource *r) {
|
||||
void alloc_space(pci_area *p, pci_resource *r)
|
||||
{
|
||||
if (p->start & (r->size-1)) {
|
||||
r->base = p->end+1-r->size;
|
||||
p->end -= r->size;
|
||||
@@ -380,29 +444,65 @@ void alloc_space(pci_area *p, pci_resource *r) {
|
||||
}
|
||||
}
|
||||
|
||||
static void reconfigure_bus_space(u_char bus, u_char type, pci_area_head *h) {
|
||||
|
||||
|
||||
|
||||
|
||||
static void reconfigure_bus_space(u_char bus, u_char type, pci_area_head *h)
|
||||
{
|
||||
pci_resource *first, *past, *r;
|
||||
pci_area *area, tmp;
|
||||
u_int flags;
|
||||
u_int required = find_range(bus, type, &first, &past, &flags);
|
||||
|
||||
if (required==0) return;
|
||||
|
||||
area = alloc_area(h, first->dev->bus, required, first->size-1, flags);
|
||||
|
||||
if (!area) return;
|
||||
|
||||
tmp = *area;
|
||||
for (r=first; r!=past; r=r->next) {
|
||||
for (r=first; r!=past; r=r->next)
|
||||
{
|
||||
alloc_space(&tmp, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define BUS0_IO_START 0x10000
|
||||
#define BUS0_IO_END 0x1ffff
|
||||
#define BUS0_MEM_START 0x1000000
|
||||
#define BUS0_MEM_END 0xaffffff
|
||||
|
||||
#define BUSREST_IO_START 0x20000
|
||||
#define BUSREST_IO_END 0x7ffff
|
||||
#define BUSREST_MEM_START 0xb000000
|
||||
#define BUSREST_MEM_END 0x30000000
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void reconfigure_pci(void) {
|
||||
pci_resource *r;
|
||||
struct pci_dev *dev;
|
||||
|
||||
/* FIXME: for now memory is relocated from low, it's better
|
||||
* to start from higher addresses.
|
||||
*/
|
||||
/*
|
||||
init_free_area(&pci->io, 0x10000, 0x7fffff, 0xfff, 0);
|
||||
init_free_area(&pci->mem, 0x1000000, 0x3cffffff, 0xfffff, 0);
|
||||
*/
|
||||
|
||||
init_free_area(&pci->io, BUS0_IO_START, BUS0_IO_END, 0xfff, 0);
|
||||
init_free_area(&pci->mem, BUS0_MEM_START, BUS0_MEM_END, 0xfffff, 0);
|
||||
|
||||
|
||||
/* First reconfigure the I/O space, this will be more
|
||||
* complex when there is more than 1 bus. And 64 bits
|
||||
@@ -454,6 +554,11 @@ static void reconfigure_pci(void) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
indirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
|
||||
unsigned char offset, unsigned char *val) {
|
||||
@@ -614,16 +719,24 @@ static const struct pci_config_access_functions direct_functions = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void pci_read_bases(struct pci_dev *dev, unsigned int howmany)
|
||||
{
|
||||
unsigned int reg, nextreg;
|
||||
|
||||
#define REG (PCI_BASE_ADDRESS_0 + (reg<<2))
|
||||
|
||||
u_short cmd;
|
||||
u32 l, ml;
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
|
||||
for(reg=0; reg<howmany; reg=nextreg) {
|
||||
for(reg=0; reg<howmany; reg=nextreg)
|
||||
{
|
||||
pci_resource *r;
|
||||
|
||||
nextreg=reg+1;
|
||||
pci_read_config_dword(dev, REG, &l);
|
||||
#if 0
|
||||
@@ -679,6 +792,10 @@ void pci_read_bases(struct pci_dev *dev, unsigned int howmany)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
u_int pci_scan_bus(struct pci_bus *bus)
|
||||
{
|
||||
unsigned int devfn, l, max, class;
|
||||
@@ -686,6 +803,10 @@ u_int pci_scan_bus(struct pci_bus *bus)
|
||||
struct pci_dev *dev, **bus_last;
|
||||
struct pci_bus *child;
|
||||
|
||||
#if 0
|
||||
printk("scanning pci bus %d\n", bus->number );
|
||||
#endif
|
||||
|
||||
bus_last = &bus->devices;
|
||||
max = bus->secondary;
|
||||
for (devfn = 0; devfn < 0xff; ++devfn) {
|
||||
@@ -750,10 +871,10 @@ u_int pci_scan_bus(struct pci_bus *bus)
|
||||
goto bad;
|
||||
pci_read_bases(dev, 1);
|
||||
break;
|
||||
|
||||
default: /* unknown header */
|
||||
bad:
|
||||
printk("PCI device with unknown "
|
||||
"header type %d ignored.\n",
|
||||
printk("PCI device with unknown header type %d ignored.\n",
|
||||
hdr_type&0x7f);
|
||||
continue;
|
||||
}
|
||||
@@ -852,7 +973,7 @@ u_int pci_scan_bus(struct pci_bus *bus)
|
||||
| ((unsigned int)(child->subordinate) << 16);
|
||||
pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
|
||||
}
|
||||
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
|
||||
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -865,18 +986,373 @@ u_int pci_scan_bus(struct pci_bus *bus)
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
void
|
||||
pci_fixup(void) {
|
||||
pci_fixup(void)
|
||||
{
|
||||
struct pci_dev *p;
|
||||
struct pci_bus *bus;
|
||||
for (bus = &pci_root; bus; bus=bus->next) {
|
||||
|
||||
for (p=bus->devices; p; p=p->sibling) {
|
||||
for (bus = &pci_root; bus; bus=bus->next)
|
||||
{
|
||||
for (p=bus->devices; p; p=p->sibling)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init(void) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void print_pci_info()
|
||||
{
|
||||
pci_resource *r;
|
||||
struct pci_bus *pb = &pci_root;
|
||||
|
||||
printk("\n");
|
||||
printk("PCI busses:\n");
|
||||
|
||||
for(pb= &pci_root; pb; pb=pb->children )
|
||||
{
|
||||
printk(" number %d, primary %d, secondary %d, subordinate %d\n",
|
||||
pb->number,
|
||||
pb->primary,
|
||||
pb->secondary,
|
||||
pb->subordinate );
|
||||
printk(" bridge; vendor %04x, device %04x\n",
|
||||
pb->self->vendor,
|
||||
pb->self->device );
|
||||
|
||||
{
|
||||
struct pci_dev *pd;
|
||||
|
||||
for(pd= pb->devices; pd; pd=pd->sibling )
|
||||
{
|
||||
printk(" vendor %04x, device %04x, irq %d\n",
|
||||
pd->vendor,
|
||||
pd->device,
|
||||
pd->irq );
|
||||
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
printk("PCI resources:\n");
|
||||
for (r=pci->resources; r; r= r->next)
|
||||
{
|
||||
printk(" bus %d, vendor %04x, device %04x, base %08x, size %08x, type %d\n",
|
||||
r->dev->bus->number,
|
||||
r->dev->vendor,
|
||||
r->dev->device,
|
||||
r->base,
|
||||
r->size,
|
||||
r->type );
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static struct _addr_start
|
||||
{
|
||||
unsigned32 start_pcimem;
|
||||
unsigned32 start_pciio;
|
||||
unsigned32 start_prefetch;
|
||||
} astart;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static pci_resource *enum_device_resources( struct pci_dev *pdev, int i )
|
||||
{
|
||||
pci_resource *r;
|
||||
|
||||
for(r= pci->resources; r; r= r->next )
|
||||
{
|
||||
if( r->dev == pdev )
|
||||
{
|
||||
if( i-- == 0 ) break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define MEMORY_IO_GRANULARITY 256
|
||||
|
||||
|
||||
|
||||
static void recursive_bus_reconfigure( struct pci_bus *pbus )
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
struct pci_bus *childbus;
|
||||
int isroot = 0;
|
||||
|
||||
|
||||
if( !pbus )
|
||||
{
|
||||
/* start with the root bus */
|
||||
astart.start_pcimem = BUSREST_MEM_START;
|
||||
astart.start_pciio = BUSREST_IO_START;
|
||||
astart.start_prefetch = ((BUSREST_MEM_END >> 16) << 16);
|
||||
|
||||
pbus = &pci_root;
|
||||
isroot = -1;
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_BRIDGE_IO
|
||||
#define WRITE_BRIDGE_MEM
|
||||
#define WRITE_BRIDGE_PF
|
||||
#define WRITE_BRIDGE_ENABLE
|
||||
|
||||
|
||||
/*
|
||||
** Run thru the p2p bridges on this bus and recurse into subordinate busses
|
||||
*/
|
||||
for( childbus= pbus->children; childbus; childbus= childbus->next )
|
||||
{
|
||||
pdev= childbus->self;
|
||||
|
||||
{
|
||||
struct _addr_start addrhold;
|
||||
unsigned8 base8, limit8;
|
||||
unsigned16 base16, limit16, ubase16, ulimit16;
|
||||
|
||||
/* save the base address values */
|
||||
memcpy( &addrhold, &astart, sizeof(struct _addr_start));
|
||||
|
||||
recursive_bus_reconfigure( childbus );
|
||||
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: configuring bus %d bridge (%04x:%04x), bus %d : (%d-%d)\n",
|
||||
pdev->bus->number,
|
||||
pdev->vendor,
|
||||
pdev->device,
|
||||
childbus->primary,
|
||||
childbus->secondary,
|
||||
childbus->subordinate );
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
**use the current values & the saved ones to figure out
|
||||
** the address spaces for the bridge
|
||||
*/
|
||||
|
||||
if( addrhold.start_pciio == astart.start_pciio )
|
||||
{
|
||||
base8 = limit8 = 0xff;
|
||||
ubase16 = ulimit16 = 0xffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
base8 = (unsigned8) ((addrhold.start_pciio >> 8) & 0xf0);
|
||||
ubase16 = (unsigned16)(addrhold.start_pciio >> 16);
|
||||
limit8 = (unsigned8) ((astart.start_pciio >> 8 ) & 0xf0);
|
||||
ulimit16 = (unsigned16)(astart.start_pciio >> 16);
|
||||
astart.start_pciio += 0x1000;
|
||||
}
|
||||
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: io base %08x limit %08x\n", (base8<<8)+(ubase16<<16), (limit8<<8)+(ulimit16<<16));
|
||||
#endif
|
||||
#ifdef WRITE_BRIDGE_IO
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_IO_BASE_UPPER16, ubase16 );
|
||||
pcibios_write_config_byte(pdev->bus->number, pdev->devfn, PCI_IO_BASE, base8 );
|
||||
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_IO_LIMIT_UPPER16, ulimit16 );
|
||||
pcibios_write_config_byte(pdev->bus->number, pdev->devfn, PCI_IO_LIMIT, limit8 );
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
if( addrhold.start_pcimem == astart.start_pcimem )
|
||||
{
|
||||
limit16 = 0;
|
||||
base16 = 0xffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
limit16= (unsigned16)((astart.start_pcimem >> 16) & 0xfff0);
|
||||
base16 = (unsigned16)((addrhold.start_pcimem >> 16) & 0xfff0);
|
||||
astart.start_pcimem += 0x100000;
|
||||
}
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: memory %04x, limit %04x\n", base16, limit16);
|
||||
#endif
|
||||
#ifdef WRITE_BRIDGE_MEM
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_MEMORY_BASE, base16 );
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_MEMORY_LIMIT, limit16 );
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if( astart.start_prefetch == addrhold.start_prefetch )
|
||||
{
|
||||
limit16 = 0;
|
||||
base16 = 0xffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
limit16= (unsigned16)((addrhold.start_prefetch >> 16) & 0xfff0);
|
||||
base16 = (unsigned16)((astart.start_prefetch >> 16) & 0xfff0);
|
||||
astart.start_prefetch -= 0x100000;
|
||||
}
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: pf memory %04x, limit %04x\n", base16, limit16);
|
||||
#endif
|
||||
#ifdef WRITE_BRIDGE_PF
|
||||
pcibios_write_config_dword(pdev->bus->number, pdev->devfn, PCI_PREF_BASE_UPPER32, 0);
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_PREF_MEMORY_BASE, base16 );
|
||||
pcibios_write_config_dword(pdev->bus->number, pdev->devfn, PCI_PREF_LIMIT_UPPER32, 0);
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_PREF_MEMORY_LIMIT, limit16 );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WRITE_BRIDGE_ENABLE
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_BRIDGE_CONTROL, (unsigned16)( PCI_BRIDGE_CTL_PARITY |
|
||||
PCI_BRIDGE_CTL_SERR |
|
||||
PCI_BRIDGE_CTL_FAST_BACK));
|
||||
|
||||
pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_COMMAND, (unsigned16)( PCI_COMMAND_IO |
|
||||
PCI_COMMAND_MEMORY |
|
||||
PCI_COMMAND_MASTER |
|
||||
PCI_COMMAND_PARITY |
|
||||
PCI_COMMAND_WAIT |
|
||||
PCI_COMMAND_SERR |
|
||||
PCI_COMMAND_FAST_BACK ));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if( !isroot )
|
||||
{
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: Configuring devices on bus %d\n", pbus->number);
|
||||
#endif
|
||||
/*
|
||||
** Run thru this bus and set up addresses for all the non-bridge devices
|
||||
*/
|
||||
for( pdev = pbus->devices; pdev; pdev= pdev->sibling )
|
||||
{
|
||||
if( (pdev->class >> 8) != PCI_CLASS_BRIDGE_PCI )
|
||||
{
|
||||
pci_resource *r;
|
||||
int i = 0;
|
||||
unsigned alloc;
|
||||
|
||||
/* enumerate all the resources defined by this device & reserve space
|
||||
** for each of their defined regions.
|
||||
*/
|
||||
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: configuring; vendor %04x, device %04x\n", pdev->vendor, pdev->device );
|
||||
#endif
|
||||
|
||||
while( (r= enum_device_resources( pdev, i++ )) )
|
||||
{
|
||||
if( r->type & PCI_BASE_ADDRESS_MEM_PREFETCH )
|
||||
{
|
||||
/* prefetchable space */
|
||||
|
||||
/* shift base pointer down to an integer multiple of the size of the desired region */
|
||||
astart.start_prefetch -= (alloc= ((r->size / PAGE_SIZE) + 1) * PAGE_SIZE);
|
||||
/* shift base pointer down to an integer multiple of the size of the desired region */
|
||||
astart.start_prefetch = (astart.start_prefetch / r->size) * r->size;
|
||||
|
||||
r->base = astart.start_prefetch;
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: pf %08X, size %08X, alloc %08X\n", r->base, r->size, alloc );
|
||||
#endif
|
||||
}
|
||||
else if( r->type & PCI_BASE_ADDRESS_SPACE_IO )
|
||||
{
|
||||
/* io space */
|
||||
|
||||
/* shift base pointer up to an integer multiple of the size of the desired region */
|
||||
if( astart.start_pciio % r->size )
|
||||
astart.start_pciio = (((astart.start_pciio / r->size) + 1) * r->size);
|
||||
|
||||
r->base = astart.start_pciio;
|
||||
astart.start_pciio += (alloc= ((r->size / MEMORY_IO_GRANULARITY) + 1) * MEMORY_IO_GRANULARITY);
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: io %08X, size %08X, alloc %08X\n", r->base, r->size, alloc );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* memory space */
|
||||
|
||||
/* shift base pointer up to an integer multiple of the size of the desired region */
|
||||
if( astart.start_pcimem % r->size )
|
||||
astart.start_pcimem = (((astart.start_pcimem / r->size) + 1) * r->size);
|
||||
|
||||
r->base = astart.start_pcimem;
|
||||
astart.start_pcimem += (alloc= ((r->size / MEMORY_IO_GRANULARITY) + 1) * MEMORY_IO_GRANULARITY);
|
||||
#ifdef PCI_DEBUG
|
||||
printk("pci: mem %08X, size %08X, alloc %08X\n", r->base, r->size, alloc );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
PPC_DEVICE *hostbridge;
|
||||
|
||||
if (pci->last_dev_p) {
|
||||
@@ -925,8 +1401,14 @@ void pci_init(void) {
|
||||
/* Now build a small database of all found PCI devices */
|
||||
printk("\nPCI: Probing PCI hardware\n");
|
||||
pci_root.subordinate=pci_scan_bus(&pci_root);
|
||||
print_pci_resources("Configurable PCI resources:\n");
|
||||
|
||||
print_pci_resources("Installed PCI resources:\n");
|
||||
|
||||
recursive_bus_reconfigure(NULL);
|
||||
reconfigure_pci();
|
||||
|
||||
print_pci_resources("Allocated PCI resources:\n");
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
|
||||
@@ -118,6 +118,70 @@ static int isValidInterrupt(int irq)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ------------------------ RTEMS Shared Irq Handler Mngt Routines ----------------
|
||||
*/
|
||||
int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq)
|
||||
{
|
||||
unsigned int level;
|
||||
rtems_irq_connect_data* vchain;
|
||||
|
||||
if (!isValidInterrupt(irq->name)) {
|
||||
printk("Invalid interrupt vector %i\n",irq->name);
|
||||
return 0;
|
||||
}
|
||||
if ( (int)rtems_hdl_tbl[irq->name].next_handler == -1 ) {
|
||||
printk("IRQ vector %i already connected to an unshared handler\n",irq->name);
|
||||
return 0;
|
||||
}
|
||||
_CPU_ISR_Disable(level);
|
||||
|
||||
|
||||
vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
|
||||
|
||||
/* save off topmost handler */
|
||||
vchain[0]= rtems_hdl_tbl[irq->name];
|
||||
|
||||
/*
|
||||
* store the data provided by user
|
||||
*/
|
||||
rtems_hdl_tbl[irq->name] = *irq;
|
||||
|
||||
/* link chain to new topmost handler */
|
||||
rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
|
||||
|
||||
|
||||
if (is_isa_irq(irq->name)) {
|
||||
/*
|
||||
* Enable interrupt at PIC level
|
||||
*/
|
||||
BSP_irq_enable_at_i8259s (irq->name);
|
||||
}
|
||||
|
||||
if (is_pci_irq(irq->name)) {
|
||||
/*
|
||||
* Enable interrupt at OPENPIC level
|
||||
*/
|
||||
openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||
}
|
||||
|
||||
if (is_processor_irq(irq->name)) {
|
||||
/*
|
||||
* Enable exception at processor level
|
||||
*/
|
||||
}
|
||||
/*
|
||||
* Enable interrupt on device
|
||||
*/
|
||||
irq->on(irq);
|
||||
|
||||
_CPU_ISR_Enable(level);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
|
||||
*/
|
||||
@@ -147,6 +211,7 @@ int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||
* store the data provided by user
|
||||
*/
|
||||
rtems_hdl_tbl[irq->name] = *irq;
|
||||
rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
|
||||
|
||||
if (is_isa_irq(irq->name)) {
|
||||
/*
|
||||
@@ -189,6 +254,7 @@ int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq)
|
||||
|
||||
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||
{
|
||||
rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
|
||||
unsigned int level;
|
||||
|
||||
if (!isValidInterrupt(irq->name)) {
|
||||
@@ -206,6 +272,35 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||
}
|
||||
_CPU_ISR_Disable(level);
|
||||
|
||||
if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
|
||||
(vchain->hdl != default_rtems_entry.hdl);
|
||||
(pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
|
||||
{
|
||||
if( vchain->hdl == irq->hdl )
|
||||
{
|
||||
found= -1; break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !found )
|
||||
{
|
||||
_CPU_ISR_Enable(level);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rtems_hdl_tbl[irq->name].hdl != irq->hdl)
|
||||
{
|
||||
_CPU_ISR_Enable(level);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_isa_irq(irq->name)) {
|
||||
/*
|
||||
* disable interrupt at PIC level
|
||||
@@ -232,7 +327,27 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||
/*
|
||||
* restore the default irq value
|
||||
*/
|
||||
if( !vchain )
|
||||
{
|
||||
/* single handler vector... */
|
||||
rtems_hdl_tbl[irq->name] = default_rtems_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pchain )
|
||||
{
|
||||
/* non-first handler being removed */
|
||||
pchain->next_handler = vchain->next_handler;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* first handler isn't malloc'ed, so just overwrite it. Since
|
||||
the contents of vchain are being struct copied, vchain itself
|
||||
goes away */
|
||||
rtems_hdl_tbl[irq->name]= *vchain;
|
||||
}
|
||||
free(vchain);
|
||||
}
|
||||
|
||||
_CPU_ISR_Enable(level);
|
||||
|
||||
@@ -266,10 +381,29 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
|
||||
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
|
||||
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||
BSP_irq_enable_at_i8259s (i);
|
||||
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
|
||||
|
||||
/* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[i];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->on(vchain);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
|
||||
/* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[i];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->off(vchain);
|
||||
}
|
||||
}
|
||||
BSP_irq_disable_at_i8259s (i);
|
||||
}
|
||||
}
|
||||
@@ -288,10 +422,30 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
|
||||
internal_config->irqPrioTbl[i]);
|
||||
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||
openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
|
||||
/* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[i];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->on(vchain);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
|
||||
/* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[i];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->off(vchain);
|
||||
}
|
||||
}
|
||||
|
||||
openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||
}
|
||||
}
|
||||
@@ -304,10 +458,30 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
|
||||
*/
|
||||
for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
|
||||
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
|
||||
/* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[i];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->on(vchain);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
|
||||
/* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[i];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->off(vchain);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
_CPU_ISR_Enable(level);
|
||||
@@ -373,7 +547,17 @@ void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
|
||||
new_msr = msr | MSR_EE;
|
||||
_CPU_MSR_SET(new_msr);
|
||||
|
||||
rtems_hdl_tbl[irq].hdl();
|
||||
/* rtems_hdl_tbl[irq].hdl(); */
|
||||
{
|
||||
rtems_irq_connect_data* vchain;
|
||||
for( vchain = &rtems_hdl_tbl[irq];
|
||||
((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
|
||||
vchain = (rtems_irq_connect_data*)vchain->next_handler )
|
||||
{
|
||||
vchain->hdl();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_CPU_MSR_SET(msr);
|
||||
|
||||
|
||||
@@ -175,6 +175,11 @@ typedef struct __rtems_irq_connect_data__ {
|
||||
* if someone manipulates the i8259s interrupt mask without care...
|
||||
*/
|
||||
rtems_irq_is_enabled isOn;
|
||||
/*
|
||||
* Set to -1 for vectors forced to have only 1 handler
|
||||
*/
|
||||
void *next_handler;
|
||||
|
||||
}rtems_irq_connect_data;
|
||||
|
||||
typedef struct {
|
||||
@@ -276,6 +281,10 @@ int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine);
|
||||
*
|
||||
*/
|
||||
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data*);
|
||||
int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data*);
|
||||
|
||||
#define BSP_SHARED_HANDLER_SUPPORT 1
|
||||
|
||||
/*
|
||||
* function to get the current RTEMS irq handler for ptr->name. It enables to
|
||||
* define hanlder chain...
|
||||
|
||||
@@ -18,6 +18,137 @@
|
||||
#include <libcpu/io.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
** Board-specific table that maps interrupt names to onboard pci
|
||||
** peripherals as well as local pci busses. This table is used at
|
||||
** bspstart() to configure the interrupt name & pin for all devices that
|
||||
** do not have it already specified. If the device is already
|
||||
** configured, we leave it alone but sanity check & print a warning if
|
||||
** we don't know about the pin/line the card gives us.
|
||||
**
|
||||
** bus = the bus number of the slot/device in question
|
||||
**
|
||||
** slot :
|
||||
**
|
||||
** If slot != -1, it indicates a device on the given bus in that slot
|
||||
** is to use one of the listed interrupt names given an interrupt pin.
|
||||
**
|
||||
** If slot == -1, it means devices on this bus can occupy any slot-
|
||||
** and for pci, this means the particular interrupt pin that the
|
||||
** device signals is therefore dependent on the particular slot. To
|
||||
** work from the slot to the interrupt pin, the swizzle table is used.
|
||||
** Once the bus and interrupt pin is known, the correct interrupt name
|
||||
** can be pulled from the table. The swizzle table relates the
|
||||
** interrupt pin from the device to the particular interrupt
|
||||
** controller interrupt pin- so it is quite reasonable for a device on
|
||||
** bus 1 signalling interrupt pin 1 to show up at the interrupt
|
||||
** controller as pin 4- this is why the int pin field varies for
|
||||
** bridged pci busses.
|
||||
**
|
||||
**
|
||||
** opts = bitmap of options that control the configuration of this
|
||||
** slot/bus.
|
||||
**
|
||||
** pin_routes[] = array of pin & vectors that may serve this slot;
|
||||
**
|
||||
** pin = the pin # which delivers an interrupt on this route, A=1,
|
||||
** B=2, C=3, D=4
|
||||
**
|
||||
** int_name[4] = an array of up to 4 bsp-specific interrupt name
|
||||
** that can be used by this route. Unused entries should be -1.
|
||||
** The array is of primary use for slots that can be vectored thru
|
||||
** multiple interrupt lines over the interrupt pin supplied by the
|
||||
** record. If more than one entry is present, the most preferable
|
||||
** should supplied first.
|
||||
**
|
||||
*/
|
||||
|
||||
#define NULL_PINMAP {-1,{-1,-1,-1,-1}}
|
||||
#define NULL_INTMAP {-1,-1,-1,{}}
|
||||
|
||||
|
||||
|
||||
static struct _int_map mcp750_intmap[] = {
|
||||
|
||||
{ 0, 16, 0, {{1, {5, 19,-1,-1}}, /* pmc slot */
|
||||
NULL_PINMAP}},
|
||||
|
||||
{ 0, 14, 0, {{1, {10,18,-1,-1}}, /* onboard ethernet */
|
||||
NULL_PINMAP}},
|
||||
|
||||
{ 1, -1, 0, {{1, {24,-1,-1,-1}},
|
||||
{2, {25,-1,-1,-1}},
|
||||
{3, {26,-1,-1,-1}},
|
||||
{4, {27,-1,-1,-1}},
|
||||
NULL_PINMAP}},
|
||||
|
||||
NULL_INTMAP };
|
||||
|
||||
|
||||
|
||||
|
||||
static struct _int_map mtx603_intmap[] = {
|
||||
|
||||
{0, 14, 0, {{1, {10,16,-1,-1}}, /* onboard ethernet */
|
||||
NULL_PINMAP}},
|
||||
|
||||
{0, 12, 0, {{1, {14,18,-1,-1}}, /* onboard scsi */
|
||||
NULL_PINMAP}},
|
||||
|
||||
{0, 16, 0, {{1, {25,-1,-1,-1}}, /* pci/pmc slot 1 */
|
||||
{2, {26,-1,-1,-1}},
|
||||
{3, {27,-1,-1,-1}},
|
||||
{4, {28,-1,-1,-1}},
|
||||
NULL_PINMAP}},
|
||||
|
||||
{0, 17, 0, {{1, {26,-1,-1,-1}}, /* pci/pmc slot 2 */
|
||||
{2, {27,-1,-1,-1}},
|
||||
{3, {28,-1,-1,-1}},
|
||||
{4, {25,-1,-1,-1}},
|
||||
NULL_PINMAP}},
|
||||
|
||||
{0, 18, 0, {{1, {27,-1,-1,-1}}, /* pci slot 3 */
|
||||
{2, {28,-1,-1,-1}},
|
||||
{3, {25,-1,-1,-1}},
|
||||
{4, {26,-1,-1,-1}},
|
||||
NULL_PINMAP}},
|
||||
|
||||
NULL_INTMAP };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This table represents the standard PCI swizzle defined in the
|
||||
* PCI bus specification. Table taken from Linux 2.4.18, prep_pci.c,
|
||||
* the values in this table are interrupt_pin values (1 based).
|
||||
*/
|
||||
static unsigned char prep_pci_intpins[4][4] =
|
||||
{
|
||||
{ 1, 2, 3, 4 }, /* Buses 0, 4, 8, ... */
|
||||
{ 2, 3, 4, 1 }, /* Buses 1, 5, 9, ... */
|
||||
{ 3, 4, 1, 2 }, /* Buses 2, 6, 10 ... */
|
||||
{ 4, 1, 2, 3 }, /* Buses 3, 7, 11 ... */
|
||||
};
|
||||
|
||||
static int prep_pci_swizzle(int slot, int pin)
|
||||
{
|
||||
return prep_pci_intpins[ slot % 4 ][ pin-1 ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* 0x100 mask assumes for Raven and Hawk boards
|
||||
@@ -27,33 +158,38 @@ typedef struct {
|
||||
int cpu_type;
|
||||
int base_type;
|
||||
const char *name;
|
||||
|
||||
struct _int_map *intmap;
|
||||
int (*swizzler)(int, int);
|
||||
} mot_info_t;
|
||||
|
||||
|
||||
static const mot_info_t mot_boards[] = {
|
||||
{0x300, 0x00, "MVME 2400"},
|
||||
{0x010, 0x00, "Genesis"},
|
||||
{0x020, 0x00, "Powerstack (Series E)"},
|
||||
{0x040, 0x00, "Blackhawk (Powerstack)"},
|
||||
{0x050, 0x00, "Omaha (PowerStack II Pro3000)"},
|
||||
{0x060, 0x00, "Utah (Powerstack II Pro4000)"},
|
||||
{0x0A0, 0x00, "Powerstack (Series EX)"},
|
||||
{0x1E0, 0xE0, "Mesquite cPCI (MCP750)"},
|
||||
{0x1E0, 0xE1, "Sitka cPCI (MCPN750)"},
|
||||
{0x1E0, 0xE2, "Mesquite cPCI (MCP750) w/ HAC"},
|
||||
{0x1E0, 0xF6, "MTX Plus"},
|
||||
{0x1E0, 0xF7, "MTX w/o Parallel Port"},
|
||||
{0x1E0, 0xF8, "MTX w/ Parallel Port"},
|
||||
{0x1E0, 0xF9, "MVME 2300"},
|
||||
{0x1E0, 0xFA, "MVME 2300SC/2600"},
|
||||
{0x1E0, 0xFB, "MVME 2600 with MVME712M"},
|
||||
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761"},
|
||||
{0x1E0, 0xFD, "MVME 3600 with MVME712M"},
|
||||
{0x1E0, 0xFE, "MVME 3600 with MVME761"},
|
||||
{0x1E0, 0xFF, "MVME 1600-001 or 1600-011"},
|
||||
{0x300, 0x00, "MVME 2400", NULL, NULL},
|
||||
{0x010, 0x00, "Genesis", NULL, NULL},
|
||||
{0x020, 0x00, "Powerstack (Series E)", NULL, NULL},
|
||||
{0x040, 0x00, "Blackhawk (Powerstack)", NULL, NULL},
|
||||
{0x050, 0x00, "Omaha (PowerStack II Pro3000)", NULL, NULL},
|
||||
{0x060, 0x00, "Utah (Powerstack II Pro4000)", NULL, NULL},
|
||||
{0x0A0, 0x00, "Powerstack (Series EX)", NULL, NULL},
|
||||
{0x1E0, 0xE0, "Mesquite cPCI (MCP750)", mcp750_intmap, prep_pci_swizzle},
|
||||
{0x1E0, 0xE1, "Sitka cPCI (MCPN750)", mcp750_intmap, prep_pci_swizzle},
|
||||
{0x1E0, 0xE2, "Mesquite cPCI (MCP750) w/ HAC", mcp750_intmap, prep_pci_swizzle},
|
||||
{0x1E0, 0xF6, "MTX Plus", NULL, NULL},
|
||||
{0x1E0, 0xF7, "MTX w/o Parallel Port", mtx603_intmap, prep_pci_swizzle},
|
||||
{0x1E0, 0xF8, "MTX w/ Parallel Port", mtx603_intmap, prep_pci_swizzle},
|
||||
{0x1E0, 0xF9, "MVME 2300", NULL, NULL},
|
||||
{0x1E0, 0xFA, "MVME 2300SC/2600", NULL, NULL},
|
||||
{0x1E0, 0xFB, "MVME 2600 with MVME712M", NULL, NULL},
|
||||
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761", NULL, NULL},
|
||||
{0x1E0, 0xFD, "MVME 3600 with MVME712M", NULL, NULL},
|
||||
{0x1E0, 0xFE, "MVME 3600 with MVME761", NULL, NULL},
|
||||
{0x1E0, 0xFF, "MVME 1600-001 or 1600-011", NULL, NULL},
|
||||
{0x000, 0x00, ""}
|
||||
};
|
||||
|
||||
|
||||
|
||||
prep_t currentPrepType;
|
||||
motorolaBoard currentBoard;
|
||||
prep_t checkPrepBoardType(RESIDUAL *res)
|
||||
@@ -114,9 +250,24 @@ motorolaBoard getMotorolaBoard()
|
||||
return currentBoard;
|
||||
}
|
||||
|
||||
|
||||
const char* motorolaBoardToString(motorolaBoard board)
|
||||
{
|
||||
if (board == MOTOROLA_UNKNOWN) return "Unknown motorola board";
|
||||
return (mot_boards[board].name);
|
||||
}
|
||||
|
||||
|
||||
const struct _int_map *motorolaIntMap(motorolaBoard board)
|
||||
{
|
||||
if (board == MOTOROLA_UNKNOWN) return NULL;
|
||||
return mot_boards[board].intmap;
|
||||
}
|
||||
|
||||
|
||||
const void *motorolaIntSwizzle(motorolaBoard board)
|
||||
{
|
||||
if (board == MOTOROLA_UNKNOWN) return NULL;
|
||||
return (void *)mot_boards[board].swizzler;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
#define LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H
|
||||
|
||||
#include <bsp/residual.h>
|
||||
#include <bsp/pci.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
PREP_IBM = 0,
|
||||
@@ -61,6 +69,8 @@ extern prep_t currentPrepType;
|
||||
extern motorolaBoard getMotorolaBoard();
|
||||
extern motorolaBoard currentBoard;
|
||||
extern const char* motorolaBoardToString(motorolaBoard);
|
||||
extern const struct _int_map *motorolaIntMap(motorolaBoard board);
|
||||
extern const void *motorolaIntSwizzle(motorolaBoard board);
|
||||
|
||||
|
||||
#endif /* LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H */
|
||||
|
||||
@@ -216,6 +216,320 @@ const pci_config_access_functions pci_direct_functions = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define PRINT_MSG() \
|
||||
printk("pci : Device %d:%02x routed to interrupt_line %d\n", pbus, pslot, int_name )
|
||||
|
||||
|
||||
/*
|
||||
** Validate a test interrupt name and print a warning if its not one of
|
||||
** the names defined in the routing record.
|
||||
*/
|
||||
static int test_intname( struct _int_map *row, int pbus, int pslot, int int_pin, int int_name )
|
||||
{
|
||||
int j,k;
|
||||
int _nopin= -1, _noname= -1;
|
||||
|
||||
for(j=0; row->pin_route[j].pin > -1; j++)
|
||||
{
|
||||
if( row->pin_route[j].pin == int_pin )
|
||||
{
|
||||
_nopin = 0;
|
||||
|
||||
for(k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ )
|
||||
{
|
||||
if( row->pin_route[j].int_name[k] == int_name ){ _noname=0; break; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( _nopin )
|
||||
{
|
||||
printk("pci : Device %d:%02x supplied a bogus interrupt_pin %d\n", pbus, pslot, int_pin );
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( _noname )
|
||||
printk("pci : Device %d:%02x supplied a suspicious interrupt_line %d, using it anyway\n", pbus, pslot, int_name );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct pcibridge
|
||||
{
|
||||
int bus,slot;
|
||||
};
|
||||
|
||||
|
||||
static int FindPCIbridge( int mybus, struct pcibridge *pb )
|
||||
{
|
||||
int pbus, pslot;
|
||||
unsigned8 bussec, buspri;
|
||||
unsigned16 devid, vendorid, dclass;
|
||||
|
||||
for(pbus=0; pbus< BusCountPCI(); pbus++)
|
||||
{
|
||||
for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
|
||||
{
|
||||
pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
|
||||
if( devid == 0xffff ) continue;
|
||||
|
||||
pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
|
||||
if( vendorid == 0xffff ) continue;
|
||||
|
||||
pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
|
||||
|
||||
if( dclass == PCI_CLASS_BRIDGE_PCI )
|
||||
{
|
||||
pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS, &buspri);
|
||||
pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS, &bussec);
|
||||
|
||||
#if 0
|
||||
printk("pci : Found bridge at %d:%d, mybus %d, pribus %d, secbus %d ", pbus, pslot, mybus, buspri, bussec );
|
||||
#endif
|
||||
if( bussec == mybus )
|
||||
{
|
||||
#if 0
|
||||
printk("match\n");
|
||||
#endif
|
||||
/* found our nearest bridge going towards the root */
|
||||
pb->bus = pbus;
|
||||
pb->slot = pslot;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
printk("no match\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void FixupPCI( struct _int_map *bspmap, int (*swizzler)(int,int) )
|
||||
{
|
||||
unsigned char cvalue;
|
||||
unsigned16 devid;
|
||||
int ismatch, i, j, pbus, pslot, int_pin, int_name;
|
||||
|
||||
/*
|
||||
** If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
|
||||
** INTERRUPT_NAME if one isn't already in place. Then, drivers can
|
||||
** trivially use INTERRUPT_NAME to hook up with devices.
|
||||
*/
|
||||
|
||||
for(pbus=0; pbus< BusCountPCI(); pbus++)
|
||||
{
|
||||
for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
|
||||
{
|
||||
pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
|
||||
if( devid == 0xffff ) continue;
|
||||
|
||||
/* got a device */
|
||||
|
||||
pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_PIN, &cvalue);
|
||||
int_pin = cvalue;
|
||||
|
||||
pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_LINE, &cvalue);
|
||||
int_name = cvalue;
|
||||
|
||||
/* printk("pci : device %d:%02x devid %04x, intpin %d, intline %d\n", pbus, pslot, devid, int_pin, int_name ); */
|
||||
|
||||
if( int_pin > 0 )
|
||||
{
|
||||
ismatch = 0;
|
||||
|
||||
/*
|
||||
** first run thru the bspmap table and see if we have an explicit configuration
|
||||
*/
|
||||
for(i=0; bspmap[i].bus > -1; i++)
|
||||
{
|
||||
if( bspmap[i].bus == pbus && bspmap[i].slot == pslot )
|
||||
{
|
||||
ismatch = -1;
|
||||
/* we have a record in the table that gives specific
|
||||
* pins and interrupts for devices in this slot */
|
||||
if( int_name == 255 )
|
||||
{
|
||||
/* find the vector associated with whatever pin the device gives us */
|
||||
for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
|
||||
{
|
||||
if( bspmap[i].pin_route[j].pin == int_pin )
|
||||
{
|
||||
int_name = bspmap[i].pin_route[j].int_name[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( int_name == -1 )
|
||||
{
|
||||
printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %i to an interrupt_line.\n", pbus, pslot, int_pin );
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_MSG();
|
||||
pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
test_intname( &bspmap[i],pbus,pslot,int_pin,int_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( !ismatch )
|
||||
{
|
||||
/*
|
||||
** no match, which means we're on a bus someplace. Work
|
||||
** backwards from it to one of our defined busses,
|
||||
** swizzling thru each bridge on the way.
|
||||
*/
|
||||
|
||||
/* keep pbus, pslot pointed to the device being
|
||||
configured while we track down the bridges using
|
||||
tbus,tslot. We keep searching the routing table because
|
||||
we may end up finding our bridge in it */
|
||||
|
||||
int tbus= pbus, tslot= pslot;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
for(i=0; bspmap[i].bus > -1; i++)
|
||||
{
|
||||
if( bspmap[i].bus == tbus && (bspmap[i].slot == tslot || bspmap[i].slot == -1) )
|
||||
{
|
||||
ismatch = -1;
|
||||
/* found a record for this bus, so swizzle the
|
||||
* int_pin which we then use to find the
|
||||
* interrupt_name.
|
||||
*/
|
||||
|
||||
if( int_name == 255 )
|
||||
{
|
||||
/*
|
||||
** FIXME. I can't believe this little hack
|
||||
** is right. It does not yield an error in
|
||||
** convienently simple situations.
|
||||
*/
|
||||
if( tbus ) int_pin = (*swizzler)(tslot,int_pin);
|
||||
|
||||
|
||||
/*
|
||||
** int_pin points to the interrupt channel
|
||||
** this card ends up delivering interrupts
|
||||
** on. Find the int_name servicing it.
|
||||
*/
|
||||
for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
|
||||
{
|
||||
if( bspmap[i].pin_route[j].pin == int_pin )
|
||||
{
|
||||
int_name = bspmap[i].pin_route[j].int_name[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( int_name == -1 )
|
||||
{
|
||||
printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %i to an interrupt_line.\n", pbus, pslot, int_pin );
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_MSG();
|
||||
pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
test_intname(&bspmap[i],pbus,pslot,int_pin,int_name);
|
||||
}
|
||||
goto donesearch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( !ismatch )
|
||||
{
|
||||
struct pcibridge pb;
|
||||
|
||||
/*
|
||||
** Haven't found our bus in the int map, so work
|
||||
** upwards thru the bridges till we find it.
|
||||
*/
|
||||
|
||||
if( FindPCIbridge( tbus, &pb )== 0 )
|
||||
{
|
||||
int_pin = (*swizzler)(tslot,int_pin);
|
||||
|
||||
/* our next bridge up is on pb.bus, pb.slot- now
|
||||
** instead of pointing to the device we're
|
||||
** trying to configure, we move from bridge to
|
||||
** bridge.
|
||||
*/
|
||||
|
||||
tbus = pb.bus;
|
||||
tslot = pb.slot;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk("pci : No bridge from bus %i towards root found\n", tbus );
|
||||
goto donesearch;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
donesearch:
|
||||
|
||||
|
||||
if( !ismatch && int_pin != 0 && int_name == 255 )
|
||||
{
|
||||
printk("pci : Unable to match device %d:%d with an int routing table entry\n", pbus, pslot );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This routine determines the maximum bus number in the system
|
||||
*/
|
||||
@@ -228,6 +542,7 @@ void InitializePCI()
|
||||
unsigned int ulClass, ulDeviceID;
|
||||
|
||||
detect_host_bridge();
|
||||
|
||||
/*
|
||||
* Scan PCI bus 0 looking for PCI-PCI bridges
|
||||
*/
|
||||
|
||||
@@ -1153,6 +1153,20 @@ pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char func
|
||||
extern unsigned char BusCountPCI();
|
||||
extern void InitializePCI();
|
||||
|
||||
|
||||
struct _pin_routes
|
||||
{
|
||||
int pin, int_name[4];
|
||||
};
|
||||
struct _int_map
|
||||
{
|
||||
int bus, slot, opts;
|
||||
struct _pin_routes pin_route[5];
|
||||
};
|
||||
|
||||
void FixupPCI( struct _int_map *, int (*swizzler)(int,int) );
|
||||
|
||||
|
||||
/* scan for a specific device */
|
||||
/* find a particular PCI device
|
||||
* (currently, only bus0 is scanned for device/fun0)
|
||||
|
||||
@@ -37,7 +37,7 @@ unsigned char bus,dev,fun,hd;
|
||||
if (PCI_INVALID_VENDORDEVICEID == d)
|
||||
continue;
|
||||
#ifdef PCI_DEBUG
|
||||
printk("BSP_pciFindDevice: found 0x%08x at %i/%i/%i\n",d,bus,dev,fun);
|
||||
printk("BSP_pciFindDevice: found 0x%08x at %d/%d/%d\n",d,bus,dev,fun);
|
||||
#endif
|
||||
(void) pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
|
||||
if (vendorid != s)
|
||||
|
||||
@@ -253,7 +253,7 @@ void bsp_start( void )
|
||||
* provided by the RAVEN
|
||||
*/
|
||||
/* T. Straumann: give more PCI address space */
|
||||
setdbat(2, PCI_MEM_BASE, PCI_MEM_BASE, 0x10000000, IO_PAGE);
|
||||
setdbat(2, PCI_MEM_BASE, PCI_MEM_BASE, 0x30000000, IO_PAGE);
|
||||
/*
|
||||
* Must have acces to open pic PCI ACK registers
|
||||
* provided by the RAVEN
|
||||
@@ -300,6 +300,21 @@ void bsp_start( void )
|
||||
printk("Going to start PCI buses scanning and initialization\n");
|
||||
#endif
|
||||
InitializePCI();
|
||||
|
||||
{
|
||||
struct _int_map *bspmap = motorolaIntMap(currentBoard);
|
||||
if( bspmap )
|
||||
{
|
||||
printk("pci : Configuring interrupt routing for '%s'\n", motorolaBoardToString(currentBoard));
|
||||
FixupPCI(bspmap, motorolaIntSwizzle(currentBoard) );
|
||||
}
|
||||
else
|
||||
printk("pci : Interrupt routing not available for this bsp\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef SHOW_MORE_INIT_SETTINGS
|
||||
printk("Number of PCI buses found is : %d\n", BusCountPCI());
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user