371 lines
8.1 KiB
C
371 lines
8.1 KiB
C
|
/*
|
||
|
* VLSI.C - VLSI Wildcat PCI chipset routines.
|
||
|
*
|
||
|
* Notes:
|
||
|
* Algorithms from VLSI VL82C596/7 spec.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "local.h"
|
||
|
|
||
|
#define NUM_VLSI_IRQ (sizeof(rgbIndexToIRQ)/sizeof(rgbIndexToIRQ[0]))
|
||
|
|
||
|
const UCHAR rgbIndexToIRQ[] = { 3, 5, 9, 10, 11, 12, 14, 15 };
|
||
|
|
||
|
#define INDEX_UNUSED ((ULONG)-1)
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* VLSISetIRQ - Set a VLSI PCI link to a specific IRQ
|
||
|
*
|
||
|
* Exported.
|
||
|
*
|
||
|
* ENTRY: bIRQNumber is the new IRQ to be used.
|
||
|
*
|
||
|
* bLink is the Link to be set.
|
||
|
*
|
||
|
* EXIT: Standard PCIMP return value.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
PCIMPRET CDECL
|
||
|
VLSISetIRQ(UCHAR bIRQNumber, UCHAR bLink)
|
||
|
{
|
||
|
ULONG ulNewIRQIndex;
|
||
|
ULONG rgbIRQSteering[NUM_IRQ_PINS];
|
||
|
ULONG ulMask;
|
||
|
ULONG ulUnusedIndex;
|
||
|
ULONG ulVLSIRegister;
|
||
|
ULONG ulIRQIndex;
|
||
|
ULONG i;
|
||
|
|
||
|
//
|
||
|
// Make link number 0 based, and validate.
|
||
|
//
|
||
|
bLink--;
|
||
|
if (bLink > 3) {
|
||
|
|
||
|
return(PCIMP_INVALID_LINK);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find the VLSI index of the new IRQ.
|
||
|
//
|
||
|
if (bIRQNumber) {
|
||
|
|
||
|
//
|
||
|
// Look through the list of valid indicies.
|
||
|
//
|
||
|
for (ulNewIRQIndex=0; ulNewIRQIndex<NUM_VLSI_IRQ; ulNewIRQIndex++)
|
||
|
{
|
||
|
if (rgbIndexToIRQ[ulNewIRQIndex] == bIRQNumber)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If there is no VLSI equivalent, bail.
|
||
|
//
|
||
|
if (ulNewIRQIndex==NUM_VLSI_IRQ) {
|
||
|
|
||
|
return(PCIMP_INVALID_IRQ);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Blowing away this interrupt.
|
||
|
//
|
||
|
ulNewIRQIndex = INDEX_UNUSED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Read in the VLSI Interrupt Steering Register.
|
||
|
//
|
||
|
ulVLSIRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x74);
|
||
|
|
||
|
//
|
||
|
// Compute the complete IRQ mapping.
|
||
|
//
|
||
|
for (i=0, ulMask=0x07; i<NUM_IRQ_PINS; i++, ulMask<<=4)
|
||
|
{
|
||
|
ulIRQIndex = (ulVLSIRegister & ulMask) >> (i * 4);
|
||
|
|
||
|
if ((ulVLSIRegister & (1 << (ulIRQIndex + 16))) != 0)
|
||
|
{
|
||
|
rgbIRQSteering[i] = ulIRQIndex;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rgbIRQSteering[i] = INDEX_UNUSED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update the IRQ Mapping with the new IRQ.
|
||
|
//
|
||
|
rgbIRQSteering[bLink] = ulNewIRQIndex;
|
||
|
|
||
|
//
|
||
|
// Find an unused IRQ index.
|
||
|
//
|
||
|
for (ulUnusedIndex=0; ulUnusedIndex<NUM_VLSI_IRQ; ulUnusedIndex++)
|
||
|
{
|
||
|
for (i=0; i<NUM_IRQ_PINS; i++)
|
||
|
{
|
||
|
if (rgbIRQSteering[i] == ulUnusedIndex)
|
||
|
break;
|
||
|
}
|
||
|
if (i == NUM_IRQ_PINS)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Compute the new VLSI Interrupt Steering Register.
|
||
|
//
|
||
|
ulVLSIRegister = 0x00000000;
|
||
|
for (i=0; i<NUM_IRQ_PINS; i++)
|
||
|
{
|
||
|
if (rgbIRQSteering[i] == INDEX_UNUSED)
|
||
|
{
|
||
|
ulVLSIRegister |= ulUnusedIndex << (4*i);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulVLSIRegister |= rgbIRQSteering[i] << (4*i);
|
||
|
ulVLSIRegister |= 1 << (rgbIRQSteering[i] + 16);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Write out the new VLSI Interrupt Steering Register.
|
||
|
//
|
||
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x74, ulVLSIRegister);
|
||
|
|
||
|
return(PCIMP_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* VLSIGetIRQ - Get the IRQ of a VLSI PCI link
|
||
|
*
|
||
|
* Exported.
|
||
|
*
|
||
|
* ENTRY: pbIRQNumber is the buffer to fill.
|
||
|
*
|
||
|
* bLink is the Link to be read.
|
||
|
*
|
||
|
* EXIT: Standard PCIMP return value.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
PCIMPRET CDECL
|
||
|
VLSIGetIRQ(PUCHAR pbIRQNumber, UCHAR bLink)
|
||
|
{
|
||
|
ULONG ulVLSIRegister;
|
||
|
ULONG ulIndex;
|
||
|
UCHAR bIRQ;
|
||
|
|
||
|
//
|
||
|
// Make link number 0 based, and validate.
|
||
|
//
|
||
|
bLink--;
|
||
|
if (bLink > 3) {
|
||
|
|
||
|
return(PCIMP_INVALID_LINK);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Read in the VLSI Interrupt Steering Register.
|
||
|
//
|
||
|
ulVLSIRegister=ReadConfigUchar(bBusPIC, bDevFuncPIC, 0x74);
|
||
|
|
||
|
//
|
||
|
// Find the link's IRQ value.
|
||
|
//
|
||
|
ulIndex = (ulVLSIRegister >> (bLink*4)) & 0x7;
|
||
|
bIRQ = rgbIndexToIRQ[ulIndex];
|
||
|
|
||
|
//
|
||
|
// Make sure the IRQ is marked as in use.
|
||
|
//
|
||
|
if ((ulVLSIRegister & (1 << (ulIndex + 16))) == 0)
|
||
|
{
|
||
|
bIRQ = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the return buffer.
|
||
|
//
|
||
|
*pbIRQNumber = bIRQ;
|
||
|
|
||
|
return(PCIMP_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* VLSISetTrigger - Set the IRQ triggering values for the VLSI.
|
||
|
*
|
||
|
* Exported.
|
||
|
*
|
||
|
* ENTRY: ulTrigger has bits set for Level triggered IRQs.
|
||
|
*
|
||
|
* EXIT: Standard PCIMP return value.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
PCIMPRET CDECL
|
||
|
VLSISetTrigger(ULONG ulTrigger)
|
||
|
{
|
||
|
ULONG ulAssertionRegister;
|
||
|
ULONG ulPMAssertionRegister;
|
||
|
ULONG i;
|
||
|
|
||
|
//
|
||
|
// Read in the Interrupt Assertion Level register.
|
||
|
//
|
||
|
ulAssertionRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x5C);
|
||
|
|
||
|
//
|
||
|
// Clear off the old edge/level settings.
|
||
|
//
|
||
|
ulAssertionRegister &= ~0xff;
|
||
|
|
||
|
//
|
||
|
// For each VLSI interrupt...
|
||
|
//
|
||
|
for (i=0; i<NUM_VLSI_IRQ; i++)
|
||
|
{
|
||
|
//
|
||
|
// If the corresponding bit is set to level...
|
||
|
//
|
||
|
|
||
|
if (ulTrigger & (1 << rgbIndexToIRQ[i]))
|
||
|
{
|
||
|
//
|
||
|
// Set the corresponding bit in the
|
||
|
// Assertion Register.
|
||
|
//
|
||
|
ulAssertionRegister |= 1 << i;
|
||
|
|
||
|
//
|
||
|
// And clear the bit from ulTrigger.
|
||
|
//
|
||
|
ulTrigger &= ~(1 << rgbIndexToIRQ[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the caller wanted some non-VLSI IRQs level, bail.
|
||
|
//
|
||
|
if (ulTrigger)
|
||
|
{
|
||
|
return(PCIMP_INVALID_IRQ);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the Assertion Register.
|
||
|
//
|
||
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x5C, ulAssertionRegister);
|
||
|
|
||
|
//
|
||
|
// Read in the Power Mgmt edge/level setting.
|
||
|
//
|
||
|
ulPMAssertionRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x78);
|
||
|
|
||
|
//
|
||
|
// Clear off the old edge/level settings.
|
||
|
//
|
||
|
ulPMAssertionRegister &= ~0xff;
|
||
|
|
||
|
//
|
||
|
// Copy the new edge/level settings.
|
||
|
//
|
||
|
ulPMAssertionRegister |= ulAssertionRegister & 0xff;
|
||
|
|
||
|
//
|
||
|
// Set the Power Mgmt Assertion Register.
|
||
|
//
|
||
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x78, ulPMAssertionRegister);
|
||
|
|
||
|
return(PCIMP_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* VLSIGetTrigger - Get the IRQ triggering values for the VLSI.
|
||
|
*
|
||
|
* Exported.
|
||
|
*
|
||
|
* ENTRY: pulTrigger will have bits set for Level triggered IRQs.
|
||
|
*
|
||
|
* EXIT: TRUE if successful.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
PCIMPRET CDECL
|
||
|
VLSIGetTrigger(PULONG pulTrigger)
|
||
|
{
|
||
|
ULONG ulAssertionRegister;
|
||
|
ULONG i;
|
||
|
|
||
|
//
|
||
|
// Read in the Interrupt Assertion Level register.
|
||
|
//
|
||
|
ulAssertionRegister = ReadConfigUchar(bBusPIC, bDevFuncPIC, 0x5C);
|
||
|
|
||
|
//
|
||
|
// Clear the return buffer.
|
||
|
//
|
||
|
*pulTrigger = 0;
|
||
|
|
||
|
//
|
||
|
// For each VLSI interrupt...
|
||
|
//
|
||
|
for (i=0; i<NUM_VLSI_IRQ; i++)
|
||
|
{
|
||
|
//
|
||
|
// If the corresponding bit is set to level...
|
||
|
//
|
||
|
if (ulAssertionRegister & (1 << i))
|
||
|
{
|
||
|
//
|
||
|
// Set the corresponding bit in the
|
||
|
// return buffer.
|
||
|
//
|
||
|
*pulTrigger |= 1 << rgbIndexToIRQ[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(PCIMP_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* VLSIValidateTable - Validate an IRQ table
|
||
|
*
|
||
|
* Exported.
|
||
|
*
|
||
|
* ENTRY: piihIRQInfoHeader points to an IRQInfoHeader followed
|
||
|
* by an IRQ Routing Table.
|
||
|
*
|
||
|
* ulFlags are PCIMP_VALIDATE flags.
|
||
|
*
|
||
|
* EXIT: Standard PCIMP return value.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
PCIMPRET CDECL
|
||
|
VLSIValidateTable(PIRQINFOHEADER piihIRQInfoHeader, ULONG ulFlags);
|
||
|
#pragma alloc_text(PAGE, VLSIValidateTable)
|
||
|
#endif //ALLOC_PRAGMA
|
||
|
|
||
|
PCIMPRET CDECL
|
||
|
VLSIValidateTable(PIRQINFOHEADER piihIRQInfoHeader, ULONG ulFlags)
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
if (GetMaxLink(piihIRQInfoHeader)>0x04) {
|
||
|
|
||
|
return(PCIMP_FAILURE);
|
||
|
}
|
||
|
|
||
|
return(PCIMP_SUCCESS);
|
||
|
}
|
||
|
|