summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halsable/alpha/addrsup.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halsable/alpha/addrsup.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halsable/alpha/addrsup.c')
-rw-r--r--private/ntos/nthals/halsable/alpha/addrsup.c883
1 files changed, 883 insertions, 0 deletions
diff --git a/private/ntos/nthals/halsable/alpha/addrsup.c b/private/ntos/nthals/halsable/alpha/addrsup.c
new file mode 100644
index 000000000..93fdf47dd
--- /dev/null
+++ b/private/ntos/nthals/halsable/alpha/addrsup.c
@@ -0,0 +1,883 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ tbaqva.c (addrsup.c)
+
+Abstract:
+
+ This module contains the platform dependent code to create bus addreses
+ and QVAs for the Sable system.
+
+Author:
+
+ Joe Notarangelo 26-Oct-1993
+ Steve Jenness 26-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+#include "pci.h"
+#include "pcip.h"
+
+
+typedef PVOID QUASI_VIRTUAL_ADDRESS;
+
+QUASI_VIRTUAL_ADDRESS
+HalCreateQva(
+ IN PHYSICAL_ADDRESS PA,
+ IN PVOID VA
+ );
+
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system physical address for a specified I/O bus
+ address. The return value is suitable for use in a subsequent call to
+ MmMapIoSpace.
+
+Arguments:
+
+ BusHandler - Registered BUS_HANDLER for the target configuration space
+ Supplies the bus handler (bus no, interface type).
+
+ RootHandler - Registered BUS_HANDLER for the orginating
+ HalTranslateBusAddress request.
+
+ BusAddress - Supplies the bus relative address.
+
+ AddressSpace - Supplies the address space number for the device: 0 for
+ memory and 1 for I/O space. If the desired access mode is user mode,
+ then bit 1 must be TRUE.
+
+ TranslatedAddress - Supplies a pointer to return the translated address
+
+
+Notes:
+
+ This is a variation of what began in the MIPS code. The intel code often
+ assumes that if an address is in I/O space, the bottom 32 bits of the
+ physical address can be used "like" a virtual address, and are returned
+ to the user. This doesn't work on MIPs machines where physical
+ addresses can be larger than 32 bits.
+
+ Since we are using superpage addresses for I/O on Alpha, we can do
+ almost what is done on intel. If AddressSpace is equal to 0 or 1, then
+ we assume the user is doing kernel I/O and we call
+ HalCreateQva to build a Quasi Virtual Address and return
+ that to the caller. We then set AddressSpace to a 1, so that the caller
+ will not call MmMapIoSpace. The Caller will use the low 32 bits of the
+ physical address we return as the VA. (Which we built a QVA in).
+ If the caller wants to access EISA I/O or Memory through user mode, then
+ the caller must set bit 1 in AddressSpace to a 1 (AddressSpace=2 or 3,
+ depending on whether EISA I/O or Memory), then the caller is returned the
+ 34 bit Physical address. The caller will then call MmMapIoSpace, or
+ ZwMapViewOfSection which in turn calls HalCreateQva to build a QVA out
+ of a VA mapped through the page tables.
+
+ **** Note ****
+
+ The QVA in user mode can only be used via the user-mode access macros.
+
+
+
+Return Value:
+
+ A return value of TRUE indicates that a system physical address
+ corresponding to the supplied bus relative address and bus address
+ number has been returned in TranslatedAddress.
+
+ A return value of FALSE occurs if the translation for the address was
+ not possible
+
+--*/
+
+{
+ INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType;
+ ULONG BusNumber;
+ PVOID va = 0; // note, this is used for a placeholder
+
+ //
+ // The only buses available on Sable are an EISA bus and a PCI bus.
+ // We support any translations for EISA devices as well, though
+ // if they are true EISA devices they won't even be able to plug into
+ // the connectors!
+ //
+
+ if ( (InterfaceType != Isa) &&
+ (InterfaceType != Eisa) &&
+ (InterfaceType != PCIBus) &&
+ (InterfaceType != Internal) ) {
+
+ //
+ // Not on this system return nothing.
+ //
+
+#if HALDBG
+ DbgPrint( "HalTBA: Unhandled interface type = %x\n", InterfaceType );
+#endif // HALDBG
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+
+ //
+ // BusData is valid only for the PCI bus.
+ //
+
+ if( (InterfaceType == PCIBus) &&
+ (BusHandler != NULL) &&
+ (BusHandler->BusData != NULL) ) {
+
+ BusNumber = ((PPCIPBUSDATA)(BusHandler->BusData))->HwBusNumber;
+
+ } else {
+
+ //
+ // smdfix: (What should we do here?)
+ // OH MY GOD! We didn't get any BusData. Default to 0.
+ //
+
+ BusNumber = 0;
+
+ }
+
+ //
+ // Determine the address based on whether the bus address is in I/O space
+ // or bus memory space.
+ //
+
+ switch ( (ADDRESS_SPACE_TYPE)(*AddressSpace) ) {
+
+ case BusMemory: {
+
+ //
+ // The address is in PCI memory space, kernel mode.
+ //
+
+ switch( InterfaceType ) {
+
+ case Internal:
+
+ //
+ // SMDFIX: Make Internal bus constraints the same as Isa.
+ //
+
+ case Isa: {
+
+ //
+ // Can't go above 16MB (24 Bits) for Isa Buses
+ //
+
+ if( BusAddress.LowPart >= __16MB ) {
+
+#if HALDBG
+ DbgPrint ("Unsupported ISA address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif // HALDBG
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+
+ //
+ // else fall through.
+ //
+
+ } // case Isa
+
+ case Eisa:
+
+ //
+ // Eisa is the same as PCI, with respect to kernel mode
+ // sparse and dense space memory support, i.e., its a full
+ // 32 bit space, supports dense memory access.
+ //
+
+ case PCIBus: {
+
+ if( BusNumber == 0 ) {
+
+ //
+ // PCI 0 Bus support.
+ // PCI0_MAX_SPARSE_MEMORY_ADDRESS= 128MB-1
+ // PCI0_MIN_DENSE_MEMORY_ADDRESS = 128MB
+ // PCI0_MAX_DENSE_MEMORY_ADDRESS = 1GB-1
+ //
+
+ if ( BusAddress.LowPart > PCI0_MAX_DENSE_MEMORY_ADDRESS ) {
+
+ //
+ // Unsupported dense PCI bus address.
+ //
+
+#if HALDBG
+ DbgPrint ("Unsupported PCI 0 address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif // HALDBG
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+ else
+ if( BusAddress.LowPart >= PCI0_MIN_DENSE_MEMORY_ADDRESS &&
+ BusAddress.LowPart <= PCI0_MAX_DENSE_MEMORY_ADDRESS ) {
+
+ //
+ // Bus Address is in dense PCI memory space
+ //
+
+ //
+ // Start with the base physical address and add the
+ // offset
+ //
+
+ TranslatedAddress->QuadPart =
+ SABLE_PCI0_DENSE_MEMORY_PHYSICAL;
+
+ TranslatedAddress->QuadPart +=
+ (ULONGLONG)BusAddress.LowPart;
+
+ } else {
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart =
+ SABLE_PCI0_SPARSE_MEMORY_PHYSICAL;
+ TranslatedAddress->QuadPart +=
+ ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ }
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will
+ // implicitly set AddressSpace to a 1. The caller then
+ // will not call MmMapIoSpace and will use the address
+ // we return as a VA.
+ //
+
+ TranslatedAddress->LowPart =
+ (ULONG) HalCreateQva( *TranslatedAddress, va);
+
+ //
+ // clear high longword for QVA
+ //
+
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // dont let the user call MmMapIoSpace
+ //
+
+ *AddressSpace = 1;
+
+ return(TRUE);
+
+ } else { // if BusNumber == 0
+
+ //
+ // PCI 1 Bus support (64Bit Pci Bus).
+ // PCI1_MAX_SPARSE_MEMORY_ADDRESS = 64MB-1
+ // PCI1_MIN_DENSE_MEMORY_ADDRESS = 64MB
+ // PCI1_MAX_DENSE_MEMORY_ADDRESS = 1GB-1
+ //
+
+ if ( BusAddress.LowPart > PCI1_MAX_DENSE_MEMORY_ADDRESS ) {
+
+ //
+ // Unsupported dense PCI bus address.
+ //
+
+#if HALDBG
+ DbgPrint ("Unsupported PCI 1 address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif // HALDBG
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+ else
+ if( BusAddress.LowPart >= PCI1_MIN_DENSE_MEMORY_ADDRESS &&
+ BusAddress.LowPart <= PCI1_MAX_DENSE_MEMORY_ADDRESS ) {
+
+ //
+ // Bus Address is in dense PCI memory space
+ //
+
+ //
+ // Start with the base physical address and add the
+ // offset
+ //
+
+ TranslatedAddress->QuadPart =
+ SABLE_PCI1_DENSE_MEMORY_PHYSICAL;
+
+ TranslatedAddress->QuadPart +=
+ (ULONGLONG)BusAddress.LowPart;
+
+ } else {
+
+ //
+ // Start with the base physical address and add the bus
+ // address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart =
+ SABLE_PCI1_SPARSE_MEMORY_PHYSICAL;
+
+ TranslatedAddress->QuadPart +=
+ ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+
+ }
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will implicitly
+ // set AddressSpace to a 1. The caller then will not call
+ // MmMapIoSpace and will use the address we return as a VA.
+ //
+
+ TranslatedAddress->LowPart =
+ (ULONG) HalCreateQva( *TranslatedAddress, va);
+
+ //
+ // clear high longword for QVA
+ //
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // don't let the user call MmMapIoSpace
+ //
+
+ *AddressSpace = 1;
+
+ return(TRUE);
+
+ } // if (BusNumber == 0)
+
+ } // case PCIBus
+
+ } // switch( InterfaceType )
+
+ } // case BusMemory
+
+ case BusIo: {
+
+ //
+ // The address is in PCI I/O space, kernel mode.
+ //
+ switch( InterfaceType ) {
+
+ case Eisa:
+
+ //
+ // Eisa is the same as ISA, with respect to kernel mode
+ // sparse I/O space support, i.e., it is a 16 bit sparse
+ // space.
+ //
+
+ case Internal:
+
+ //
+ // SMDFIX: Make Internal bus constraints the same as Isa.
+ //
+
+ case Isa: {
+
+ //
+ // Can't go above 64KB (16 Bits) for Isa Buses
+ //
+
+ if( BusAddress.LowPart >= __64K ){
+
+#if HALDBG
+ DbgPrint ("Unsupported ISA IO address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif // HALDBG
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+
+ //
+ // Fall through
+ //
+
+ } // case Isa
+
+ case PCIBus: {
+
+ if( BusNumber == 0 ) {
+
+ //
+ // PCI 0 Bus Support.
+ // PCI0_MAX_IO_ADDRESS = 16MB-1
+ //
+
+ if( BusAddress.LowPart >= PCI0_MAX_IO_ADDRESS ){
+
+#if HALDBG
+ DbgPrint ("Unsupported PCI 0 IO address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif // HALDBG
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ } else {
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart =
+ SABLE_PCI0_SPARSE_IO_PHYSICAL;
+ TranslatedAddress->QuadPart +=
+ ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will
+ // implicitly set AddressSpace to a 1. The caller then
+ // will not call MmMapIoSpace and will use the address
+ // we return as a VA.
+ //
+
+ TranslatedAddress->LowPart =
+ (ULONG) HalCreateQva( *TranslatedAddress, va);
+
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // Make sure user doesn't call MmMapIoSpace.
+ //
+
+ *AddressSpace = 1;
+
+ return(TRUE);
+ }
+
+
+ } else { // if (BusNumber == 0)
+
+ //
+ // PCI 1 Bus Support.
+ // PCI1_MAX_SPARSE_IO_ADDRESS = 16MB-1
+ //
+
+ if( BusAddress.LowPart >= PCI1_MAX_SPARSE_IO_ADDRESS ){
+
+#if HALDBG
+ DbgPrint ("Unsupported PCI 1 IO address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif // HALDBG
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ } else {
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart =
+ SABLE_PCI1_SPARSE_IO_PHYSICAL;
+//
+// smdfix:
+//
+// The above should actually check if this hal is running on a Lynx machine
+// since the location of PCI1_SPARSE_IO is different. For now we support
+// SABLE only.
+//
+// (LynxMachine)? LYNX_PCI1_SPARSE_IO_PHYSICAL: SABLE_PCI1_SPARSE_IO_PHYSICAL;
+//
+
+ TranslatedAddress->QuadPart +=
+ ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA that
+ // we'll return to the caller. Then we will implicitly
+ // set AddressSpace to a 1. The caller then will not
+ // call MmMapIoSpace and will use the address we return
+ // as a VA.
+ //
+
+ TranslatedAddress->LowPart =
+ (ULONG) HalCreateQva( *TranslatedAddress, va);
+
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // Make sure user doesn't call MmMapIoSpace.
+ //
+
+ *AddressSpace = 1;
+
+ return(TRUE);
+ }
+
+ } // if (BusNumber == 0)
+
+ } // case PCIBus
+
+ } // switch( InterfaceType )
+
+ } // case BusIo
+
+ case UserBusMemory: {
+
+ //
+ // The address is in PCI memory space, user mode.
+ //
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ if( BusNumber == 0 ) {
+ TranslatedAddress->QuadPart = SABLE_USER_PCI0_SPARSE_MEMORY_PHYSICAL;
+ } else {
+ TranslatedAddress->QuadPart = SABLE_USER_PCI1_SPARSE_MEMORY_PHYSICAL;
+ }
+
+ TranslatedAddress->QuadPart += ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ *AddressSpace = 0; // Let the user call MmMapIoSpace
+
+ return(TRUE);
+
+ }
+
+ case UserBusIo: {
+
+ //
+ // The address is in PCI I/O space, user mode.
+ //
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ if( BusNumber == 0 ) {
+ TranslatedAddress->QuadPart = SABLE_USER_PCI0_SPARSE_IO_PHYSICAL;
+ } else {
+ TranslatedAddress->QuadPart = SABLE_USER_PCI1_SPARSE_IO_PHYSICAL;
+ }
+
+ TranslatedAddress->QuadPart += ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ //
+ // Make sure user can call MmMapIoSpace.
+ //
+
+ *AddressSpace = 0;
+
+ return(TRUE);
+
+ }
+
+ case KernelPciDenseMemory:
+ case UserPciDenseMemory:
+ {
+
+ //
+ // The address is in PCI memory space, user mode.
+ //
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ if( BusNumber == 0 ) {
+ TranslatedAddress->QuadPart = SABLE_USER_PCI0_DENSE_MEMORY_PHYSICAL;
+ } else {
+ TranslatedAddress->QuadPart = SABLE_USER_PCI1_DENSE_MEMORY_PHYSICAL;
+ }
+
+ TranslatedAddress->QuadPart += ((ULONGLONG)BusAddress.LowPart);
+
+ //
+ // Let the user call MmMapIoSpace
+ //
+
+ *AddressSpace = 0;
+
+ return(TRUE);
+
+ }
+ } // switch (*AddressSpace)
+}
+
+PVOID
+HalCreateQva(
+ IN PHYSICAL_ADDRESS PA,
+ IN PVOID VA
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called two ways. First, from HalTranslateBusAddress,
+ if the caller is going to run in kernel mode and use superpages.
+ The second way is if the user is going to access in user mode.
+ MmMapIoSpace or ZwViewMapOfSection will call this.
+
+ If the input parameter VA is zero, then we assume super page and build
+ a QUASI virtual address that is only usable by calling the hal I/O
+ access routines.
+
+ if the input parameter VA is non-zero, we assume the user has either
+ called MmMapIoSpace or ZwMapViewOfSection and will use the user mode
+ access macros.
+
+ If the PA is not an I/O space address (PCI I/O, PCI Memory),
+ then return the VA as the QVA.
+
+Arguments:
+
+ PA - the physical address generated by HalTranslateBusAddress
+
+ VA - the virtual address returned by MmMapIoSpace
+
+Return Value:
+
+ The returned value is a quasi virtual address in that it can be
+ added to and subtracted from, but it cannot be used to access the
+ bus directly. The top bits are set so that we can trap invalid
+ accesses in the memory management subsystem. All access should be
+ done through the Hal Access Routines in *ioacc.s if it was a superpage
+ kernel mode access. If it is usermode, then the user mode access
+ macros must be used.
+
+--*/
+{
+ PVOID qva;
+
+ //
+ // Clear bit 35 (if present) for user mode address spaces.
+ //
+
+ if( VA != NULL ){
+ PA.QuadPart &= 0x83FFFFFFFF;
+ }
+
+ if( (PA.QuadPart >= SABLE_PCI0_SPARSE_MEMORY_PHYSICAL) &&
+ (PA.QuadPart < SABLE_PCI1_SPARSE_MEMORY_PHYSICAL) ||
+
+ (PA.QuadPart >= SABLE_PCI1_SPARSE_MEMORY_PHYSICAL) &&
+ (PA.QuadPart < SABLE_CBUS_CSRS_PHYSICAL) ||
+
+ (PA.QuadPart >= SABLE_PCI0_SPARSE_IO_PHYSICAL) &&
+ (PA.QuadPart < SABLE_PCI0_DENSE_MEMORY_PHYSICAL) ||
+
+ (PA.QuadPart >= SABLE_PCI1_SPARSE_IO_PHYSICAL) &&
+ (PA.QuadPart <=
+ SABLE_PCI1_SPARSE_IO_PHYSICAL + PCI1_MAX_SPARSE_IO_ADDRESS) ){
+
+ //
+ // The physical address is within one of the sparse I/O spaces.
+ //
+
+ if (VA == 0) {
+
+ qva = (PVOID)(PA.QuadPart >> IO_BIT_SHIFT);
+
+ } else {
+
+ qva = (PVOID)((ULONG)VA >> IO_BIT_SHIFT);
+ }
+
+ qva = (PVOID)((ULONG)qva | QVA_ENABLE);
+
+ return(qva);
+ }
+ else if( PA.QuadPart >= SABLE_PCI0_DENSE_MEMORY_PHYSICAL &&
+ PA.QuadPart <= SABLE_PCI0_DENSE_MEMORY_PHYSICAL +
+ PCI0_MAX_DENSE_MEMORY_ADDRESS ) {
+
+ //
+ // The physical address is within the 1 GB dense space of PCI bus 0.
+ //
+
+ if (VA == 0) {
+
+ //
+ // Kernel mode: create a QVA
+ //
+ // Subtract out physical address base.
+ // Now we just have the PCI 0 bus address.
+
+ PA.QuadPart -= SABLE_PCI0_DENSE_MEMORY_PHYSICAL;
+
+ // Add in the QVA base for PCI Bus 0
+
+ PA.QuadPart += SABLE_PCI0_DENSE_MEMORY_QVA;
+
+ qva = (PVOID) PA.LowPart;
+
+ return(qva);
+
+ } else {
+
+ //
+ // Use mode, return the VA as the QVA
+ //
+
+ return(VA);
+ }
+ }
+ else if( PA.QuadPart >= SABLE_PCI1_DENSE_MEMORY_PHYSICAL &&
+ PA.QuadPart <= SABLE_PCI1_DENSE_MEMORY_PHYSICAL +
+ PCI1_MAX_DENSE_MEMORY_ADDRESS) {
+
+ //
+ // The physical address is within the 2 GB dense space of PCI bus 1.
+ //
+
+ if (VA == 0) {
+
+ // Subtract out physical address base.
+ // Now we just have the PCI 1 bus address.
+
+ PA.QuadPart -= SABLE_PCI1_DENSE_MEMORY_PHYSICAL;
+
+ // Add in the QVA base for PCI Bus 1
+
+ PA.QuadPart += SABLE_PCI1_DENSE_MEMORY_QVA;
+
+ qva = (PVOID) PA.LowPart;
+
+ return(qva);
+
+ } else {
+
+ //
+ // Use mode, return the VA as the QVA
+ //
+
+ return(VA);
+ }
+ }
+
+ //
+ // It is not an I/O space address, return the VA as the QVA
+ //
+
+ return(VA);
+
+}
+
+PVOID
+HalDereferenceQva(
+ PVOID Qva,
+ INTERFACE_TYPE InterfaceType,
+ ULONG BusNumber
+ )
+/*++
+
+Routine Description:
+
+ This function performs the inverse of the HalCreateQva for I/O addresses
+ that are memory-mapped (i.e. the quasi-virtual address was created from
+ a virtual address rather than a physical address).
+
+Arguments:
+
+ Qva - Supplies the quasi-virtual address to be converted back to a
+ virtual address.
+
+ InterfaceType - Supplies the interface type of the bus to which the
+ Qva pertains.
+
+ BusNumber - Supplies the bus number of the bus to which the Qva pertains.
+
+Return Value:
+
+ The Virtual Address from which the quasi-address was originally created
+ is returned.
+
+--*/
+{
+
+
+ //
+ // For Sable we have three supported bus types:
+ //
+ // Isa
+ // Eisa
+ // PCIBus
+ //
+
+ switch (InterfaceType ){
+
+ case Isa:
+ case Eisa:
+ case PCIBus:
+
+ //
+ // Support dense space: check to see if it's really
+ // a sparse space QVA.
+ //
+
+ if ( ((ULONG) Qva & QVA_SELECTORS) == QVA_ENABLE ) {
+ return( (PVOID)( (ULONG)Qva << IO_BIT_SHIFT ) );
+ } else {
+ return (Qva);
+ }
+ break;
+
+ default:
+
+ return NULL;
+
+ }
+
+
+}