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>
|
2003-06-13 Till Straumann <strauman@slac.stanford.edu>
|
||||||
|
|
||||||
PR 415/bsps
|
PR 415/bsps
|
||||||
|
|||||||
@@ -39,3 +39,11 @@ initialization (e.g printk, ...).
|
|||||||
Eric Valette (valette@crf.canon.fr)
|
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 "bootldr.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include <libcpu/io.h>
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/page.h>
|
||||||
#include <bsp/consoleIo.h>
|
#include <bsp/consoleIo.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned int u32;
|
typedef unsigned int u32;
|
||||||
|
|
||||||
/*#define DEBUG*/
|
/*#define DEBUG*/
|
||||||
@@ -95,6 +98,7 @@ print_pci_resources(const char *s) {
|
|||||||
pci_resource *p;
|
pci_resource *p;
|
||||||
printk("%s", s);
|
printk("%s", s);
|
||||||
for (p=pci->resources; p; p=p->next) {
|
for (p=pci->resources; p; p=p->next) {
|
||||||
|
/*
|
||||||
printk(" %p:%p %06x %08lx %08lx %d\n",
|
printk(" %p:%p %06x %08lx %08lx %d\n",
|
||||||
p, p->next,
|
p, p->next,
|
||||||
(p->dev->devfn<<8)+(p->dev->bus->number<<16)
|
(p->dev->devfn<<8)+(p->dev->bus->number<<16)
|
||||||
@@ -102,6 +106,16 @@ print_pci_resources(const char *s) {
|
|||||||
p->base,
|
p->base,
|
||||||
p->size,
|
p->size,
|
||||||
p->type);
|
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 :\
|
((r->type&PCI_BASE_ADDRESS_MEM_PREFETCH) ? PCI_AREA_PREFETCHABLE :\
|
||||||
PCI_AREA_MEMORY))
|
PCI_AREA_MEMORY))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int insert_before(pci_resource *e, pci_resource *t) {
|
static int insert_before(pci_resource *e, pci_resource *t) {
|
||||||
if (e->dev->bus->number != t->dev->bus->number)
|
if (e->dev->bus->number != t->dev->bus->number)
|
||||||
return 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);
|
return (e->size > t->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void insert_resource(pci_resource *r) {
|
static void insert_resource(pci_resource *r) {
|
||||||
struct blacklist_entry *b;
|
struct blacklist_entry *b;
|
||||||
pci_resource *p;
|
pci_resource *p;
|
||||||
@@ -195,12 +215,14 @@ static void insert_resource(pci_resource *r) {
|
|||||||
* limits have hopefully been set high enough to avoid problems.
|
* limits have hopefully been set high enough to avoid problems.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
||||||
? (r->base && r->base <0x10000)
|
? (r->base && r->base <0x10000)
|
||||||
: (r->base && r->base <0x1000000)) {
|
: (r->base && r->base <0x1000000)) {
|
||||||
sfree(r);
|
sfree(r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
|
||||||
? (r->size >= 0x10000)
|
? (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
|
/* 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.
|
* a more sophisticated version which has therefore not been implemented.
|
||||||
* Prefetchable memory is not yet handled correctly either.
|
* 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_long total=0;
|
||||||
u_int fl=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) &&
|
if ((p->dev->bus->number == bus) &&
|
||||||
AREA(p)==type) break;
|
AREA(p)==type) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
*first = p;
|
*first = p;
|
||||||
for (; p; p=p->next) {
|
|
||||||
|
for (; p; p=p->next)
|
||||||
|
{
|
||||||
if ((p->dev->bus->number != bus) ||
|
if ((p->dev->bus->number != bus) ||
|
||||||
AREA(p)!=type || p->size == 0) break;
|
AREA(p)!=type || p->size == 0) break;
|
||||||
total = total+p->size;
|
total = total+p->size;
|
||||||
fl |= 1<<p->type;
|
fl |= 1<<p->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
*past = p;
|
*past = p;
|
||||||
/* This will be used later to tell whether there are any 32 bit
|
/* This will be used later to tell whether there are any 32 bit
|
||||||
* devices in an area which could be mapped higher than 4Gb
|
* 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;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static inline void init_free_area(pci_area_head *h, u_long start,
|
static inline void init_free_area(pci_area_head *h, u_long start,
|
||||||
u_long end, u_int mask, int high) {
|
u_long end, u_int mask, int high) {
|
||||||
pci_area *p;
|
pci_area *p;
|
||||||
@@ -274,6 +310,11 @@ static inline void init_free_area(pci_area_head *h, u_long start,
|
|||||||
h->high = high;
|
h->high = high;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void insert_area(pci_area_head *h, pci_area *p) {
|
static void insert_area(pci_area_head *h, pci_area *p) {
|
||||||
pci_area *q = h->head;
|
pci_area *q = h->head;
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
@@ -298,12 +339,18 @@ static void insert_area(pci_area_head *h, pci_area *p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static
|
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;
|
pci_area *q = h->head;
|
||||||
|
|
||||||
if (!p || !q) return;
|
if (!p || !q) return;
|
||||||
if (q==p) {
|
if (q==p)
|
||||||
|
{
|
||||||
h->head = q->next;
|
h->head = q->next;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -311,13 +358,19 @@ void remove_area(pci_area_head *h, pci_area *p) {
|
|||||||
if (q) q->next=p->next;
|
if (q) q->next=p->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
||||||
u_long required, u_long mask, u_int flags) {
|
u_long required, u_long mask, u_int flags) {
|
||||||
pci_area *p;
|
pci_area *p;
|
||||||
pci_area *from, *split, *new;
|
pci_area *from, *split, *new;
|
||||||
|
|
||||||
required = (required+h->mask) & ~h->mask;
|
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 l1 = ((p->start+required+mask)&~mask)-1;
|
||||||
u_long l2 = ((p->start+mask)&~mask)+required-1;
|
u_long l2 = ((p->start+mask)&~mask)+required-1;
|
||||||
/* Allocated areas point to the bus to which they pertain */
|
/* 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->bus = bus;
|
||||||
new->flags = flags;
|
new->flags = flags;
|
||||||
/* Now allocate pci_space taking alignment into account ! */
|
/* Now allocate pci_space taking alignment into account ! */
|
||||||
if (h->high) {
|
if (h->high)
|
||||||
|
{
|
||||||
u_long l1 = ((from->end+1)&~mask)-required;
|
u_long l1 = ((from->end+1)&~mask)-required;
|
||||||
u_long l2 = (from->end+1-required)&~mask;
|
u_long l2 = (from->end+1-required)&~mask;
|
||||||
new->start = (l1>l2) ? l1 : l2;
|
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;
|
from->end = new->start-1;
|
||||||
split->start = new->start+required;
|
split->start = new->start+required;
|
||||||
new->end = new->start+required-1;
|
new->end = new->start+required-1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
u_long l1 = ((from->start+mask)&~mask)+required-1;
|
u_long l1 = ((from->start+mask)&~mask)+required-1;
|
||||||
u_long l2 = ((from->start+required+mask)&~mask)-1;
|
u_long l2 = ((from->start+required+mask)&~mask)-1;
|
||||||
new->end = (l1<l2) ? l1 : l2;
|
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 (from->end+1 == from->start) remove_area(h, from);
|
||||||
if (split->end+1 != split->start) {
|
if (split->end+1 != split->start)
|
||||||
|
{
|
||||||
split->bus = NULL;
|
split->bus = NULL;
|
||||||
insert_area(h, split);
|
insert_area(h, split);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
sfree(split);
|
sfree(split);
|
||||||
}
|
}
|
||||||
insert_area(h, new);
|
insert_area(h, new);
|
||||||
@@ -369,8 +428,13 @@ static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static inline
|
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)) {
|
if (p->start & (r->size-1)) {
|
||||||
r->base = p->end+1-r->size;
|
r->base = p->end+1-r->size;
|
||||||
p->end -= 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_resource *first, *past, *r;
|
||||||
pci_area *area, tmp;
|
pci_area *area, tmp;
|
||||||
u_int flags;
|
u_int flags;
|
||||||
u_int required = find_range(bus, type, &first, &past, &flags);
|
u_int required = find_range(bus, type, &first, &past, &flags);
|
||||||
|
|
||||||
if (required==0) return;
|
if (required==0) return;
|
||||||
|
|
||||||
area = alloc_area(h, first->dev->bus, required, first->size-1, flags);
|
area = alloc_area(h, first->dev->bus, required, first->size-1, flags);
|
||||||
|
|
||||||
if (!area) return;
|
if (!area) return;
|
||||||
|
|
||||||
tmp = *area;
|
tmp = *area;
|
||||||
for (r=first; r!=past; r=r->next) {
|
for (r=first; r!=past; r=r->next)
|
||||||
|
{
|
||||||
alloc_space(&tmp, r);
|
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) {
|
static void reconfigure_pci(void) {
|
||||||
pci_resource *r;
|
pci_resource *r;
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
|
|
||||||
/* FIXME: for now memory is relocated from low, it's better
|
/* FIXME: for now memory is relocated from low, it's better
|
||||||
* to start from higher addresses.
|
* to start from higher addresses.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
init_free_area(&pci->io, 0x10000, 0x7fffff, 0xfff, 0);
|
init_free_area(&pci->io, 0x10000, 0x7fffff, 0xfff, 0);
|
||||||
init_free_area(&pci->mem, 0x1000000, 0x3cffffff, 0xfffff, 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
|
/* First reconfigure the I/O space, this will be more
|
||||||
* complex when there is more than 1 bus. And 64 bits
|
* complex when there is more than 1 bus. And 64 bits
|
||||||
@@ -454,6 +554,11 @@ static void reconfigure_pci(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
indirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
|
indirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
|
||||||
unsigned char offset, unsigned char *val) {
|
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)
|
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))
|
#define REG (PCI_BASE_ADDRESS_0 + (reg<<2))
|
||||||
|
|
||||||
u_short cmd;
|
u_short cmd;
|
||||||
u32 l, ml;
|
u32 l, ml;
|
||||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
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;
|
pci_resource *r;
|
||||||
|
|
||||||
nextreg=reg+1;
|
nextreg=reg+1;
|
||||||
pci_read_config_dword(dev, REG, &l);
|
pci_read_config_dword(dev, REG, &l);
|
||||||
#if 0
|
#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)
|
u_int pci_scan_bus(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
unsigned int devfn, l, max, class;
|
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_dev *dev, **bus_last;
|
||||||
struct pci_bus *child;
|
struct pci_bus *child;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printk("scanning pci bus %d\n", bus->number );
|
||||||
|
#endif
|
||||||
|
|
||||||
bus_last = &bus->devices;
|
bus_last = &bus->devices;
|
||||||
max = bus->secondary;
|
max = bus->secondary;
|
||||||
for (devfn = 0; devfn < 0xff; ++devfn) {
|
for (devfn = 0; devfn < 0xff; ++devfn) {
|
||||||
@@ -750,10 +871,10 @@ u_int pci_scan_bus(struct pci_bus *bus)
|
|||||||
goto bad;
|
goto bad;
|
||||||
pci_read_bases(dev, 1);
|
pci_read_bases(dev, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* unknown header */
|
default: /* unknown header */
|
||||||
bad:
|
bad:
|
||||||
printk("PCI device with unknown "
|
printk("PCI device with unknown header type %d ignored.\n",
|
||||||
"header type %d ignored.\n",
|
|
||||||
hdr_type&0x7f);
|
hdr_type&0x7f);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -865,18 +986,373 @@ u_int pci_scan_bus(struct pci_bus *bus)
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
void
|
void
|
||||||
pci_fixup(void) {
|
pci_fixup(void)
|
||||||
|
{
|
||||||
struct pci_dev *p;
|
struct pci_dev *p;
|
||||||
struct pci_bus *bus;
|
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;
|
PPC_DEVICE *hostbridge;
|
||||||
|
|
||||||
if (pci->last_dev_p) {
|
if (pci->last_dev_p) {
|
||||||
@@ -925,8 +1401,14 @@ void pci_init(void) {
|
|||||||
/* Now build a small database of all found PCI devices */
|
/* Now build a small database of all found PCI devices */
|
||||||
printk("\nPCI: Probing PCI hardware\n");
|
printk("\nPCI: Probing PCI hardware\n");
|
||||||
pci_root.subordinate=pci_scan_bus(&pci_root);
|
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();
|
reconfigure_pci();
|
||||||
|
|
||||||
print_pci_resources("Allocated PCI resources:\n");
|
print_pci_resources("Allocated PCI resources:\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* eof */
|
||||||
|
|||||||
@@ -118,6 +118,70 @@ static int isValidInterrupt(int irq)
|
|||||||
return 1;
|
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 ----------------
|
* ------------------------ 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
|
* store the data provided by user
|
||||||
*/
|
*/
|
||||||
rtems_hdl_tbl[irq->name] = *irq;
|
rtems_hdl_tbl[irq->name] = *irq;
|
||||||
|
rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
|
||||||
|
|
||||||
if (is_isa_irq(irq->name)) {
|
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)
|
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
||||||
{
|
{
|
||||||
|
rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
|
||||||
unsigned int level;
|
unsigned int level;
|
||||||
|
|
||||||
if (!isValidInterrupt(irq->name)) {
|
if (!isValidInterrupt(irq->name)) {
|
||||||
@@ -206,6 +272,35 @@ int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
|
|||||||
}
|
}
|
||||||
_CPU_ISR_Disable(level);
|
_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)) {
|
if (is_isa_irq(irq->name)) {
|
||||||
/*
|
/*
|
||||||
* disable interrupt at PIC level
|
* 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
|
* restore the default irq value
|
||||||
*/
|
*/
|
||||||
|
if( !vchain )
|
||||||
|
{
|
||||||
|
/* single handler vector... */
|
||||||
rtems_hdl_tbl[irq->name] = default_rtems_entry;
|
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);
|
_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++) {
|
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) {
|
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||||
BSP_irq_enable_at_i8259s (i);
|
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 {
|
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);
|
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]);
|
internal_config->irqPrioTbl[i]);
|
||||||
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
|
||||||
openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
|
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 {
|
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);
|
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++) {
|
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) {
|
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 {
|
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);
|
_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;
|
new_msr = msr | MSR_EE;
|
||||||
_CPU_MSR_SET(new_msr);
|
_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);
|
_CPU_MSR_SET(msr);
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,11 @@ typedef struct __rtems_irq_connect_data__ {
|
|||||||
* if someone manipulates the i8259s interrupt mask without care...
|
* if someone manipulates the i8259s interrupt mask without care...
|
||||||
*/
|
*/
|
||||||
rtems_irq_is_enabled isOn;
|
rtems_irq_is_enabled isOn;
|
||||||
|
/*
|
||||||
|
* Set to -1 for vectors forced to have only 1 handler
|
||||||
|
*/
|
||||||
|
void *next_handler;
|
||||||
|
|
||||||
}rtems_irq_connect_data;
|
}rtems_irq_connect_data;
|
||||||
|
|
||||||
typedef struct {
|
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_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
|
* function to get the current RTEMS irq handler for ptr->name. It enables to
|
||||||
* define hanlder chain...
|
* define hanlder chain...
|
||||||
|
|||||||
@@ -18,6 +18,137 @@
|
|||||||
#include <libcpu/io.h>
|
#include <libcpu/io.h>
|
||||||
#include <string.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 {
|
typedef struct {
|
||||||
/*
|
/*
|
||||||
* 0x100 mask assumes for Raven and Hawk boards
|
* 0x100 mask assumes for Raven and Hawk boards
|
||||||
@@ -27,33 +158,38 @@ typedef struct {
|
|||||||
int cpu_type;
|
int cpu_type;
|
||||||
int base_type;
|
int base_type;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
struct _int_map *intmap;
|
||||||
|
int (*swizzler)(int, int);
|
||||||
} mot_info_t;
|
} mot_info_t;
|
||||||
|
|
||||||
|
|
||||||
static const mot_info_t mot_boards[] = {
|
static const mot_info_t mot_boards[] = {
|
||||||
{0x300, 0x00, "MVME 2400"},
|
{0x300, 0x00, "MVME 2400", NULL, NULL},
|
||||||
{0x010, 0x00, "Genesis"},
|
{0x010, 0x00, "Genesis", NULL, NULL},
|
||||||
{0x020, 0x00, "Powerstack (Series E)"},
|
{0x020, 0x00, "Powerstack (Series E)", NULL, NULL},
|
||||||
{0x040, 0x00, "Blackhawk (Powerstack)"},
|
{0x040, 0x00, "Blackhawk (Powerstack)", NULL, NULL},
|
||||||
{0x050, 0x00, "Omaha (PowerStack II Pro3000)"},
|
{0x050, 0x00, "Omaha (PowerStack II Pro3000)", NULL, NULL},
|
||||||
{0x060, 0x00, "Utah (Powerstack II Pro4000)"},
|
{0x060, 0x00, "Utah (Powerstack II Pro4000)", NULL, NULL},
|
||||||
{0x0A0, 0x00, "Powerstack (Series EX)"},
|
{0x0A0, 0x00, "Powerstack (Series EX)", NULL, NULL},
|
||||||
{0x1E0, 0xE0, "Mesquite cPCI (MCP750)"},
|
{0x1E0, 0xE0, "Mesquite cPCI (MCP750)", mcp750_intmap, prep_pci_swizzle},
|
||||||
{0x1E0, 0xE1, "Sitka cPCI (MCPN750)"},
|
{0x1E0, 0xE1, "Sitka cPCI (MCPN750)", mcp750_intmap, prep_pci_swizzle},
|
||||||
{0x1E0, 0xE2, "Mesquite cPCI (MCP750) w/ HAC"},
|
{0x1E0, 0xE2, "Mesquite cPCI (MCP750) w/ HAC", mcp750_intmap, prep_pci_swizzle},
|
||||||
{0x1E0, 0xF6, "MTX Plus"},
|
{0x1E0, 0xF6, "MTX Plus", NULL, NULL},
|
||||||
{0x1E0, 0xF7, "MTX w/o Parallel Port"},
|
{0x1E0, 0xF7, "MTX w/o Parallel Port", mtx603_intmap, prep_pci_swizzle},
|
||||||
{0x1E0, 0xF8, "MTX w/ Parallel Port"},
|
{0x1E0, 0xF8, "MTX w/ Parallel Port", mtx603_intmap, prep_pci_swizzle},
|
||||||
{0x1E0, 0xF9, "MVME 2300"},
|
{0x1E0, 0xF9, "MVME 2300", NULL, NULL},
|
||||||
{0x1E0, 0xFA, "MVME 2300SC/2600"},
|
{0x1E0, 0xFA, "MVME 2300SC/2600", NULL, NULL},
|
||||||
{0x1E0, 0xFB, "MVME 2600 with MVME712M"},
|
{0x1E0, 0xFB, "MVME 2600 with MVME712M", NULL, NULL},
|
||||||
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761"},
|
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761", NULL, NULL},
|
||||||
{0x1E0, 0xFD, "MVME 3600 with MVME712M"},
|
{0x1E0, 0xFD, "MVME 3600 with MVME712M", NULL, NULL},
|
||||||
{0x1E0, 0xFE, "MVME 3600 with MVME761"},
|
{0x1E0, 0xFE, "MVME 3600 with MVME761", NULL, NULL},
|
||||||
{0x1E0, 0xFF, "MVME 1600-001 or 1600-011"},
|
{0x1E0, 0xFF, "MVME 1600-001 or 1600-011", NULL, NULL},
|
||||||
{0x000, 0x00, ""}
|
{0x000, 0x00, ""}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
prep_t currentPrepType;
|
prep_t currentPrepType;
|
||||||
motorolaBoard currentBoard;
|
motorolaBoard currentBoard;
|
||||||
prep_t checkPrepBoardType(RESIDUAL *res)
|
prep_t checkPrepBoardType(RESIDUAL *res)
|
||||||
@@ -114,9 +250,24 @@ motorolaBoard getMotorolaBoard()
|
|||||||
return currentBoard;
|
return currentBoard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* motorolaBoardToString(motorolaBoard board)
|
const char* motorolaBoardToString(motorolaBoard board)
|
||||||
{
|
{
|
||||||
if (board == MOTOROLA_UNKNOWN) return "Unknown motorola board";
|
if (board == MOTOROLA_UNKNOWN) return "Unknown motorola board";
|
||||||
return (mot_boards[board].name);
|
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
|
#define LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H
|
||||||
|
|
||||||
#include <bsp/residual.h>
|
#include <bsp/residual.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PREP_IBM = 0,
|
PREP_IBM = 0,
|
||||||
@@ -61,6 +69,8 @@ extern prep_t currentPrepType;
|
|||||||
extern motorolaBoard getMotorolaBoard();
|
extern motorolaBoard getMotorolaBoard();
|
||||||
extern motorolaBoard currentBoard;
|
extern motorolaBoard currentBoard;
|
||||||
extern const char* motorolaBoardToString(motorolaBoard);
|
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 */
|
#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
|
* This routine determines the maximum bus number in the system
|
||||||
*/
|
*/
|
||||||
@@ -228,6 +542,7 @@ void InitializePCI()
|
|||||||
unsigned int ulClass, ulDeviceID;
|
unsigned int ulClass, ulDeviceID;
|
||||||
|
|
||||||
detect_host_bridge();
|
detect_host_bridge();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan PCI bus 0 looking for PCI-PCI bridges
|
* 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 unsigned char BusCountPCI();
|
||||||
extern void InitializePCI();
|
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 */
|
/* scan for a specific device */
|
||||||
/* find a particular PCI device
|
/* find a particular PCI device
|
||||||
* (currently, only bus0 is scanned for device/fun0)
|
* (currently, only bus0 is scanned for device/fun0)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ unsigned char bus,dev,fun,hd;
|
|||||||
if (PCI_INVALID_VENDORDEVICEID == d)
|
if (PCI_INVALID_VENDORDEVICEID == d)
|
||||||
continue;
|
continue;
|
||||||
#ifdef PCI_DEBUG
|
#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
|
#endif
|
||||||
(void) pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
|
(void) pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
|
||||||
if (vendorid != s)
|
if (vendorid != s)
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ void bsp_start( void )
|
|||||||
* provided by the RAVEN
|
* provided by the RAVEN
|
||||||
*/
|
*/
|
||||||
/* T. Straumann: give more PCI address space */
|
/* 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
|
* Must have acces to open pic PCI ACK registers
|
||||||
* provided by the RAVEN
|
* provided by the RAVEN
|
||||||
@@ -300,6 +300,21 @@ void bsp_start( void )
|
|||||||
printk("Going to start PCI buses scanning and initialization\n");
|
printk("Going to start PCI buses scanning and initialization\n");
|
||||||
#endif
|
#endif
|
||||||
InitializePCI();
|
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
|
#ifdef SHOW_MORE_INIT_SETTINGS
|
||||||
printk("Number of PCI buses found is : %d\n", BusCountPCI());
|
printk("Number of PCI buses found is : %d\n", BusCountPCI());
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user