diff options
Diffstat (limited to 'private/ntos/nthals/halfire/ppc/pxisabus.c')
-rw-r--r-- | private/ntos/nthals/halfire/ppc/pxisabus.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/private/ntos/nthals/halfire/ppc/pxisabus.c b/private/ntos/nthals/halfire/ppc/pxisabus.c new file mode 100644 index 000000000..59c62c743 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxisabus.c @@ -0,0 +1,576 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxisabus.c $ + * $Revision: 1.21 $ + * $Date: 1996/05/14 02:34:36 $ + * $Locker: $ + */ + +/*++ + + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + pxisabus.c + +Abstract: + +Author: + +Environment: + +Revision History: + + +--*/ + +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" + +ULONG +HalpGetIsaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +#define TBS " " + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetIsaInterruptVector) +#pragma alloc_text(PAGE,HalpAdjustIsaResourceList) +#pragma alloc_text(PAGE,HalpAdjustResourceListLimits) +#endif + + + +/*++ + +Routine Description: ULONG HalpGetIsaInterruptVector() + + This function returns the system interrupt vector and IRQL level + corresponding to the specified bus interrupt level and/or vector. The + system interrupt vector and IRQL are suitable for use in a subsequent call + to KeInitializeInterrupt. + +Arguments: + + BusHandle - Per bus specific structure + + Irql - Returns the system request priority. + + Affinity - Returns the system wide irq affinity. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +ULONG +HalpGetIsaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + + // + // irq2 shows up on irq9 + // + + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetIsaInterruptVector: 0x%x, 0x%x, 0x%x 0x%x \n", + BusInterruptLevel, BusInterruptVector, *Irql, *Affinity );); + + if (BusInterruptLevel == 2) { + BusInterruptLevel = 9; + BusInterruptVector = 9; + } + + // + // Hack Hack: + // + // NOTE: NOTE: + // The Ethernet driver reports itself as an ISA device but with a + // PCI interrupt so need to fixup the interrupt if it looks correct + // for the pci bus vector: + if (BusInterruptLevel > 15) { + return 0; + } + + // + // There are 4 cases to check here: + // A) One of the entries ( BusIntLvl || BusIntVec ) is zero, + // B) Both of the entries are the same value, + // C) One of the entries is == 5 ( Which is the SPL for external + // devices on PowerPC NT ) + // D) none of the above + // + switch(BusInterruptLevel) { + case 0: + if (BusInterruptVector) { + BusInterruptLevel = BusInterruptVector; + } else { + // they're both zero, so hope this is the profile int. + } + break; + case 5: + // + // In this case, BusInterruptLevel is probably indicating the + // system SPL for external ints, so assume the BusInterruptVector + // contains the real interrupt info + // + + break; + default: + // + // Since BusInterruptLevel is nonzero and not equal to 5, then see + // if BusInterruptVector is zero or equal to 5. If it's neither, + // then print out the level and vector values and spin since this + // is a combination I've never seen before. + // + if( BusInterruptVector ) { + ULONG tmp; + if( BusInterruptVector == (BusInterruptLevel + 0x20) ) { + + BusInterruptVector = BusInterruptLevel; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetISAInt: BusIntVec(0x%x) = BusIntLvl(0x%x) +0x20 \n", + BusInterruptVector, BusInterruptLevel )); + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetISAInt: ****** Please Fix Driver to use BusInterruptVector correctly \n")); +// NOTE("Hack for audio driver to work") + } + if(( BusInterruptLevel != BusInterruptVector) + && ( BusInterruptVector != 5 )) { + HalpDebugPrint("Wierd BusIntVec & BusIntLvl (spin now)\n"); + HalpDebugPrint(" BusIntLvl = 0x%x, BusIntVec = 0x%x\n", + BusInterruptLevel, BusInterruptVector ); + for (;;) { + } + } + // + // Here, BusInterruptVector is known to be non-zero, = 5 or + // BusLevel. So, assume it's the 5 choice and swap it with + // level. + // + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("\t\tSwap BusIntLvl & BusIntVec %x, %x...\n", + BusInterruptLevel, BusInterruptVector);); + tmp = BusInterruptLevel; + BusInterruptLevel = BusInterruptVector; + BusInterruptVector = tmp; + // + // Now, BusInterruptVector has the interesting value so the + // HalpGetSystemInterrupt can correctly key on + // BusInterruptVector. + // + } else { + // + // since BusInterruptVector is zero + // + BusInterruptVector = BusInterruptLevel; + } + } + + // + // Get parent's translation from here.. + // + return BusHandler->ParentHandler->GetInterruptVector ( + BusHandler->ParentHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); +} + + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +{ + UCHAR Irq[15], c; + + for (c=0; c < 15; c++) { + Irq[c] = IRQ_VALID; + } + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpAdjustIsaResourceList: called\n")); + + return HalpAdjustResourceListLimits ( + BusHandler, RootHandler, pResourceList, + 0, 0xffffff, // Bus supports up to memory 0xFFFFFF + 0, 0, // No special range for prefetch + FALSE, + 0, 0xffff, // Bus supports up to I/O port 0xFFFF + Irq, 15, // Bus supports up to 15 IRQs + 0, 7 // Bus supports up to Dma channel 7 + ); +} + + +NTSTATUS +HalpAdjustResourceListLimits ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN ULONG MinimumMemoryAddress, + IN ULONG MaximumMemoryAddress, + IN ULONG MinimumPrefetchMemoryAddress, + IN ULONG MaximumPrefetchMemoryAddress, + IN BOOLEAN LimitedIOSupport, + IN ULONG MinimumPortAddress, + IN ULONG MaximumPortAddress, + IN PUCHAR IrqTable, + IN ULONG IrqTableSize, + IN ULONG MinimumDmaChannel, + IN ULONG MaximumDmaChannel + ) +{ + PIO_RESOURCE_REQUIREMENTS_LIST InCompleteList, OutCompleteList; + PIO_RESOURCE_LIST InResourceList, OutResourceList; + PIO_RESOURCE_DESCRIPTOR InDesc, OutDesc, HeadOutDesc; + BOOLEAN GotPFRange, FirstDescBuilt; + ULONG len, alt, cnt, i; + UCHAR LastIrqState, NewIrqState; + ULONG PFAddress, icnt, pcnt; + + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalpAdjustResourceListLimits: BusHandler=0x%08x, ResList=0x%08x\n", + BusHandler, pResourceList);); + + InCompleteList = *pResourceList; + len = InCompleteList->ListSize; + PFAddress = + MinimumPrefetchMemoryAddress || MaximumPrefetchMemoryAddress ? 1 : 0; + icnt = 0; + pcnt = 0; + + // + // Worste case, add an extra interrupt descriptor for every different + // IRQ range present + // + + LastIrqState = 0; + for (i=0; i < IrqTableSize; i++) { + if (IrqTable[i] != LastIrqState) { + icnt += 1; + LastIrqState = IrqTable[i]; + } + } + + // + // If LimitiedIOSupport, then the supported I/O ranges are + // limited to 256bytes on every 1K aligned boundry within the + // range specified. Worste case add an extra N descriptors for + // every I/O range passed. + // + + if (LimitedIOSupport && MaximumPortAddress > MinimumPortAddress) { + pcnt = (MaximumPortAddress - MinimumPortAddress) / 1024; + } + + // + // Scan input list - verify revision #'s, and increase len varible + // by amount output list may increase. + // + + i = 0; + InResourceList = InCompleteList->List; + for (alt=0; alt < InCompleteList->AlternativeLists; alt++) { + if (InResourceList->Version != 1 || InResourceList->Revision < 1) { + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sVersion is not 1, or revision is < 1.\n", + TBS);); + return STATUS_INVALID_PARAMETER; + } + + InDesc = InResourceList->Descriptors; + for (cnt = InResourceList->Count; cnt; cnt--) { + switch (InDesc->Type) { + case CmResourceTypePort: i += pcnt; break; + case CmResourceTypeInterrupt: i += icnt; break; + case CmResourceTypeMemory: i += PFAddress; break; + case CmResourceTypeDma: break; + default: + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sINVALID PARAM ..InDesc->Type: 0x%x\n", + TBS,InDesc->Type);); + return STATUS_INVALID_PARAMETER; + } + + // Next descriptor + InDesc++; + } + + // Next Resource List + InResourceList = (PIO_RESOURCE_LIST) InDesc; + } + len += i * sizeof (IO_RESOURCE_DESCRIPTOR); + + // + // Allocate output list + // + + OutCompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) + ExAllocatePool (PagedPool, len); + + if (!OutCompleteList) { + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sOutCompleteList is null ( No memory? ) \n",TBS);); + return STATUS_NO_MEMORY; + } + + // + // Walk each ResourceList and build output structure + // + + InResourceList = InCompleteList->List; + *OutCompleteList = *InCompleteList; + OutResourceList = OutCompleteList->List; + + for (alt=0; alt < InCompleteList->AlternativeLists; alt++) { + OutResourceList->Version = 1; + OutResourceList->Revision = 1; + + InDesc = InResourceList->Descriptors; + OutDesc = OutResourceList->Descriptors; + HeadOutDesc = OutDesc; + + for (cnt = InResourceList->Count; cnt; cnt--) { + + // + // Copy descriptor + // + + *OutDesc = *InDesc; + + // + // Limit desctiptor to be with the buses supported ranges + // + + switch (OutDesc->Type) { + case CmResourceTypePort: + if (OutDesc->u.Port.MinimumAddress.QuadPart < MinimumPortAddress) { + OutDesc->u.Port.MinimumAddress.QuadPart = MinimumPortAddress; + } + + if (OutDesc->u.Port.MaximumAddress.QuadPart > MaximumPortAddress) { + OutDesc->u.Port.MaximumAddress.QuadPart = MaximumPortAddress; + } + + if (!LimitedIOSupport) { + break; + } + + // In the case of LimitiedIOSupport the caller will only + // pass in 1K aligned values + + FirstDescBuilt = FALSE; + for (i = MinimumPortAddress; i < MaximumPortAddress; i += 1024) { + if (InDesc->u.Port.MinimumAddress.QuadPart < i) { + OutDesc->u.Port.MinimumAddress.QuadPart = i; + } + + if (InDesc->u.Port.MaximumAddress.QuadPart > i + 256) { + OutDesc->u.Port.MaximumAddress.QuadPart = i + 256; + } + + if (OutDesc->u.Port.MinimumAddress.QuadPart <= + OutDesc->u.Port.MaximumAddress.QuadPart) { + + // + // Valid I/O descriptor build, start another one. + // + + FirstDescBuilt = TRUE; + + OutDesc++; + *OutDesc = *InDesc; + OutDesc->Option |= IO_RESOURCE_ALTERNATIVE; + } + } + + if (FirstDescBuilt) { + OutDesc--; + } + break; + + case CmResourceTypeInterrupt: + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpAdjustResourceListLimits: new CmResourceTypeInterrupt \n");); + + // + // Build a list of interrupt descriptors which are + // a subset of the IrqTable and the current descriptor + // passed in on the input list. + // + + FirstDescBuilt = FALSE; + LastIrqState = 0; + + for (i=0; i < IrqTableSize; i++) { + NewIrqState = IrqTable[i]; + + while (LastIrqState != NewIrqState) { + if (LastIrqState) { + OutDesc++; // done with last desc + LastIrqState = 0; // new state + continue; + } + + // + // Start a new descriptor + // + + *OutDesc = *InDesc; + OutDesc->u.Interrupt.MinimumVector = i; + if (NewIrqState & IRQ_PREFERRED) { + OutDesc->Option |= IO_RESOURCE_PREFERRED; + } + + if (FirstDescBuilt) { + OutDesc->Option |= IO_RESOURCE_ALTERNATIVE; + } + + LastIrqState = NewIrqState; + FirstDescBuilt = TRUE; + } + + OutDesc->u.Interrupt.MaximumVector = i; + } + + if (!LastIrqState) { + if (!FirstDescBuilt) { + OutDesc->u.Interrupt.MinimumVector = + IrqTableSize + 1; + } else { + OutDesc--; + } + } + + break; + + case CmResourceTypeMemory: + if (PFAddress && (OutDesc->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) ) { + // + // There's a Prefetch range & this resource supports + // Prefetching. Build two descriptors - one for the + // supported Prefetch range as preferred, and the other + // normal memory range. + // + + OutDesc->Option |= IO_RESOURCE_PREFERRED; + + if (OutDesc->u.Memory.MinimumAddress.QuadPart < MinimumPrefetchMemoryAddress) { + OutDesc->u.Memory.MinimumAddress.QuadPart = MinimumPrefetchMemoryAddress; + } + + if (OutDesc->u.Memory.MaximumAddress.QuadPart > MaximumPrefetchMemoryAddress) { + OutDesc->u.Memory.MaximumAddress.QuadPart = MaximumPrefetchMemoryAddress; + } + + GotPFRange = FALSE; + if (OutDesc->u.Memory.MaximumAddress.QuadPart >= + OutDesc->u.Memory.MinimumAddress.QuadPart) { + + // + // got a valid descriptor in the Prefetch range, keep it, + // + + OutDesc++; + GotPFRange = TRUE; + } + + *OutDesc = *InDesc; + + if (GotPFRange) { + // next descriptor is an alternative + OutDesc->Option |= IO_RESOURCE_ALTERNATIVE; + } + } + + // + // Fill in memory descriptor for range + // + + if (OutDesc->u.Memory.MinimumAddress.QuadPart < MinimumMemoryAddress) { + OutDesc->u.Memory.MinimumAddress.QuadPart = MinimumMemoryAddress; + } + + if (OutDesc->u.Memory.MaximumAddress.QuadPart > MaximumMemoryAddress) { + OutDesc->u.Memory.MaximumAddress.QuadPart = MaximumMemoryAddress; + } + break; + + case CmResourceTypeDma: + if (OutDesc->u.Dma.MinimumChannel < MinimumDmaChannel) { + OutDesc->u.Dma.MinimumChannel = MinimumDmaChannel; + } + + if (OutDesc->u.Dma.MaximumChannel > MaximumDmaChannel) { + OutDesc->u.Dma.MaximumChannel = MaximumDmaChannel; + } + break; + +#if DBG + default: + DbgPrint ("HalAdjustResourceList: Unkown resource type\n"); + break; +#endif + } + + // + // Next descriptor + // + + InDesc++; + OutDesc++; + } + + OutResourceList->Count = OutDesc - HeadOutDesc; + + // + // Next Resource List + // + + InResourceList = (PIO_RESOURCE_LIST) InDesc; + OutResourceList = (PIO_RESOURCE_LIST) OutDesc; + } + + // + // Free input list, and return output list + // + + ExFreePool (InCompleteList); + + OutCompleteList->ListSize = + (ULONG) ((PUCHAR) OutResourceList - (PUCHAR) OutCompleteList); + *pResourceList = OutCompleteList; + return STATUS_SUCCESS; +} |