windows-nt/Source/XPSP1/NT/base/hals/pciirqmp/i386/vlsi.c
2020-09-26 16:20:57 +08:00

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);
}