summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2003-06-13 17:39:46 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2003-06-13 17:39:46 +0000
commit3a3e0b0e7de69486aac8a76237de7c4276f36797 (patch)
treef13b32d8274e826abb388b785593f7a8311eb2c6 /c/src/lib/libbsp/powerpc
parentChanged format so script will see PR number. (diff)
downloadrtems-3a3e0b0e7de69486aac8a76237de7c4276f36797.tar.bz2
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.
Diffstat (limited to 'c/src/lib/libbsp/powerpc')
-rw-r--r--c/src/lib/libbsp/powerpc/shared/ChangeLog17
-rw-r--r--c/src/lib/libbsp/powerpc/shared/bootloader/README8
-rw-r--r--c/src/lib/libbsp/powerpc/shared/bootloader/pci.c1904
-rw-r--r--c/src/lib/libbsp/powerpc/shared/irq/irq.c208
-rw-r--r--c/src/lib/libbsp/powerpc/shared/irq/irq.h73
-rw-r--r--c/src/lib/libbsp/powerpc/shared/motorola/motorola.c197
-rw-r--r--c/src/lib/libbsp/powerpc/shared/motorola/motorola.h10
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/pci.c315
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/pci.h14
-rw-r--r--c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c2
-rw-r--r--c/src/lib/libbsp/powerpc/shared/startup/bspstart.c17
11 files changed, 1985 insertions, 780 deletions
diff --git a/c/src/lib/libbsp/powerpc/shared/ChangeLog b/c/src/lib/libbsp/powerpc/shared/ChangeLog
index f292edd127..066a7699ef 100644
--- a/c/src/lib/libbsp/powerpc/shared/ChangeLog
+++ b/c/src/lib/libbsp/powerpc/shared/ChangeLog
@@ -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
diff --git a/c/src/lib/libbsp/powerpc/shared/bootloader/README b/c/src/lib/libbsp/powerpc/shared/bootloader/README
index 6d36a152ba..b4984e190f 100644
--- a/c/src/lib/libbsp/powerpc/shared/bootloader/README
+++ b/c/src/lib/libbsp/powerpc/shared/bootloader/README
@@ -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.
+
diff --git a/c/src/lib/libbsp/powerpc/shared/bootloader/pci.c b/c/src/lib/libbsp/powerpc/shared/bootloader/pci.c
index d698a31c56..4c0b4ce707 100644
--- a/c/src/lib/libbsp/powerpc/shared/bootloader/pci.c
+++ b/c/src/lib/libbsp/powerpc/shared/bootloader/pci.c
@@ -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*/
@@ -34,27 +37,27 @@ typedef unsigned int u32;
*/
typedef struct _pci_resource {
- struct _pci_resource *next;
- struct pci_dev *dev;
- u_long base; /* will be 64 bits on 64 bits machines */
- u_long size;
- u_char type; /* 1 is I/O else low order 4 bits of the memory type */
- u_char reg; /* Register # in conf space header */
- u_short cmd; /* Original cmd byte */
+ struct _pci_resource *next;
+ struct pci_dev *dev;
+ u_long base; /* will be 64 bits on 64 bits machines */
+ u_long size;
+ u_char type; /* 1 is I/O else low order 4 bits of the memory type */
+ u_char reg; /* Register # in conf space header */
+ u_short cmd; /* Original cmd byte */
} pci_resource;
typedef struct _pci_area {
- struct _pci_area *next;
- u_long start;
- u_long end;
- struct pci_bus *bus;
- u_int flags;
+ struct _pci_area *next;
+ u_long start;
+ u_long end;
+ struct pci_bus *bus;
+ u_int flags;
} pci_area;
typedef struct _pci_area_head {
- pci_area *head;
- u_long mask;
- int high; /* To allocate from top */
+ pci_area *head;
+ u_long mask;
+ int high; /* To allocate from top */
} pci_area_head;
#define PCI_AREA_PREFETCHABLE 0
@@ -62,20 +65,20 @@ typedef struct _pci_area_head {
#define PCI_AREA_IO 2
struct _pci_private {
- volatile u_int * config_addr;
- volatile u_char * config_data;
- struct pci_dev **last_dev_p;
- struct pci_bus pci_root;
- pci_resource *resources;
- pci_area_head io, mem;
+ volatile u_int * config_addr;
+ volatile u_char * config_data;
+ struct pci_dev **last_dev_p;
+ struct pci_bus pci_root;
+ pci_resource *resources;
+ pci_area_head io, mem;
} pci_private = {
- config_addr: NULL,
- config_data: (volatile u_char *) 0x80800000,
- last_dev_p: NULL,
- resources: NULL,
- io: {NULL, 0xfff, 0},
- mem: {NULL, 0xfffff, 0}
+ config_addr: NULL,
+ config_data: (volatile u_char *) 0x80800000,
+ last_dev_p: NULL,
+ resources: NULL,
+ io: {NULL, 0xfff, 0},
+ mem: {NULL, 0xfffff, 0}
};
#define pci ((struct _pci_private *)(bd->pci_private))
@@ -92,33 +95,44 @@ struct _pci_private {
#if defined(PCI_DEBUG)
static void
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)
- +0x10+p->reg*4,
- p->base,
- p->size,
- p->type);
- }
+ 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)
+ +0x10+p->reg*4,
+ 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);
+
+ }
}
static void
print_pci_area(pci_area *p) {
- for (; p; p=p->next) {
- printk(" %p:%p %p %08lx %08lx\n",
- p, p->next, p->bus, p->start, p->end);
- }
+ for (; p; p=p->next) {
+ printk(" %p:%p %p %08lx %08lx\n",
+ p, p->next, p->bus, p->start, p->end);
+ }
}
static void
print_pci_areas(const char *s) {
- printk("%s PCI I/O areas:\n",s);
- print_pci_area(pci->io.head);
- printk(" PCI memory areas:\n");
- print_pci_area(pci->mem.head);
+ printk("%s PCI I/O areas:\n",s);
+ print_pci_area(pci->io.head);
+ printk(" PCI memory areas:\n");
+ print_pci_area(pci->mem.head);
}
#else
#define print_pci_areas(x)
@@ -132,17 +146,17 @@ print_pci_areas(const char *s) {
*/
struct blacklist_entry {
- u_short vendor, device;
- u_char reg;
- u_long actual_size;
+ u_short vendor, device;
+ u_char reg;
+ u_long actual_size;
};
#define BLACKLIST(vid, did, breg, actual_size) \
{PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##vid##_##did, breg, actual_size}
static struct blacklist_entry blacklist[] = {
- BLACKLIST(S3, TRIO, 0, 0x04000000),
- {0xffff, 0, 0, 0}
+ BLACKLIST(S3, TRIO, 0, 0x04000000),
+ {0xffff, 0, 0, 0}
};
@@ -156,76 +170,88 @@ 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;
- if (AREA(e) != AREA(t)) return AREA(e)<AREA(t);
- return (e->size > t->size);
+ if (e->dev->bus->number != t->dev->bus->number)
+ return e->dev->bus->number > t->dev->bus->number;
+ if (AREA(e) != AREA(t)) return AREA(e)<AREA(t);
+ return (e->size > t->size);
}
+
+
+
+
static void insert_resource(pci_resource *r) {
- struct blacklist_entry *b;
- pci_resource *p;
- if (!r) return;
-
- /* First fixup in case we have a blacklist entry. Note that this
- * may temporarily leave a resource in an inconsistent state: with
- * (base & (size-1)) !=0. This is harmless.
- */
- for (b=blacklist; b->vendor!=0xffff; b++) {
- if ((r->dev->vendor==b->vendor) &&
- (r->dev->device==b->device) &&
- (r->reg==b->reg)) {
- r->size=b->actual_size;
- break;
- }
- }
+ struct blacklist_entry *b;
+ pci_resource *p;
+ if (!r) return;
+
+ /* First fixup in case we have a blacklist entry. Note that this
+ * may temporarily leave a resource in an inconsistent state: with
+ * (base & (size-1)) !=0. This is harmless.
+ */
+ for (b=blacklist; b->vendor!=0xffff; b++) {
+ if ((r->dev->vendor==b->vendor) &&
+ (r->dev->device==b->device) &&
+ (r->reg==b->reg)) {
+ r->size=b->actual_size;
+ break;
+ }
+ }
- /* Motorola NT firmware does not configure pci devices which are not
- * required for booting, others do. For now:
- * - allocated devices in the ISA range (64kB I/O, 16Mb memory)
- * but non zero base registers are left as is.
- * - all other registers, whether already allocated or not, are
- * reallocated unless they require an inordinate amount of
- * resources (>256 Mb for memory >64kB for I/O). These
- * devices with too large mapping requirements are simply ignored
- * and their bases are set to 0. This should disable the
- * corresponding decoders according to the PCI specification.
- * Many devices are buggy in this respect, however, but the
- * limits have hopefully been set high enough to avoid problems.
- */
-
- if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
- ? (r->base && r->base <0x10000)
- : (r->base && r->base <0x1000000)) {
- sfree(r);
- return;
- }
-
- if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
- ? (r->size >= 0x10000)
- : (r->size >= 0x10000000)) {
- r->size = 0;
- r->base = 0;
- }
-
- /* Now insert into the list sorting by
- * 1) decreasing bus number
- * 2) space: prefetchable memory, non-prefetchable and finally I/O
- * 3) decreasing size
- */
- if (!pci->resources || insert_before(r, pci->resources)) {
- r->next = pci->resources;
- pci->resources=r;
- } else {
- for (p=pci->resources; p->next; p=p->next) {
- if (insert_before(r, p->next)) break;
- }
- r->next=p->next;
- p->next=r;
- }
+ /* Motorola NT firmware does not configure pci devices which are not
+ * required for booting, others do. For now:
+ * - allocated devices in the ISA range (64kB I/O, 16Mb memory)
+ * but non zero base registers are left as is.
+ * - all other registers, whether already allocated or not, are
+ * reallocated unless they require an inordinate amount of
+ * resources (>256 Mb for memory >64kB for I/O). These
+ * devices with too large mapping requirements are simply ignored
+ * and their bases are set to 0. This should disable the
+ * corresponding decoders according to the PCI specification.
+ * Many devices are buggy in this respect, however, but the
+ * 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)
+ : (r->size >= 0x10000000)) {
+ r->size = 0;
+ r->base = 0;
+ }
+
+ /* Now insert into the list sorting by
+ * 1) decreasing bus number
+ * 2) space: prefetchable memory, non-prefetchable and finally I/O
+ * 3) decreasing size
+ */
+ if (!pci->resources || insert_before(r, pci->resources)) {
+ r->next = pci->resources;
+ pci->resources=r;
+ } else {
+ for (p=pci->resources; p->next; p=p->next) {
+ if (insert_before(r, p->next)) break;
+ }
+ r->next=p->next;
+ p->next=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.
@@ -234,699 +260,1155 @@ static void insert_resource(pci_resource *r) {
*/
static u_long find_range(u_char bus, u_char type,
- pci_resource **first,
- pci_resource **past, u_int *flags) {
- pci_resource *p;
- u_long total=0;
- u_int fl=0;
-
- 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) {
- 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
- * on 64 bits architectures
- */
- *flags = fl;
- return total;
+ pci_resource **first,
+ pci_resource **past, u_int *flags) {
+ pci_resource *p;
+ u_long total=0;
+ u_int fl=0;
+
+ 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)
+ {
+ 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
+ * on 64 bits architectures
+ */
+ *flags = fl;
+ 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;
- p = salloc(sizeof(pci_area));
- if (!p) return;
- h->head = p;
- p->next = NULL;
- p->start = (start+mask)&~mask;
- p->end = (end-mask)|mask;
- p->bus = NULL;
- h->mask = mask;
- h->high = high;
+ u_long end, u_int mask, int high) {
+ pci_area *p;
+ p = salloc(sizeof(pci_area));
+ if (!p) return;
+ h->head = p;
+ p->next = NULL;
+ p->start = (start+mask)&~mask;
+ p->end = (end-mask)|mask;
+ p->bus = NULL;
+ h->mask = mask;
+ h->high = high;
}
+
+
+
+
+
static void insert_area(pci_area_head *h, pci_area *p) {
- pci_area *q = h->head;
- if (!p) return;
- if (q && (q->start< p->start)) {
- for(;q->next && q->next->start<p->start; q = q->next);
- if ((q->end >= p->start) ||
- (q->next && p->end>=q->next->start)) {
- sfree(p);
- printk("Overlapping pci areas!\n");
- return;
- }
- p->next = q->next;
- q->next = p;
- } else { /* Insert at head */
- if (q && (p->end >= q->start)) {
- sfree(p);
- printk("Overlapping pci areas!\n");
- return;
- }
- p->next = q;
- h->head = p;
- }
+ pci_area *q = h->head;
+ if (!p) return;
+ if (q && (q->start< p->start)) {
+ for(;q->next && q->next->start<p->start; q = q->next);
+ if ((q->end >= p->start) ||
+ (q->next && p->end>=q->next->start)) {
+ sfree(p);
+ printk("Overlapping pci areas!\n");
+ return;
+ }
+ p->next = q->next;
+ q->next = p;
+ } else { /* Insert at head */
+ if (q && (p->end >= q->start)) {
+ sfree(p);
+ printk("Overlapping pci areas!\n");
+ return;
+ }
+ p->next = q;
+ h->head = p;
+ }
}
-static
-void remove_area(pci_area_head *h, pci_area *p) {
- pci_area *q = h->head;
- if (!p || !q) return;
- if (q==p) {
- h->head = q->next;
- return;
- }
- for(;q && q->next!=p; q=q->next);
- if (q) q->next=p->next;
+
+
+
+static
+void remove_area(pci_area_head *h, pci_area *p)
+{
+ pci_area *q = h->head;
+
+ if (!p || !q) return;
+ if (q==p)
+ {
+ h->head = q->next;
+ return;
+ }
+ for(;q && q->next!=p; q=q->next);
+ 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) {
- 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 */
- if (p->bus) continue;
- if ((p->end)>=l1 || (p->end)>=l2) from=p;
- if (from && !h->high) break;
- }
- if (!from) return NULL;
-
- split = salloc(sizeof(pci_area));
- new = salloc(sizeof(pci_area));
- /* If allocation of new succeeds then allocation of split has
- * also been successful (given the current mm algorithms) !
- */
- if (!new) {
- sfree(split);
- return NULL;
- }
- new->bus = bus;
- new->flags = flags;
- /* Now allocate pci_space taking alignment into account ! */
- 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;
- split->end = from->end;
- from->end = new->start-1;
- split->start = new->start+required;
- new->end = new->start+required-1;
- } 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;
- split->start = from->start;
- from->start = new->end+1;
- new->start = new->end+1-required;
- split->end = new->start-1;
- }
+ 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)
+ {
+ 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 */
+ if (p->bus) continue;
+ if ((p->end)>=l1 || (p->end)>=l2) from=p;
+ if (from && !h->high) break;
+ }
+ if (!from) return NULL;
+
+ split = salloc(sizeof(pci_area));
+ new = salloc(sizeof(pci_area));
+ /* If allocation of new succeeds then allocation of split has
+ * also been successful (given the current mm algorithms) !
+ */
+ if (!new) {
+ sfree(split);
+ return NULL;
+ }
+ new->bus = bus;
+ new->flags = flags;
+ /* Now allocate pci_space taking alignment into account ! */
+ 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;
+ split->end = from->end;
+ from->end = new->start-1;
+ split->start = new->start+required;
+ new->end = new->start+required-1;
+ }
+ 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;
+ split->start = from->start;
+ from->start = new->end+1;
+ new->start = new->end+1-required;
+ split->end = new->start-1;
+ }
- if (from->end+1 == from->start) remove_area(h, from);
- if (split->end+1 != split->start) {
- split->bus = NULL;
- insert_area(h, split);
- } else {
- sfree(split);
- }
- insert_area(h, new);
- print_pci_areas("alloc_area called:\n");
- return new;
+ if (from->end+1 == from->start) remove_area(h, from);
+ if (split->end+1 != split->start)
+ {
+ split->bus = NULL;
+ insert_area(h, split);
+ }
+ else
+ {
+ sfree(split);
+ }
+ insert_area(h, new);
+ print_pci_areas("alloc_area called:\n");
+ return new;
}
+
+
+
+
static inline
-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;
- } else {
- r->base = p->start;
- p->start += r->size;
- }
-}
-
-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) {
- alloc_space(&tmp, 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;
+ } else {
+ r->base = p->start;
+ p->start += r->size;
+ }
}
+
+
+
+
+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)
+ {
+ 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);
-
- /* First reconfigure the I/O space, this will be more
- * complex when there is more than 1 bus. And 64 bits
- * devices are another kind of problems.
- */
- reconfigure_bus_space(0, PCI_AREA_IO, &pci->io);
- reconfigure_bus_space(0, PCI_AREA_MEMORY, &pci->mem);
- reconfigure_bus_space(0, PCI_AREA_PREFETCHABLE, &pci->mem);
-
- /* Now we have to touch the configuration space of all
- * the devices to remap them better than they are right now.
- * This is done in 3 steps:
- * 1) first disable I/O and memory response of all devices
- * 2) modify the base registers
- * 3) restore the original PCI_COMMAND register.
- */
- for (r=pci->resources; r; r= r->next) {
- if (!r->dev->sysdata) {
- r->dev->sysdata=r;
- pci_read_config_word(r->dev, PCI_COMMAND, &r->cmd);
- pci_write_config_word(r->dev, PCI_COMMAND,
- r->cmd & ~(PCI_COMMAND_IO|
- PCI_COMMAND_MEMORY));
- }
- }
-
- for (r=pci->resources; r; r= r->next) {
- pci_write_config_dword(r->dev,
- PCI_BASE_ADDRESS_0+(r->reg<<2),
- r->base);
- if ((r->type&
- (PCI_BASE_ADDRESS_SPACE|
- PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
- (PCI_BASE_ADDRESS_SPACE_MEMORY|
- PCI_BASE_ADDRESS_MEM_TYPE_64)) {
- pci_write_config_dword(r->dev,
- PCI_BASE_ADDRESS_1+
- (r->reg<<2),
- 0);
- }
- }
- for (dev=bd->pci_devices; dev; dev= dev->next) {
- if (dev->sysdata) {
- pci_write_config_word(dev, PCI_COMMAND,
- ((pci_resource *)dev->sysdata)
- ->cmd);
- dev->sysdata=NULL;
- }
- }
+ 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
+ * devices are another kind of problems.
+ */
+ reconfigure_bus_space(0, PCI_AREA_IO, &pci->io);
+ reconfigure_bus_space(0, PCI_AREA_MEMORY, &pci->mem);
+ reconfigure_bus_space(0, PCI_AREA_PREFETCHABLE, &pci->mem);
+
+ /* Now we have to touch the configuration space of all
+ * the devices to remap them better than they are right now.
+ * This is done in 3 steps:
+ * 1) first disable I/O and memory response of all devices
+ * 2) modify the base registers
+ * 3) restore the original PCI_COMMAND register.
+ */
+ for (r=pci->resources; r; r= r->next) {
+ if (!r->dev->sysdata) {
+ r->dev->sysdata=r;
+ pci_read_config_word(r->dev, PCI_COMMAND, &r->cmd);
+ pci_write_config_word(r->dev, PCI_COMMAND,
+ r->cmd & ~(PCI_COMMAND_IO|
+ PCI_COMMAND_MEMORY));
+ }
+ }
+
+ for (r=pci->resources; r; r= r->next) {
+ pci_write_config_dword(r->dev,
+ PCI_BASE_ADDRESS_0+(r->reg<<2),
+ r->base);
+ if ((r->type&
+ (PCI_BASE_ADDRESS_SPACE|
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+ (PCI_BASE_ADDRESS_SPACE_MEMORY|
+ PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ pci_write_config_dword(r->dev,
+ PCI_BASE_ADDRESS_1+
+ (r->reg<<2),
+ 0);
+ }
+ }
+ for (dev=bd->pci_devices; dev; dev= dev->next) {
+ if (dev->sysdata) {
+ pci_write_config_word(dev, PCI_COMMAND,
+ ((pci_resource *)dev->sysdata)
+ ->cmd);
+ dev->sysdata=NULL;
+ }
+ }
}
+
+
+
+
+
static int
indirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val) {
- out_be32(pci->config_addr,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- *val=in_8(pci->config_data + (offset&3));
- return PCIBIOS_SUCCESSFUL;
+ out_be32(pci->config_addr,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ *val=in_8(pci->config_data + (offset&3));
+ return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val) {
- *val = 0xffff;
- if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci->config_addr,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- *val=in_le16((volatile u_short *)(pci->config_data + (offset&3)));
- return PCIBIOS_SUCCESSFUL;
+ *val = 0xffff;
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci->config_addr,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ *val=in_le16((volatile u_short *)(pci->config_data + (offset&3)));
+ return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val) {
- *val = 0xffffffff;
- if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci->config_addr,
- 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
- *val=in_le32((volatile u_int *)pci->config_data);
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned int *val) {
+ *val = 0xffffffff;
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci->config_addr,
+ 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
+ *val=in_le32((volatile u_int *)pci->config_data);
+ return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val) {
- out_be32(pci->config_addr,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- out_8(pci->config_data + (offset&3), val);
- return PCIBIOS_SUCCESSFUL;
+ out_be32(pci->config_addr,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ out_8(pci->config_data + (offset&3), val);
+ return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val) {
- if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci->config_addr,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- out_le16((volatile u_short *)(pci->config_data + (offset&3)), val);
- return PCIBIOS_SUCCESSFUL;
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci->config_addr,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ out_le16((volatile u_short *)(pci->config_data + (offset&3)), val);
+ return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val) {
- if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci->config_addr,
- 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
- out_le32((volatile u_int *)pci->config_data, val);
- return PCIBIOS_SUCCESSFUL;
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci->config_addr,
+ 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
+ out_le32((volatile u_int *)pci->config_data, val);
+ return PCIBIOS_SUCCESSFUL;
}
static const struct pci_config_access_functions indirect_functions = {
- indirect_pci_read_config_byte,
- indirect_pci_read_config_word,
- indirect_pci_read_config_dword,
- indirect_pci_write_config_byte,
- indirect_pci_write_config_word,
- indirect_pci_write_config_dword
+ indirect_pci_read_config_byte,
+ indirect_pci_read_config_word,
+ indirect_pci_read_config_dword,
+ indirect_pci_write_config_byte,
+ indirect_pci_write_config_word,
+ indirect_pci_write_config_dword
};
static int
direct_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val) {
- if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
- *val=0xff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val=in_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
- + (PCI_FUNC(dev_fn)<<8) + offset);
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned char *val) {
+ if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
+ *val=0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val=in_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ + (PCI_FUNC(dev_fn)<<8) + offset);
+ return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val) {
- *val = 0xffff;
- if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
- if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val=in_le16((volatile u_short *)
- (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
- + (PCI_FUNC(dev_fn)<<8) + offset));
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned short *val) {
+ *val = 0xffff;
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val=in_le16((volatile u_short *)
+ (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ + (PCI_FUNC(dev_fn)<<8) + offset));
+ return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val) {
- *val = 0xffffffff;
- if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
- if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val=in_le32((volatile u_int *)
- (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
- + (PCI_FUNC(dev_fn)<<8) + offset));
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned int *val) {
+ *val = 0xffffffff;
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val=in_le32((volatile u_int *)
+ (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ + (PCI_FUNC(dev_fn)<<8) + offset));
+ return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val) {
- if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- out_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
- + (PCI_FUNC(dev_fn)<<8) + offset,
- val);
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned char val) {
+ if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ + (PCI_FUNC(dev_fn)<<8) + offset,
+ val);
+ return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val) {
- if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
- if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- out_le16((volatile u_short *)
- (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
- + (PCI_FUNC(dev_fn)<<8) + offset),
- val);
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned short val) {
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_le16((volatile u_short *)
+ (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ + (PCI_FUNC(dev_fn)<<8) + offset),
+ val);
+ return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val) {
- if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
- if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- out_le32((volatile u_int *)
- (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
- + (PCI_FUNC(dev_fn)<<8) + offset),
- val);
- return PCIBIOS_SUCCESSFUL;
+ unsigned char offset, unsigned int val) {
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_le32((volatile u_int *)
+ (pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ + (PCI_FUNC(dev_fn)<<8) + offset),
+ val);
+ return PCIBIOS_SUCCESSFUL;
}
static const struct pci_config_access_functions direct_functions = {
- direct_pci_read_config_byte,
- direct_pci_read_config_word,
- direct_pci_read_config_dword,
- direct_pci_write_config_byte,
- direct_pci_write_config_word,
- direct_pci_write_config_dword
+ direct_pci_read_config_byte,
+ direct_pci_read_config_word,
+ direct_pci_read_config_dword,
+ direct_pci_write_config_byte,
+ direct_pci_write_config_word,
+ direct_pci_write_config_dword
};
+
+
+
+
void pci_read_bases(struct pci_dev *dev, unsigned int howmany)
{
- unsigned int reg, nextreg;
+ 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) {
- pci_resource *r;
- nextreg=reg+1;
- pci_read_config_dword(dev, REG, &l);
+
+ u_short cmd;
+ u32 l, ml;
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+ for(reg=0; reg<howmany; reg=nextreg)
+ {
+ pci_resource *r;
+
+ nextreg=reg+1;
+ pci_read_config_dword(dev, REG, &l);
#if 0
- if (l == 0xffffffff /*AJF || !l*/) continue;
+ if (l == 0xffffffff /*AJF || !l*/) continue;
#endif
- /* Note that disabling the memory response of a host bridge
- * would lose data if a DMA transfer were in progress. In a
- * bootloader we don't care however. Also we can't print any
- * message for a while since we might just disable the console.
- */
- pci_write_config_word(dev, PCI_COMMAND, cmd &
- ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
- pci_write_config_dword(dev, REG, ~0);
- pci_read_config_dword(dev, REG, &ml);
- pci_write_config_dword(dev, REG, l);
-
- /* Reenable the device now that we've played with
- * base registers.
- */
- pci_write_config_word(dev, PCI_COMMAND, cmd);
-
- /* seems to be an unused entry skip it */
- if ( ml == 0 || ml == 0xffffffff ) continue;
-
- if ((l &
- (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_MEM_TYPE_64
- |PCI_BASE_ADDRESS_SPACE_MEMORY)) {
- nextreg=reg+2;
- }
- dev->base_address[reg] = l;
- r = salloc(sizeof(pci_resource));
- if (!r) {
- printk("Error allocating pci_resource struct.\n");
- continue;
- }
- r->dev = dev;
- r->reg = reg;
- if ((l&PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
- r->type = l&~PCI_BASE_ADDRESS_IO_MASK;
- r->base = l&PCI_BASE_ADDRESS_IO_MASK;
- r->size = ~(ml&PCI_BASE_ADDRESS_IO_MASK)+1;
- } else {
- r->type = l&~PCI_BASE_ADDRESS_MEM_MASK;
- r->base = l&PCI_BASE_ADDRESS_MEM_MASK;
- r->size = ~(ml&PCI_BASE_ADDRESS_MEM_MASK)+1;
- }
- /* Check for the blacklisted entries */
- insert_resource(r);
- }
+ /* Note that disabling the memory response of a host bridge
+ * would lose data if a DMA transfer were in progress. In a
+ * bootloader we don't care however. Also we can't print any
+ * message for a while since we might just disable the console.
+ */
+ pci_write_config_word(dev, PCI_COMMAND, cmd &
+ ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
+ pci_write_config_dword(dev, REG, ~0);
+ pci_read_config_dword(dev, REG, &ml);
+ pci_write_config_dword(dev, REG, l);
+
+ /* Reenable the device now that we've played with
+ * base registers.
+ */
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ /* seems to be an unused entry skip it */
+ if ( ml == 0 || ml == 0xffffffff ) continue;
+
+ if ((l &
+ (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+ == (PCI_BASE_ADDRESS_MEM_TYPE_64
+ |PCI_BASE_ADDRESS_SPACE_MEMORY)) {
+ nextreg=reg+2;
+ }
+ dev->base_address[reg] = l;
+ r = salloc(sizeof(pci_resource));
+ if (!r) {
+ printk("Error allocating pci_resource struct.\n");
+ continue;
+ }
+ r->dev = dev;
+ r->reg = reg;
+ if ((l&PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+ r->type = l&~PCI_BASE_ADDRESS_IO_MASK;
+ r->base = l&PCI_BASE_ADDRESS_IO_MASK;
+ r->size = ~(ml&PCI_BASE_ADDRESS_IO_MASK)+1;
+ } else {
+ r->type = l&~PCI_BASE_ADDRESS_MEM_MASK;
+ r->base = l&PCI_BASE_ADDRESS_MEM_MASK;
+ r->size = ~(ml&PCI_BASE_ADDRESS_MEM_MASK)+1;
+ }
+ /* Check for the blacklisted entries */
+ insert_resource(r);
+ }
}
+
+
+
+
u_int pci_scan_bus(struct pci_bus *bus)
{
- unsigned int devfn, l, max, class;
- unsigned char irq, hdr_type, is_multi = 0;
- struct pci_dev *dev, **bus_last;
- struct pci_bus *child;
-
- bus_last = &bus->devices;
- max = bus->secondary;
- for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) && !is_multi) {
- /* not a multi-function device */
- continue;
- }
- if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type))
- continue;
- if (!PCI_FUNC(devfn))
- is_multi = hdr_type & 0x80;
-
- if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
- /* some broken boards return 0 if a slot is empty: */
- l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
- is_multi = 0;
- continue;
- }
-
- dev = salloc(sizeof(*dev));
- dev->bus = bus;
- dev->devfn = devfn;
- dev->vendor = l & 0xffff;
- dev->device = (l >> 16) & 0xffff;
-
- pcibios_read_config_dword(bus->number, devfn,
- PCI_CLASS_REVISION, &class);
- class >>= 8; /* upper 3 bytes */
- dev->class = class;
- class >>= 8;
- dev->hdr_type = hdr_type;
-
- switch (hdr_type & 0x7f) { /* header type */
- case PCI_HEADER_TYPE_NORMAL: /* standard header */
- if (class == PCI_CLASS_BRIDGE_PCI)
- goto bad;
- /*
- * If the card generates interrupts, read IRQ number
- * (some architectures change it during pcibios_fixup())
- */
- pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq);
- if (irq)
- pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
- dev->irq = irq;
- /*
- * read base address registers, again pcibios_fixup() can
- * tweak these
- */
- pci_read_bases(dev, 6);
- pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
- dev->rom_address = (l == 0xffffffff) ? 0 : l;
- break;
- case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
- if (class != PCI_CLASS_BRIDGE_PCI)
- goto bad;
- pci_read_bases(dev, 2);
- pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
- dev->rom_address = (l == 0xffffffff) ? 0 : l;
- break;
- case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
- if (class != PCI_CLASS_BRIDGE_CARDBUS)
- goto bad;
- pci_read_bases(dev, 1);
- break;
- default: /* unknown header */
- bad:
- printk("PCI device with unknown "
- "header type %d ignored.\n",
- hdr_type&0x7f);
- continue;
- }
-
- /*
- * Put it into the global PCI device chain. It's used to
- * find devices once everything is set up.
- */
- *pci->last_dev_p = dev;
- pci->last_dev_p = &dev->next;
-
- /*
- * Now insert it into the list of devices held
- * by the parent bus.
- */
- *bus_last = dev;
- bus_last = &dev->sibling;
-
- }
-
- /*
- * After performing arch-dependent fixup of the bus, look behind
- * all PCI-to-PCI bridges on this bus.
- */
- for(dev=bus->devices; dev; dev=dev->sibling)
- /*
- * If it's a bridge, scan the bus behind it.
- */
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- unsigned int buses;
- unsigned int devfn = dev->devfn;
- unsigned short cr;
-
- /*
- * Insert it into the tree of buses.
- */
- child = salloc(sizeof(*child));
- child->next = bus->children;
- bus->children = child;
- child->self = dev;
- child->parent = bus;
-
- /*
- * Set up the primary, secondary and subordinate
- * bus numbers.
- */
- child->number = child->secondary = ++max;
- child->primary = bus->secondary;
- child->subordinate = 0xff;
- /*
- * Clear all status bits and turn off memory,
- * I/O and master enables.
- */
- pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
- pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
- pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
- /*
- * Read the existing primary/secondary/subordinate bus
- * number configuration to determine if the PCI bridge
- * has already been configured by the system. If so,
- * do not modify the configuration, merely note it.
- */
- pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
- if ((buses & 0xFFFFFF) != 0)
- {
- unsigned int cmax;
-
- child->primary = buses & 0xFF;
- child->secondary = (buses >> 8) & 0xFF;
- child->subordinate = (buses >> 16) & 0xFF;
- child->number = child->secondary;
- cmax = pci_scan_bus(child);
- if (cmax > max) max = cmax;
- }
- else
- {
- /*
- * Configure the bus numbers for this bridge:
- */
- buses &= 0xff000000;
- buses |=
- (((unsigned int)(child->primary) << 0) |
- ((unsigned int)(child->secondary) << 8) |
- ((unsigned int)(child->subordinate) << 16));
- pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
- /*
- * Now we can scan all subordinate buses:
- */
- max = pci_scan_bus(child);
- /*
- * Set the subordinate bus number to its real
- * value:
- */
- child->subordinate = max;
- buses = (buses & 0xff00ffff)
- | ((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);
- }
-
- /*
- * We've scanned the bus and so we know all about what's on
- * the other side of any bridges that may be on this bus plus
- * any devices.
- *
- * Return how far we've got finding sub-buses.
- */
- return max;
+ unsigned int devfn, l, max, class;
+ unsigned char irq, hdr_type, is_multi = 0;
+ 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) {
+ if (PCI_FUNC(devfn) && !is_multi) {
+ /* not a multi-function device */
+ continue;
+ }
+ if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type))
+ continue;
+ if (!PCI_FUNC(devfn))
+ is_multi = hdr_type & 0x80;
+
+ if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
+ /* some broken boards return 0 if a slot is empty: */
+ l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
+ is_multi = 0;
+ continue;
+ }
+
+ dev = salloc(sizeof(*dev));
+ dev->bus = bus;
+ dev->devfn = devfn;
+ dev->vendor = l & 0xffff;
+ dev->device = (l >> 16) & 0xffff;
+
+ pcibios_read_config_dword(bus->number, devfn,
+ PCI_CLASS_REVISION, &class);
+ class >>= 8; /* upper 3 bytes */
+ dev->class = class;
+ class >>= 8;
+ dev->hdr_type = hdr_type;
+
+ switch (hdr_type & 0x7f) { /* header type */
+ case PCI_HEADER_TYPE_NORMAL: /* standard header */
+ if (class == PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ /*
+ * If the card generates interrupts, read IRQ number
+ * (some architectures change it during pcibios_fixup())
+ */
+ pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq);
+ if (irq)
+ pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
+ dev->irq = irq;
+ /*
+ * read base address registers, again pcibios_fixup() can
+ * tweak these
+ */
+ pci_read_bases(dev, 6);
+ pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
+ dev->rom_address = (l == 0xffffffff) ? 0 : l;
+ break;
+ case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
+ if (class != PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ pci_read_bases(dev, 2);
+ pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
+ dev->rom_address = (l == 0xffffffff) ? 0 : l;
+ break;
+ case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
+ if (class != PCI_CLASS_BRIDGE_CARDBUS)
+ goto bad;
+ pci_read_bases(dev, 1);
+ break;
+
+ default: /* unknown header */
+ bad:
+ printk("PCI device with unknown header type %d ignored.\n",
+ hdr_type&0x7f);
+ continue;
+ }
+
+ /*
+ * Put it into the global PCI device chain. It's used to
+ * find devices once everything is set up.
+ */
+ *pci->last_dev_p = dev;
+ pci->last_dev_p = &dev->next;
+
+ /*
+ * Now insert it into the list of devices held
+ * by the parent bus.
+ */
+ *bus_last = dev;
+ bus_last = &dev->sibling;
+
+ }
+
+ /*
+ * After performing arch-dependent fixup of the bus, look behind
+ * all PCI-to-PCI bridges on this bus.
+ */
+ for(dev=bus->devices; dev; dev=dev->sibling)
+ /*
+ * If it's a bridge, scan the bus behind it.
+ */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ unsigned int buses;
+ unsigned int devfn = dev->devfn;
+ unsigned short cr;
+
+ /*
+ * Insert it into the tree of buses.
+ */
+ child = salloc(sizeof(*child));
+ child->next = bus->children;
+ bus->children = child;
+ child->self = dev;
+ child->parent = bus;
+
+ /*
+ * Set up the primary, secondary and subordinate
+ * bus numbers.
+ */
+ child->number = child->secondary = ++max;
+ child->primary = bus->secondary;
+ child->subordinate = 0xff;
+ /*
+ * Clear all status bits and turn off memory,
+ * I/O and master enables.
+ */
+ pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
+ pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
+ pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
+ /*
+ * Read the existing primary/secondary/subordinate bus
+ * number configuration to determine if the PCI bridge
+ * has already been configured by the system. If so,
+ * do not modify the configuration, merely note it.
+ */
+ pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
+ if ((buses & 0xFFFFFF) != 0)
+ {
+ unsigned int cmax;
+
+ child->primary = buses & 0xFF;
+ child->secondary = (buses >> 8) & 0xFF;
+ child->subordinate = (buses >> 16) & 0xFF;
+ child->number = child->secondary;
+ cmax = pci_scan_bus(child);
+ if (cmax > max) max = cmax;
+ }
+ else
+ {
+ /*
+ * Configure the bus numbers for this bridge:
+ */
+ buses &= 0xff000000;
+ buses |=
+ (((unsigned int)(child->primary) << 0) |
+ ((unsigned int)(child->secondary) << 8) |
+ ((unsigned int)(child->subordinate) << 16));
+ pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
+ /*
+ * Now we can scan all subordinate buses:
+ */
+ max = pci_scan_bus(child);
+ /*
+ * Set the subordinate bus number to its real
+ * value:
+ */
+ child->subordinate = max;
+ buses = (buses & 0xff00ffff)
+ | ((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 );
+ }
+
+ /*
+ * We've scanned the bus and so we know all about what's on
+ * the other side of any bridges that may be on this bus plus
+ * any devices.
+ *
+ * Return how far we've got finding sub-buses.
+ */
+ return max;
}
+
+
+
+
+
+
+
+
+
+#if 0
+
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) {
- }
- }
-}
-
-void pci_init(void) {
- PPC_DEVICE *hostbridge;
-
- if (pci->last_dev_p) {
- printk("Two or more calls to pci_init!\n");
- return;
- }
- pci->last_dev_p = &(bd->pci_devices);
- hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
- BridgeController,
- PCIBridge, -1, 0);
- if (hostbridge) {
- if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
- bd->pci_functions=&indirect_functions;
- /* Should be extracted from residual data,
- * indeed MPC106 in CHRP mode is different,
- * but we should not use residual data in
- * this case anyway.
- */
- pci->config_addr = ((volatile u_int *)
- (ptr_mem_map->io_base+0xcf8));
- pci->config_data = ptr_mem_map->io_base+0xcfc;
- } else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
- bd->pci_functions=&direct_functions;
- pci->config_data=(u_char *) 0x80800000;
- } else {
- }
- } else {
- /* Let us try by experimentation at our own risk! */
- u_int id0;
- bd->pci_functions = &direct_functions;
- /* On all direct bridges I know the host bridge itself
- * appears as device 0 function 0.
- */
- pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &id0);
- if (id0==~0U) {
- bd->pci_functions = &indirect_functions;
- pci->config_addr = ((volatile u_int *)
- (ptr_mem_map->io_base+0xcf8));
- pci->config_data = ptr_mem_map->io_base+0xcfc;
- }
- /* Here we should check that the host bridge is actually
- * present, but if it not, we are in such a desperate
- * situation, that we probably can't even tell it.
- */
- }
- /* 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");
- reconfigure_pci();
- print_pci_resources("Allocated PCI resources:\n");
+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)
+ {
+ }
+ }
+}
+
+
+
+
+
+
+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) {
+ printk("Two or more calls to pci_init!\n");
+ return;
+ }
+ pci->last_dev_p = &(bd->pci_devices);
+ hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
+ BridgeController,
+ PCIBridge, -1, 0);
+ if (hostbridge) {
+ if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
+ bd->pci_functions=&indirect_functions;
+ /* Should be extracted from residual data,
+ * indeed MPC106 in CHRP mode is different,
+ * but we should not use residual data in
+ * this case anyway.
+ */
+ pci->config_addr = ((volatile u_int *)
+ (ptr_mem_map->io_base+0xcf8));
+ pci->config_data = ptr_mem_map->io_base+0xcfc;
+ } else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
+ bd->pci_functions=&direct_functions;
+ pci->config_data=(u_char *) 0x80800000;
+ } else {
+ }
+ } else {
+ /* Let us try by experimentation at our own risk! */
+ u_int id0;
+ bd->pci_functions = &direct_functions;
+ /* On all direct bridges I know the host bridge itself
+ * appears as device 0 function 0.
+ */
+ pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &id0);
+ if (id0==~0U) {
+ bd->pci_functions = &indirect_functions;
+ pci->config_addr = ((volatile u_int *)
+ (ptr_mem_map->io_base+0xcf8));
+ pci->config_data = ptr_mem_map->io_base+0xcfc;
+ }
+ /* Here we should check that the host bridge is actually
+ * present, but if it not, we are in such a desperate
+ * situation, that we probably can't even tell it.
+ */
+ }
+ /* 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("Installed PCI resources:\n");
+
+ recursive_bus_reconfigure(NULL);
+ reconfigure_pci();
+
+ print_pci_resources("Allocated PCI resources:\n");
+}
+
+
+/* eof */
diff --git a/c/src/lib/libbsp/powerpc/shared/irq/irq.c b/c/src/lib/libbsp/powerpc/shared/irq/irq.c
index d45242529b..dbb5e72f77 100644
--- a/c/src/lib/libbsp/powerpc/shared/irq/irq.c
+++ b/c/src/lib/libbsp/powerpc/shared/irq/irq.c
@@ -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
*/
- rtems_hdl_tbl[irq->name] = default_rtems_entry;
+ 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);
@@ -265,12 +380,31 @@ 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]);
+ BSP_irq_enable_at_i8259s (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]);
- BSP_irq_disable_at_i8259s (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);
}
}
/*
@@ -287,12 +421,32 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
openpic_set_source_priority(i - BSP_PCI_IRQ_LOWEST_OFFSET,
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]);
+ openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
+ /* 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]);
- openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
+ /* 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);
diff --git a/c/src/lib/libbsp/powerpc/shared/irq/irq.h b/c/src/lib/libbsp/powerpc/shared/irq/irq.h
index a356762e4f..7d54a6eff7 100644
--- a/c/src/lib/libbsp/powerpc/shared/irq/irq.h
+++ b/c/src/lib/libbsp/powerpc/shared/irq/irq.h
@@ -143,38 +143,43 @@ typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__*);
typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*);
typedef struct __rtems_irq_connect_data__ {
- /*
- * IRQ line
- */
- rtems_irq_symbolic_name name;
- /*
- * handler. See comment on handler properties below in function prototype.
- */
- rtems_irq_hdl hdl;
- /*
- * function for enabling interrupts at device level (ONLY!).
- * The BSP code will automatically enable it at i8259s level and openpic level.
- * RATIONALE : anyway such code has to exist in current driver code.
- * It is usually called immediately AFTER connecting the interrupt handler.
- * RTEMS may well need such a function when restoring normal interrupt
- * processing after a debug session.
- *
- */
- rtems_irq_enable on;
- /*
- * function for disabling interrupts at device level (ONLY!).
- * The code will disable it at i8259s level. RATIONALE : anyway
- * such code has to exist for clean shutdown. It is usually called
- * BEFORE disconnecting the interrupt. RTEMS may well need such
- * a function when disabling normal interrupt processing for
- * a debug session. May well be a NOP function.
- */
- rtems_irq_disable off;
- /*
- * function enabling to know what interrupt may currently occur
- * if someone manipulates the i8259s interrupt mask without care...
- */
- rtems_irq_is_enabled isOn;
+ /*
+ * IRQ line
+ */
+ rtems_irq_symbolic_name name;
+ /*
+ * handler. See comment on handler properties below in function prototype.
+ */
+ rtems_irq_hdl hdl;
+ /*
+ * function for enabling interrupts at device level (ONLY!).
+ * The BSP code will automatically enable it at i8259s level and openpic level.
+ * RATIONALE : anyway such code has to exist in current driver code.
+ * It is usually called immediately AFTER connecting the interrupt handler.
+ * RTEMS may well need such a function when restoring normal interrupt
+ * processing after a debug session.
+ *
+ */
+ rtems_irq_enable on;
+ /*
+ * function for disabling interrupts at device level (ONLY!).
+ * The code will disable it at i8259s level. RATIONALE : anyway
+ * such code has to exist for clean shutdown. It is usually called
+ * BEFORE disconnecting the interrupt. RTEMS may well need such
+ * a function when disabling normal interrupt processing for
+ * a debug session. May well be a NOP function.
+ */
+ rtems_irq_disable off;
+ /*
+ * function enabling to know what interrupt may currently occur
+ * 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...
diff --git a/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c b/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
index d45e09044b..a6a4ce9868 100644
--- a/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
+++ b/c/src/lib/libbsp/powerpc/shared/motorola/motorola.c
@@ -18,42 +18,178 @@
#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
* that the level/edge are set.
* 0x200 if this board has a Hawk chip.
*/
- int cpu_type;
- int base_type;
- const char *name;
+ 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;
+}
+
diff --git a/c/src/lib/libbsp/powerpc/shared/motorola/motorola.h b/c/src/lib/libbsp/powerpc/shared/motorola/motorola.h
index 585d1d62dc..c538bd2f74 100644
--- a/c/src/lib/libbsp/powerpc/shared/motorola/motorola.h
+++ b/c/src/lib/libbsp/powerpc/shared/motorola/motorola.h
@@ -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 */
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/pci.c b/c/src/lib/libbsp/powerpc/shared/pci/pci.c
index a6d615cea6..0661a8a60e 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/pci.c
+++ b/c/src/lib/libbsp/powerpc/shared/pci/pci.c
@@ -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
*/
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/pci.h b/c/src/lib/libbsp/powerpc/shared/pci/pci.h
index 7327a6afbc..bacf8d51b5 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/pci.h
+++ b/c/src/lib/libbsp/powerpc/shared/pci/pci.h
@@ -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)
diff --git a/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c b/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c
index a1d2a0d3ad..4414c5755e 100644
--- a/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c
+++ b/c/src/lib/libbsp/powerpc/shared/pci/pcifinddevice.c
@@ -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)
diff --git a/c/src/lib/libbsp/powerpc/shared/startup/bspstart.c b/c/src/lib/libbsp/powerpc/shared/startup/bspstart.c
index a865742dad..5fc61e65bb 100644
--- a/c/src/lib/libbsp/powerpc/shared/startup/bspstart.c
+++ b/c/src/lib/libbsp/powerpc/shared/startup/bspstart.c
@@ -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