399 lines
8.8 KiB
C
399 lines
8.8 KiB
C
/*
|
|
* Copyright (c) 1995 FirePower Systems, Inc.
|
|
* DO NOT DISTRIBUTE without permission
|
|
*
|
|
* $RCSfile: pxpciint.c $
|
|
* $Revision: 1.26 $
|
|
* $Date: 1996/05/15 00:06:27 $
|
|
* $Locker: $
|
|
*/
|
|
|
|
/*++
|
|
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ixpciint.c
|
|
|
|
Abstract:
|
|
|
|
All PCI bus interrupt mapping is in this module, so that a real
|
|
system which doesn't have all the limitations which PC PCI
|
|
systems have can replaced this code easly.
|
|
(bus memory & i/o address mappings can also be fix here)
|
|
|
|
Author:
|
|
|
|
Ken Reneris
|
|
Jim Wooldridge - Ported to PowerPC
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "phsystem.h"
|
|
#include "pci.h"
|
|
#include "pcip.h"
|
|
#include "stdio.h"
|
|
#include "fpdebug.h"
|
|
|
|
ULONG PciAllowedInts = 0;
|
|
|
|
#define PCI_DEVICE_VECTOR 0x10
|
|
#define PCI_IO_ADDRESS_SPACE 0x81000000
|
|
|
|
|
|
ULONG HalpGetPciIntVector( PBUS_HANDLER,
|
|
PBUS_HANDLER,
|
|
ULONG,
|
|
ULONG,
|
|
PKIRQL,
|
|
PKAFFINITY );
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,HalpGetPCIIntOnISABus)
|
|
#pragma alloc_text(PAGE,HalpAdjustPCIResourceList)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* HalpGetPciIntVector:
|
|
* This routine is a mirror ( but better ) version of HalpGetPCIIntOnISABus
|
|
*
|
|
*/
|
|
|
|
ULONG
|
|
HalpGetPciIntVector(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG BusInterruptLevel,
|
|
IN ULONG BusInterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
)
|
|
{
|
|
// since we can't see who's asking for an interrupt, must rely upon some
|
|
// known data: First, check to see if there is already one specified out
|
|
// among the pci devices: ( need to keep in mind some stubborn drivers
|
|
// that request several times for a particular interrupt i.e. scsi ).
|
|
//
|
|
// For now, to deal with a screwed up amd scsi driver, permanently map
|
|
// any requests for f ( as well as d which is what firmware sets this
|
|
// device to ) to 0x19, corresponding to the bit in our interrupt word.
|
|
//
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint("HalpGetPciIntVector: %x, %x \n",
|
|
BusInterruptLevel, BusInterruptVector ););
|
|
|
|
#if defined(HALDEBUG_ON)
|
|
if (DBGSET(DBG_INTERRUPTS)) {
|
|
switch( BusInterruptVector ) {
|
|
case 0xd:
|
|
case 0xf:
|
|
HalpDebugPrint(" BusIntVec set to 0x%x \n",
|
|
BusInterruptVector);
|
|
break;
|
|
case 0xe:
|
|
HalpDebugPrint(" BusIntVec set to 0x%x \n",
|
|
BusInterruptVector);
|
|
break;
|
|
default:
|
|
HalpDebugPrint(" BusIntVec unchanged: \n");
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return HalGetInterruptVector (
|
|
Internal, 0,
|
|
BusInterruptLevel,
|
|
BusInterruptVector,
|
|
Irql,
|
|
Affinity
|
|
);
|
|
}
|
|
|
|
ULONG
|
|
HalpGetPCIIntOnISABus (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG BusInterruptLevel,
|
|
IN ULONG BusInterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
)
|
|
{
|
|
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint("HalpGetPCIIntOnIsaBus: 0x%x, 0x%x, %x, %x, %x, %x \n",
|
|
BusHandler,
|
|
RootHandler,
|
|
BusInterruptLevel,
|
|
BusInterruptVector,
|
|
*Irql,
|
|
*Affinity ););
|
|
if (BusInterruptLevel < 1) {
|
|
// bogus bus level
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Check that the requested interrupt is valid and return 0
|
|
// if the interrupt is not in the allowed set of interrupts.
|
|
if (((1 << BusInterruptVector) & PciAllowedInts) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//
|
|
// For FirePOWER, pci interrupts are not mapped onto the isa bus ( with the
|
|
// exception of the amd ethernet drive which will always believe it's isa )
|
|
// so for the moment map their "isa" int values so that they're picked up
|
|
// correctly by HalpGetSystem...
|
|
//
|
|
switch( BusInterruptVector ) {
|
|
case 0xa:
|
|
//
|
|
// For now, map this vector back down to ISA level since the
|
|
// audio driver is confused, thinking it's on the pci bus.
|
|
//
|
|
//BusInterruptVector = 0xa - PCI_DEVICE_VECTOR;
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint("%sVector is not PCI based vector: 0x%x\n",
|
|
" ", BusInterruptVector ););
|
|
break;
|
|
case 0xd:
|
|
case 0xf:
|
|
BusInterruptVector = 0xd +0xc ;
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint(" BusIntVect set to 0x19 \n"););
|
|
break;
|
|
case 0xe:
|
|
BusInterruptVector = 0xe +0xc;
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint(" BusIntVect set to 0x1a \n"););
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint("%sBusInterruptVector set to: 0x%x \n",
|
|
" ", BusInterruptVector););
|
|
//BusInterruptVector += PCI_DEVICE_VECTOR;
|
|
BusInterruptLevel = BusInterruptVector;
|
|
HDBG(DBG_INTERRUPTS,
|
|
HalpDebugPrint("%sBusIntVec set to 0x%x \n",
|
|
" ", BusInterruptVector););
|
|
|
|
//
|
|
// Current PCI buses just map their IRQs ontop of the ISA space,
|
|
// so foreward this to the isa handler for the isa vector
|
|
// (the isa vector was saved away at either HalSetBusData or
|
|
// IoAssignReosurces time - if someone is trying to connect a
|
|
// PCI interrupt without performing one of those operations first,
|
|
// they are broken).
|
|
//
|
|
|
|
return HalGetInterruptVector (
|
|
Internal, 0,
|
|
BusInterruptLevel,
|
|
BusInterruptVector,
|
|
Irql,
|
|
Affinity
|
|
);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
// Routine Description: VOID HalpPCIPin2ISALine ()
|
|
//
|
|
// This function maps the device's InterruptPin to an InterruptLine
|
|
// value.
|
|
//
|
|
// On Sandalfoot and Polo machines PCI interrupts are statically routed
|
|
// via slot number. This routine just returns and the static routing
|
|
// is done in HalpGetIsaFixedPCIIrq
|
|
//
|
|
|
|
--*/
|
|
|
|
VOID
|
|
HalpPCIPin2ISALine (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
Routine Description: VOID HalpPCIISALine2Pin ()
|
|
This functions maps the device's InterruptLine to it's
|
|
device specific InterruptPin value.
|
|
|
|
|
|
--*/
|
|
|
|
VOID
|
|
HalpPCIISALine2Pin (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciNewData,
|
|
IN PPCI_COMMON_CONFIG PciOldData
|
|
)
|
|
{
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: VOID HalpPCIISALine2Pin ()
|
|
|
|
Translate PCI bus address.
|
|
Verify the address is within the range of the bus.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or error
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
HalpTranslatePCIBusAddress (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PHYSICAL_ADDRESS BusAddress,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
|
)
|
|
{
|
|
BOOLEAN status;
|
|
PPCIPBUSDATA BusData;
|
|
|
|
if (BusAddress.HighPart) {
|
|
return FALSE;
|
|
}
|
|
|
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
|
switch (*AddressSpace) {
|
|
case MEMORY_ADDRESS_SPACE:
|
|
//
|
|
// verify memory address is within PCI buses memory limits
|
|
//
|
|
status = BusAddress.LowPart >= BusData->MemoryBase &&
|
|
BusAddress.LowPart <= BusData->MemoryLimit;
|
|
|
|
if (!status) {
|
|
status = BusAddress.LowPart >= BusData->PFMemoryBase &&
|
|
BusAddress.LowPart <= BusData->PFMemoryLimit;
|
|
}
|
|
|
|
break;
|
|
//
|
|
// Everyone should be assumed IO space if not otherwise requested
|
|
//
|
|
default:
|
|
case IO_ADDRESS_SPACE:
|
|
//
|
|
// verify memory address is within PCI buses io limits
|
|
//
|
|
status = BusAddress.LowPart >= BusData->IOBase &&
|
|
BusAddress.LowPart <= BusData->IOLimit;
|
|
break;
|
|
|
|
case SYSTEM_ADDRESS_SPACE:
|
|
// #pragma NOTE("SYSTEM_ADDRESS_SPACE, verify?")
|
|
status = BusAddress.LowPart < BusData->IOBase &&
|
|
BusAddress.LowPart >= 0;
|
|
break;
|
|
|
|
}
|
|
|
|
if (!status) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Valid address for this bus - foreward it to the parent bus
|
|
//
|
|
|
|
return BusHandler->ParentHandler->TranslateBusAddress (
|
|
BusHandler->ParentHandler,
|
|
RootHandler,
|
|
BusAddress,
|
|
AddressSpace,
|
|
TranslatedAddress
|
|
);
|
|
}
|
|
|
|
|
|
/*++
|
|
Routine Description: NTSTATUS HalpAdjustPCIResourceList ()
|
|
Rewrite the callers requested resource list to fit within
|
|
the supported ranges of this bus
|
|
--*/
|
|
|
|
NTSTATUS
|
|
HalpAdjustPCIResourceList (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PPCIPBUSDATA BusData;
|
|
PCI_SLOT_NUMBER PciSlot;
|
|
UCHAR IrqTable[255];
|
|
PFPHAL_BUSNODE FpNode;
|
|
|
|
FpNode = (PFPHAL_BUSNODE) BusHandler->BusData;
|
|
// BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
|
BusData = (PPCIPBUSDATA) &(FpNode->Bus);
|
|
PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber);
|
|
|
|
//
|
|
// Determine PCI device's interrupt restrictions
|
|
//
|
|
// ======= Here's where thePCI interrupts are determined and set as a
|
|
// result of the call to HalpAdjustResourceListLimits
|
|
|
|
RtlZeroMemory(IrqTable, sizeof (IrqTable));
|
|
Status = BusData->GetIrqTable(BusHandler, RootHandler, PciSlot, IrqTable);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Adjust resources
|
|
//
|
|
|
|
return HalpAdjustResourceListLimits (
|
|
BusHandler, RootHandler, pResourceList,
|
|
BusData->MemoryBase, BusData->MemoryLimit,
|
|
BusData->PFMemoryBase, BusData->PFMemoryLimit,
|
|
BusData->LimitedIO,
|
|
BusData->IOBase, BusData->IOLimit,
|
|
IrqTable, 0xff,
|
|
0, 0xffff // dma
|
|
);
|
|
}
|
|
|