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