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:
Joel Sherrill
2003-06-13 17:39:46 +00:00
parent 9274ea760f
commit 3a3e0b0e7d
11 changed files with 1951 additions and 746 deletions

View File

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

View File

@@ -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.

File diff suppressed because it is too large Load Diff

View File

@@ -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
*/ */
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); _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++) { 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]); */
BSP_irq_disable_at_i8259s (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, openpic_set_source_priority(i - BSP_PCI_IRQ_LOWEST_OFFSET,
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]); */
openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET); {
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++) { 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);

View File

@@ -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 int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*);
typedef struct __rtems_irq_connect_data__ { typedef struct __rtems_irq_connect_data__ {
/* /*
* IRQ line * IRQ line
*/ */
rtems_irq_symbolic_name name; rtems_irq_symbolic_name name;
/* /*
* handler. See comment on handler properties below in function prototype. * handler. See comment on handler properties below in function prototype.
*/ */
rtems_irq_hdl hdl; rtems_irq_hdl hdl;
/* /*
* function for enabling interrupts at device level (ONLY!). * function for enabling interrupts at device level (ONLY!).
* The BSP code will automatically enable it at i8259s level and openpic level. * The BSP code will automatically enable it at i8259s level and openpic level.
* RATIONALE : anyway such code has to exist in current driver code. * RATIONALE : anyway such code has to exist in current driver code.
* It is usually called immediately AFTER connecting the interrupt handler. * It is usually called immediately AFTER connecting the interrupt handler.
* RTEMS may well need such a function when restoring normal interrupt * RTEMS may well need such a function when restoring normal interrupt
* processing after a debug session. * processing after a debug session.
* *
*/ */
rtems_irq_enable on; rtems_irq_enable on;
/* /*
* function for disabling interrupts at device level (ONLY!). * function for disabling interrupts at device level (ONLY!).
* The code will disable it at i8259s level. RATIONALE : anyway * The code will disable it at i8259s level. RATIONALE : anyway
* such code has to exist for clean shutdown. It is usually called * such code has to exist for clean shutdown. It is usually called
* BEFORE disconnecting the interrupt. RTEMS may well need such * BEFORE disconnecting the interrupt. RTEMS may well need such
* a function when disabling normal interrupt processing for * a function when disabling normal interrupt processing for
* a debug session. May well be a NOP function. * a debug session. May well be a NOP function.
*/ */
rtems_irq_disable off; rtems_irq_disable off;
/* /*
* function enabling to know what interrupt may currently occur * function enabling to know what interrupt may currently occur
* 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...

View File

@@ -18,42 +18,178 @@
#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
* that the level/edge are set. * that the level/edge are set.
* 0x200 if this board has a Hawk chip. * 0x200 if this board has a Hawk chip.
*/ */
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;
}

View File

@@ -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 */

View File

@@ -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
*/ */

View File

@@ -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)

View File

@@ -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)

View File

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