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