summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halraw/alpha/iodio.s
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halraw/alpha/iodio.s')
-rw-r--r--private/ntos/nthals/halraw/alpha/iodio.s2997
1 files changed, 2997 insertions, 0 deletions
diff --git a/private/ntos/nthals/halraw/alpha/iodio.s b/private/ntos/nthals/halraw/alpha/iodio.s
new file mode 100644
index 000000000..6edc5f9d0
--- /dev/null
+++ b/private/ntos/nthals/halraw/alpha/iodio.s
@@ -0,0 +1,2997 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ iodio.s
+
+Abstract:
+
+ This module implements the I/O access routines for the IOD
+ (CAP/MDP) ASICs.
+
+ The module contains the functions to turn quasi virtual
+ addresses into an Alpha superpage virtual address
+ and then read or write based on the request.
+
+Author:
+
+ Eric Rehm 10-Apr-1995
+
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+
+--*/
+
+#include "halalpha.h"
+#include "iod.h"
+
+
+//
+// Superpage VAs
+//
+// The following constants are used to construct the physical addresses
+// used to access i/o space.
+//
+// assembler BUGBUG:
+//
+// The following values are hacks to get around the intelligent
+// Alpha assemblers. Instead of sign extending 16 bit quantities greater
+// than 32K-1, the assembler generates a ldah/lda pair to load exactly
+// the sixteen bit quantity specified, without sign extending.
+//
+// By specifying the quantity as a negative number, the assembler allows
+// a single lda instruction, with sign extension.
+//
+
+
+//
+// ecrfix - these definitions are good for PCI 0 (GID = 7, MID = 4) ONLY!!!
+//
+
+
+#define IOD_SPARSE_MEM_SVA -0x3080 // negative of 0xcf80
+#define IOD_DENSE_MEM_SVA -0x3070 // negative of 0xcf90
+#define IOD_SPARSE_IO_SVA -0x3068 // negative of 0xcf98
+#define IOD_REGISTER_SVA -0x3062 // negative of 0xcf9E
+
+//
+// These definitions are based on GID=0, MID=0 and can be used
+// to construct an superpage address for any (GID, MID).
+//
+
+#define IOD_PCI0_REGISTER_SVA -0x3062 // negative of 0xcf9E
+#define IOD_REGISTER_NEW_SVA -0x3800 // negative of 0xc800
+#define IOD_IP_INTR_SVA -0x37ff // negative of 0xc801 (to CUD only)
+#define IOD_INTTIM_SVA -0x37f0 // negative of 0xc810 (to CUD only)
+#define IOD_IP_ACK_SVA -0x37ef // negative of 0xc811 (to CUD only)
+#define IOD_MCHK_ACK_SVA -0x37ee // negative of 0xc812 (to CUD only)
+#define IOD_HALT_ACK_SVA -0x37e9 // negative of 0xc817 (to CUD only)
+#define IOD_PCI_CONFIG_SVA -0x37e4 // negative of 0xc81C
+#define IOD_INT_ACK_SVA -0x37e1 // negative of 0xc81F
+
+#define IOD_TARGET0_OFFSET 0x3f00
+#define IOD_TARGET1_OFFSET 0x3f40
+
+#define MabNumber 0 // offset of HalpMasterAbortExpected.Number
+#define MabAddr 8 // offset of HalpMasterAbortExpected.Addr
+#define MASTER_ABORT_NOT_EXPECTED 0xffffffff
+
+#define GET_PROCESSOR_CONTROL_BLOCK_BASE \
+ call_pal rdpcr; \
+ ldl v0, PcPrcb(v0)
+
+
+ SBTTL( "Return PCR address for current processor" )
+//++
+//
+// PVOID
+// HalpRdPcr(
+// )
+//
+// Routine Description:
+//
+// Calls PAL to obtain PCR for current processor
+//
+// Arguments:
+//
+// None
+//
+// Return Value:
+//
+// v0 - Address of PCR
+//
+//--
+
+ LEAF_ENTRY(HalpRdPcr)
+
+
+ call_pal rdpcr; // CallPal to read PCR
+ ret zero, (ra) // return
+
+ .end HalpRdPcr
+
+
+
+ SBTTL( "Read byte from PCI memory" )
+//++
+//
+// UCHAR
+// READ_REGISTER_UCHAR(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a byte location in PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O byte to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+ bis zero, 0xffffffff,v0 // ecrfix
+
+ ldl v0, (t0) // get the longword
+ extbl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, 3, t3 // capture byte offset
+ bic a0, 3, a0 // clear byte offset
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, a0, t0 // 0xffff fcf9 xxxx xxxx
+ bis zero, 0xffffffff,v0 // ecrfix
+ mb // ensure all writes are visible
+ ldl v0, 0(t0) // read from dense space
+ extbl v0, t3, v0 // extract appropriate byte
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_UCHAR
+
+
+
+ SBTTL( "Read byte from PCI sparse i/o" )
+//++
+//
+// UCHAR
+// READ_PORT_UCHAR(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a byte location in PCI bus sparse i/o space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O byte to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff cf98 0000
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+ bis zero, 0xffffffff,v0 // ecrfix
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+ extbl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_UCHAR
+
+
+ SBTTL( "Read short from PCI memory" )
+//++
+//
+// UCHAR
+// READ_REGISTER_USHORT(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a short location in PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory short to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI memory.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_WORD_LEN, t0 // set size to short
+ bis zero, 0xffffffff,v0 // ecrfix
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+ extwl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, 3, t3 // capture byte offset
+ bic a0, 3, a0 // clear byte offset
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, a0, t0 // 0xffff fcf9 xxxx xxxx
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // read from dense space
+ extwl v0, t3, v0 // extract appropriate word
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_USHORT
+
+
+ SBTTL( "Read short from PCI sparse I/O" )
+//++
+//
+// UCHAR
+// READ_PORT_USHORT(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a short location in PCI bus sparse i/o space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the i/o short to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI I/O.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_WORD_LEN, t0 // set size to short
+ bis zero, 0xffffffff,v0 // ecrfix
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+ extwl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_USHORT
+
+
+ SBTTL( "Read long from PCI memory" )
+//++
+//
+// UCHAR
+// READ_REGISTER_ULONG(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a long location in PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory long to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI memory.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // set size to long
+
+ mb // ensure all writes are visible
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, (t0) // get the longword
+#if 0 //mdbfix support Canonical ULONG form
+ extll v0, 0, v0 // if NXM, make exception more precise
+#endif
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, a0, t0 // 0xffff fcf9 xxxx xxxx
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // read from dense space
+#if 0 //mdbfix support Canonical ULONG form
+ extll v0, 0, v0 // if NXM, make exception more precise
+#endif
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_ULONG
+
+
+ SBTTL( "Read long from PCI sparse I/O" )
+//++
+//
+// UCHAR
+// READ_PORT_ULONG(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a long location in PCI bus sparse i/o space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the i/o long to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI I/O.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // set size to short
+
+ bis zero, 0xffffffff,v0 // ecrfix
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_ULONG
+
+
+ SBTTL( "Write byte to PCI memory" )
+//++
+//
+// VOID
+// WRITE_REGISTER_UCHAR(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a byte location to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ insbl a1, t3, v0 // insert to proper byte lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear byte offset
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, a0, t0 // 0xffff fcf9 xxxx xxxx
+
+ ldl t1, (t0) // get the long
+ mskbl t1, t3, t1 // mask the proper byte
+
+
+ insbl a1, t3, a1 // insert to appropriate byte lane
+ bis a1, t1, a1 // merge byte in result
+ stl a1, (t0) // write to dense space
+ mb // order subsequent reads/writes
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_UCHAR
+
+
+ SBTTL( "Write byte to PCI sparse i/o" )
+//++
+//
+// VOID
+// WRITE_PORT_UCHAR(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a byte location to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ insbl a1, t3, v0 // insert to proper byte lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_UCHAR
+
+
+ SBTTL( "Write short to PCI memory" )
+//++
+//
+// VOID
+// WRITE_REGISTER_USHORT(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a short to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory short to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_WORD_LEN, t0 // set size to short
+
+ inswl a1, t3, v0 // insert to proper short lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear byte offset
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ bis t0, a0, t0 // 0xffff fcf9 xxxx xxxx
+ ldl t1, (t0) // get the long
+ mskwl t1, t3, t1 // mask the proper word
+ inswl a1, t3, a1 // insert to appropriate short lane
+ bis a1, t1, a1 // merge in result
+ stl a1, (t0) // write to dense space
+ mb // order subsequent reads/writes
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_USHORT
+
+
+ SBTTL( "Write short to PCI sparse i/o" )
+//++
+//
+// VOID
+// WRITE_PORT_USHORT(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a byte location to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_WORD_LEN, t0 // set size to short
+
+ inswl a1, t3, v0 // insert to proper short lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_USHORT
+
+
+
+ SBTTL( "Write long to PCI memory" )
+//++
+//
+// VOID
+// WRITE_REGISTER_ULONG(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a long to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory long to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // set size to long
+
+ stl a1, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, a0, t0 // 0xffff fcf9 xxxx xxxx
+ stl a1, 0(t0) // write to dense space
+ mb // order subsequent reads/writes
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_ULONG
+
+
+ SBTTL( "Write long to PCI sparse i/o" )
+//++
+//
+// VOID
+// WRITE_PORT_ULONG(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a long to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O long to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // set size to long
+
+ stl a1, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_ULONG
+
+
+ SBTTL( "Write IOD Register" )
+//++
+//
+// VOID
+// WRITE_IOD_REGISTER(
+// IN PVOID RegisterQva,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// Write an IOD control register.
+//
+// Arguments:
+//
+// RegisterQva(a0) - QVA of control register to be written.
+//
+// Value(a1) - Longword value to be written to the control register.
+//
+// Return Value:
+//
+// None.
+//
+// N.B. Since the physical address of the IOD CSRS exceed the 34 bit
+// capacity of the QVAs, the QVA values of the IOD CSRS specify
+// the offset of the QVAs from the IOD CSR base address (89.e000.0000)
+//--
+
+ LEAF_ENTRY(WRITE_IOD_REGISTER)
+
+ ALTERNATE_ENTRY(WRITE_GRU_REGISTER)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, IOD_REGISTER_SVA(zero) // 0xffff ffff ffff cf9e
+ sll t4, 28, t4 // 0xffff fcf9 e000 0000
+ or t0, t4, t0 // superpage mode
+ stl a1, (t0) // write the longword
+ mb // order the write
+ ret zero, (ra) // return
+
+10:
+ BREAK_DEBUG_STOP // take a breakpoint
+ ret zero, (ra) // return
+
+ .end WRITE_IOD_REGISTER
+
+
+ SBTTL( "Read IOD Register" )
+//++
+//
+// ULONG
+// READ_IOD_REGISTER(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Read an IOD Control register
+//
+// Arguments:
+//
+// RegisterQva(a0) - QVA of control register to be written.
+//
+// Return Value:
+//
+// v0 - Return the value read from the control register.
+//
+//--
+
+ LEAF_ENTRY(READ_IOD_REGISTER)
+
+//
+// Generate the superpage address of the requested IOD register.
+//
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 20f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, IOD_REGISTER_SVA(zero) // 0xffff ffff ffff cf9e
+ sll t4, 28, t4 // 0xffff fcf9 e000 0000
+ or t0, t4, t0 // superpage mode
+
+//
+// Perform the read of the requested IOD register and return.
+//
+
+ ldl v0, (t0) // read the register
+
+ ret zero, (ra) // return
+
+//
+// The requested IOD register address is bogus. Stop in the debugger so
+// we can find the culprit.
+//
+
+20: // flag bad QVAs
+ BREAK_DEBUG_STOP // take a breakpoint
+
+ ret zero, (ra) // return
+
+ .end READ_IOD_REGISTER
+
+
+ SBTTL( "Write IOD Register_New" )
+//++
+//
+// VOID
+// WRITE_IOD_REGISTER_NEW(
+// IN ULONG McDevid
+// IN PVOID RegisterQva,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// Write a IOD control register.
+//
+// Arguments:
+//
+// McDevid(a0) - MC Bus Device ID of this IOD
+//
+// RegisterQva(a1) - Qva of control register to be written.
+// N.B. RegisterQva *does not* specifiy which IOD to write to.
+// That's why we pass in McDevid
+//
+// Value(a2) - Longword value to be written to the control register.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_IOD_REGISTER_NEW)
+
+//
+// Generate the superpage address of the requested IOD register.
+//
+
+ // Args are actually byte values:
+ and a1, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a1, 0xf0, a1 // clear <63:32>
+ bic a1, QVA_ENABLE, a1 // clear QVA fields so shift is correct
+ sll a1, IO_BIT_SHIFT, t4 // shift RegisterOffset into position
+
+ extbl a0, zero, a0 // McDevId
+
+ lda t0, IOD_REGISTER_NEW_SVA(zero) // 0xffff ffff ffff c800
+ sll a0, 5, t1 // shift McDevId into position
+ bis t0, t1, t0 // create SVA for this IOD
+ sll t0, 28, t0 // 0xffff fcXX 0000 0000
+
+ or t0, t4, t0 // superpage mode
+ stl a2, (t0) // write the longword
+ mb // order the write
+ ret zero, (ra) // return
+
+//
+// The requested IOD register address is bogus. Stop in the debugger so
+// we can find the culprit.
+//
+
+10:
+ BREAK_DEBUG_STOP // take a breakpoint
+ ret zero, (ra) // return
+
+ .end WRITE_IOD_REGISTER_NEW
+
+
+ SBTTL( "Read IOD Register_NEW" )
+//++
+//
+// ULONG
+// READ_IOD_REGISTER_NEW(
+// IN ULONG McDevid
+// IN ULONG RegisterOffset
+// )
+//
+// Routine Description:
+//
+// Read an IOD Control register
+//
+// Arguments:
+//
+// McDevid(a0) - MC Bus Device ID of this IOD.
+//
+// RegisterQva(a1) - QVA of control register to be read.
+//
+// Return Value:
+//
+// v0 - Return the value read from the control register.
+//
+//--
+
+ LEAF_ENTRY(READ_IOD_REGISTER_NEW)
+
+//
+// Generate the superpage address of the requested IOD register.
+//
+
+ and a1, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a1, 0xf0, a1 // clear <63:32>
+ bic a1, QVA_ENABLE, a1 // clear QVA fields so shift is correct
+ sll a1, IO_BIT_SHIFT, t4 // shift RegisterQva into position
+
+ extbl a0, zero, a0 // McDevId
+
+ lda t0, IOD_REGISTER_NEW_SVA(zero) // 0xffff ffff ffff c800
+ sll a0, 5, t1 // shift McDevId into position
+ bis t0, t1, t0 // create SVA for this IOD
+ sll t0, 28, t0 // 0xffff fcXX 0000 0000
+
+ or t0, t4, t0 // superpage mode
+
+//
+// Perform the read of the requested IOD register and return.
+//
+
+ ldl v0, (t0) // read the register
+
+ ret zero, (ra) // return
+
+//
+// The requested IOD register address is bogus. Stop in the debugger so
+// we can find the culprit.
+//
+
+10:
+ BREAK_DEBUG_STOP // take a breakpoint
+ ret zero, (ra) // return
+
+ .end READ_IOD_REGISTER_NEW
+
+
+ SBTTL( "Read Buffer from Port Space in Uchars")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_UCHAR(
+// IN PVOID PortQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple bytes from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of bytes to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+10: beq a2, 20f // while count > 0
+
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0,t3,v0 // get the correct byte
+ stb v0,(a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ br zero, 10b // end while
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_BUFFER_UCHAR
+
+
+ SBTTL( "Read Buffer from Port Space in Ushorts")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_USHORT(
+// IN PVOID PortQva,
+// IN PUSHORT Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple words from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of words to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // while count > 0
+
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extwl v0,t3,v0 // get the correct word
+ stw v0,(a1) // cheat and let the assembler do it
+ addl a1, 2, a1 // next word in buffer
+ br zero, 10b // end while
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_BUFFER_USHORT
+
+ SBTTL( "Read Buffer from Port Space in Ulongs")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_ULONG(
+// IN PVOID PortQva,
+// IN PULONG Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple longwords from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of longwords to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // while count > 0
+
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ stl v0,(a1) // cheat and let the assembler do it
+ addl a1, 4, a1 // next word in buffer
+ br zero, 10b // end while
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_BUFFER_ULONG
+
+
+ SBTTL( "Write Buffer to Port Space in Uchars")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_UCHAR(
+// IN PVOID PortQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple bytes from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of bytes to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+10: beq a2, 20f // copy while a2 > 0
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // put byte to appropriate lane
+ stl t1, 0(t0) // store to port
+ mb // push writes off chip
+ br zero, 10b // end while
+
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+
+ .end WRITE_PORT_BUFFER_UCHAR
+
+ SBTTL( "Write Buffer to Port Space in Ushorts")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_USHORT(
+// IN PVOID PortQva,
+// IN PSHORT Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple words from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of words to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // copy while a2 > 0
+
+ ldq_u t1, 0(a1) // get quad surrounding word
+ subl a2, 1, a2 // decrement count
+ extwl t1, a1, t1 // extract appropriate word
+ addl a1, 2, a1 // increment buffer pointer
+ inswl t1, t3, t1 // put word in appropriate lane
+ stl t1, 0(t0) // store to port
+ mb // push the write off the chip
+ br zero, 10b // end while
+
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_BUFFER_USHORT
+
+
+ SBTTL( "Write Buffer to Port Space in Ulongs")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_ULONG(
+// IN PVOID PortQva,
+// IN PULONG Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple longwords from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_IO_SVA(zero) // 0xffff ffff ffff cf98
+ sll t4, 28, t4 // 0xffff fcf9 8000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // copy while a2 > 0
+
+ ldl t1, 0(a1) // a1 must be longword aligned
+ subl a2, 1, a2 // decrement count
+ stl t1, 0(t0) // store to port
+ mb // push write off the chip
+ addl a1, 4, a1 // increment buffer
+ br zero, 10b // end while
+
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_BUFFER_ULONG
+
+
+ SBTTL( "Read Buffer from PCI Memory Space in Uchars")
+//++
+//
+// VOID
+// READ_REGISTER_BUFFER_UXXXXX(
+// IN PVOID RegisterQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Copies a buffer from PCI Memory Space to an in-memory buffer.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer.
+//
+// Buffer(a1) - Supplies a pointer to the in-memory buffer to receive
+// the copied data.
+//
+// Count(a2) - Supplies the number of bytes, words or longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG)
+
+ sll a2, 1, a2 // convert number of longs to words
+
+ ALTERNATE_ENTRY(READ_REGISTER_BUFFER_USHORT)
+
+
+ sll a2, 1, a2 // convert number of words to chars
+
+ ALTERNATE_ENTRY(READ_REGISTER_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ beq t1, 1f // if (eq) go do sparse space
+
+//
+// Dense space access: QVA is an offset into dense space
+// Set IO address in t0
+//
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or a0, t0, t0 // superpage mode: add offset to base
+
+ ldil a3, 1 // Offset to next byte
+ ldil a4, 4 // Offset to next long
+ ldil a5, 0 // LONG LEN ENABLE
+
+ br zero 2f // go do the actual transfer
+
+//
+// Sparse memory
+// Set IO address in t0
+//
+
+1:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ ldil a3, IO_BYTE_OFFSET // Offset to next byte
+ ldil a4, IO_LONG_OFFSET // Offset to next long
+ ldil a5, IO_LONG_LEN // LONG LEN ENABLE
+
+//
+// Do the ACTUAL TRANSFER
+// a2 = count in characters
+//
+
+2:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+//
+// Check alignment of src and destn
+//
+
+ and a0, 3, t3 // source alignment = t3
+ and a1, 3, t2 // destination alignment = t2
+ xor t2, t3, t4 // t4 = t2 xor t3
+ bne t4, 70f // if (t4!=0) do unaligned copy
+ // else do byte copies till alignment
+
+ beq t3, 20f // if t3==0 go do long word copies
+ // else do byte copies till alignment
+
+//
+// Src and Destn are not longword aligned but have same alignment
+// (sympathetically aligned) copy till alignment
+//
+
+10:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addq t0, a3, t0 // next I/O address
+ addl a1, 1, a1 // next byte in buffer
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne t3, 10b // while unaligned
+
+//
+// Src and Destn have same alignment and are longword aligned
+//
+
+20:
+ srl a2, 2, t3 // t3= #longwords to move
+ beq t3, 40f // if #longwords == 0 goto 40f
+ or t0, a5, t0 // We will now do LONG READS
+
+30:
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // get the longword
+ subl t3, 1, t3 // decrement long word count
+ stl v0, (a1) // store the longword at destn
+ addq t0, a4, t0 // next I/O address
+ addl a1, 4, a1 // next longword in buffer
+ bne t3, 30b // while #longwords > 0
+
+//
+// Do byte copies of remaining data uncopied
+//
+ bic t0, a5, t0 // We will now do BYTE READS
+40:
+ and a2, 3, a2 // remaining Bytes to copy
+ beq a2, 60f // if count == 0 goto 60f
+
+50:
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne a2, 50b // while count > 0
+
+60:
+ ret zero, (ra) // return
+
+
+//
+// source IO alignment != destination memory alignment
+// move enough bytes to longword align the IO source
+// then move 32bit (longwords) storing unaligned into memory
+// then move residual bytes
+//
+// Align src IO addresses; unaligned destn memory
+//
+
+70:
+ beq t3, 90f // branch if source is long aligned
+//
+// Move bytes until IO src is at a longword boundary or bytes exhausted
+//
+
+80:
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne t3, 80b // while unaligned
+
+//
+// aligned IO source, unaligned memory destination
+//
+
+90:
+ srl a2, 3, t3 // quadwords to move
+ beq t3, 110f // if no quads finish with bytes copies
+
+ or t0, a5, t0 // We will now do LONG READS
+
+100:
+ //
+ // Decoding for Comment:
+ // S= sign, X= overwritten byte, V= Valid byte,assume destn align a1= 2
+ //
+ bis zero, 0xffffffff,t1 // ecrfix
+ ldl t1, 0(t0) // load LW 0 from IO src SSSS 4321
+ ldq_u t4, 0(a1) // load destn merge XXVV VVVV
+ ldq_u t5, 7(a1) // load destn next merge VVXX XXXX
+ subl t3, 1, t3 // decrement quadwords to move
+
+ addq t0, a4, t0 // add LONG OFFSET to t0
+ bis zero, 0xffffffff,t2 // ecrfix
+ ldl t2, 0(t0) // load LW 1 from IO src SSSS 8765
+
+ mskql t4, a1, t4 // mask low LW for merge 00VV VVVV
+ mskqh t5, a1, t5 // mask high LW for merge VV00 0000
+
+ zap t1, 0xf0, t1 // clear high LW for long 0 0000 4321
+ sll t2, 32, t2 // get long 1 to high longword 8765 0000
+ bis t1, t2, t1 // merge read quadword together8765 4321
+
+ addq t0, a4, t0 // increment to next long
+
+ insql t1, a1, t6 // position low QW for merge 2100 0000
+ insqh t1, a1, t7 // position high QW for merge 0087 6543
+
+ bis t4, t6, t4 // merge new data, low QW 21VV VVVV
+ bis t5, t7, t5 // merge new data, high QW VV87 6543
+
+ stq_u t5, 7(a1) // write high quadword
+ stq_u t4, 0(a1) // write low quadword
+
+ lda a1, 8(a1) // increment memory pointer
+ bne t3, 100b // while quadwords to move
+
+//
+// Do byte copies of the remaining data not yet copied
+//
+ bic t0, a5, t0 // We will now do BYTE READS
+110:
+ and a2, 7, a2 // remaining bytes to copy
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+120:
+ bis zero, 0xffffffff,v0 // ecrfix
+ ldl v0, 0(t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne a2, 120b // while count != 0
+
+130:
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
+
+
+ SBTTL( "Write Buffer to PCI Memory Space in Uchars")
+//++
+//
+// VOID
+// WRITE_REGISTER_BUFFER_UXXXXX(
+// IN PVOID RegisterQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Copies an in-memory buffer to a PCI Memory Space buffer.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer.
+//
+// Buffer(a1) - Supplies a pointer to the in-memory source buffer.
+//
+// Count(a2) - Supplies the number of bytes, words to longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG)
+
+ sll a2, 1, a2 // convert number of longs to words
+
+ ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_USHORT)
+
+ sll a2, 1, a2 // convert number of words to chars
+
+ ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ beq t1, 1f // if (eq) go do sparse space
+
+//
+// Dense space access: QVA is an offset into dense space
+// Set IO address in t0
+//
+
+ ldil t7, 1 // DENSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_DENSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_DENSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_DENSE_ENABLE, a0 // clear QVA fields <31:30>
+ lda t0, IOD_DENSE_MEM_SVA(zero) // 0xffff ffff ffff cf90
+ sll t0, 28, t0 // 0xffff fcf9 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or a0, t0, t0 // superpage mode: add offset to base
+
+ ldil a3, 1 // Offset to next byte
+ ldil a4, 4 // Offset to next long
+ ldil a5, 0 // LONG LEN ENABLE
+
+ br zero, 2f // go do the actual transfer
+
+//
+// Sparse Space
+// Set IO address in t0
+//
+
+1:
+ ldil t7, 0 // SPARSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, IOD_SPARSE_SELECTORS, t2 // get BusNum from QVA
+ sll t2, IOD_SPARSE_BUS_SHIFT, t2 // put BusNum into MID position
+
+ bic a0, IOD_SPARSE_ENABLE, a0 // clear QVA fields <32:27>
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, IOD_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff cf80
+ sll t4, 28, t4 // 0xffff fcf8 0000 0000
+ or t0, t2, t0 // add BusNum in MID field
+ or t0, t4, t0 // superpage mode
+
+ ldil a3, IO_BYTE_OFFSET // Offset to next byte
+ ldil a4, IO_LONG_OFFSET // Offset to next long
+ ldil a5, IO_LONG_LEN // LONG LEN ENABLE
+
+//
+// Do the ACTUAL TRANSFER
+// a2 = count in characters
+//
+
+2:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+//
+// Check alignment of src and destn
+//
+ and a0, 3, t3 // destn alignment = t3
+ and a1, 3, t2 // src alignment = t2
+ xor t2, t3, t4 // t4 = t2 xor t3
+ bne t4, 70f // if (t4!=0) do unaligned copy
+ // else do byte copies till alignment
+
+ beq t3, 20f // if t3==0 go do longword copies
+ // else do byte copies till alignment
+
+//
+// Src and Destn are not longword aligned but have same alignment
+// (sympathetically aligned) copy till alignment
+//
+
+10:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 11f // if not DENSE goto 11f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 12f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+11:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+12:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne t3, 10b // loop while not long aligned
+
+//
+// Src and Destn have same alignment and are longword aligned
+//
+
+20:
+ srl a2, 2, t3 // t3= #longwords to move
+ beq t3, 40f // if #longwords == 0 goto 40f
+ or t0, a5, t0 // We will now do LONG WRITE
+
+30:
+ ldl t1, 0(a1) // get the longword
+ addl a1, 4, a1 // increment buffer pointer
+ subl t3, 1, t3 // decrement #longwords by 1
+ stl t1, 0(t0) // store long to buffer
+ addq t0, a4, t0 // increment I/O buffer
+ bne t3, 30b // while #longwords > 0
+
+//
+// Do byte copies of remaining data uncopied
+//
+ bic t0, a5, t0 // Stop doing LONG WRITE
+
+40:
+ and a2, 3, a2 // remaining Bytes to copy
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+50:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 51f // if not DENSE goto 51f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 52f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+51:
+ stl t1, 0(t0) // store to buffer
+52:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne a2, 50b // while count != 0
+
+60:
+ mb // push writes off chip
+ ret zero, (ra) // return
+
+//
+// destn IO alignment != Src memory alignment
+// move enough bytes to longword align the IO destn
+// then move 32bit (longwords) reading unaligned data from memory
+// then move residual bytes
+//
+
+70:
+ beq t3, 90f // branch if destn is long aligned
+
+//
+// Move bytes until IO destn is at a longword boundary or bytes exhausted
+//
+
+80:
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ extbl t1, a1, t1 // extract appropriate byte
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 81f // if not DENSE goto 81f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 82f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+81:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+82:
+ subl a2, 1, a2 // decrement count
+ addl a1, 1, a1 // increment buffer pointer
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne t3, 80b // loop if not long aligned
+
+//
+// aligned IO destn, unaligned memory src
+//
+
+90:
+ srl a2, 3, t3 // t3 = quadwords to move
+ beq t3, 110f // if no quads finish with bytes copies
+
+ or t0, a5, t0 // We will now do LONG WRITES
+
+100:
+ ldq_u t1, 0(a1) // load low source quadword
+ ldq_u t2, 7(a1) // load high source quadword
+ extql t1, a1, t1 // extract low portion of quadword
+ extqh t2, a1, t2 // extract high portion of quadword
+ or t1, t2, t1 // merge to get the source quadword
+ stl t1, 0(t0) // store the long word (LONG ENABLED)
+
+ lda a1, 8(a1) // next source quadword
+ srl t1, 32, t1 // get high longword into position
+ subl t3, 1, t3 // decrement number of quadwords to move
+ addq t0, a4, t0 // add LONG OFFSET to t0
+ stl t1, (t0) // store the second long word
+
+ addq t0, a4, t0 // increment to next dest. long
+ bne t3, 100b // while quadwords to move
+//
+// Do byte copies of the remaining data not yet copied
+//
+ bic t0, a5, t0 // We will now do BYTE WRITES
+110:
+ and a2, 7, a2 // remaining Bytes to copy
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+120:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 121f // if not DENSE goto 122f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 122f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+121:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+122:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne a2, 120b // while count != 0
+
+130:
+ mb // push writes off chip
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
+
+
+#if 0 //ecrfix
+//
+// Values and structures used to access configuration space.
+//
+
+//
+// Define the configuration routines stack frame.
+//
+
+ .struct 0
+CfgRa: .space 8 // return address
+CfgA0: .space 8 // saved McDevid
+CfgA1: .space 8 // saved BusNumber
+CfgA2: .space 8 // saved SlotNumber
+CfgA3: .space 8 // saved Offset
+CfgA4: .space 8 // padding for 16 byte alignment
+CfgFrameLength:
+
+#endif
+
+//++
+//
+// ULONG
+// READ_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read an unsigned byte from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//
+//--
+
+ LEAF_ENTRY( READ_CONFIG_UCHAR )
+
+//
+// Set the flag indicating the number of the processor upon which a PCI master abort
+// may be expected by the machine check handler.
+//
+
+#if !defined(AXP_FIRMWARE)
+ GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = prcb base address
+ ldl t0, PbNumber(v0) // capture current processor number
+#else
+ bis zero,zero,t0 // Force processor zero in fw
+#endif
+ extbl t0, 0, t0 // PbNumber is of type CCHAR
+ lda t4, HalpMasterAbortExpected // get address of flag
+ stl t0, MabNumber(t4) // save current processor number
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c
+ sll t7, 28, t7 // 0xffff fc81 c000 0000
+
+ extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress
+ sll t0, 33, t0 // shift McDevId into position @ bit 33
+ bis t7, t0, t7 // superpage mode
+
+ and a0, 0x3, t3 // capture byte lane
+ zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress
+ sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position
+ bis t7, t1, t7 //
+
+ bis t7, IO_BYTE_LEN, t7 // or in the byte enables
+ stq t7, MabAddr(t4) // save current access address
+
+ .set noreorder // cannot reorder these instructions
+
+ mb // order the writes
+ ldl v0, (t7) // read the longword
+ mb // stall the pipe waiting for mchk
+ mb //
+ extbl v0, t3, v0 // return byte from requested lane
+
+ .set reorder // reordering can begin again
+
+ lda t5, MASTER_ABORT_NOT_EXPECTED(zero)
+ stl t5, MabNumber(t4) // "clear" flag
+
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_UCHAR
+
+//++
+//
+// VOID
+// WRITE_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// UCHAR ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write an unsigned byte to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// None.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ LEAF_ENTRY( WRITE_CONFIG_UCHAR )
+
+//
+// Perform the write to configuration space
+//
+
+ lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c
+ sll t7, 28, t7 // 0xffff fc81 c000 0000
+
+ extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress
+ sll t0, 33, t0 // shift McDevId into position @ bit 33
+ bis t7, t0, t7 // superpage mode
+
+ and a0, 0x3, t3 // capture byte lane
+ zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress
+ sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position
+ bis t7, t1, t7 //
+
+ bis t7, IO_BYTE_LEN, t7 // or in the byte enables
+
+ insbl a1, t3, t4 // put byte in the appropriate lane
+ stl t4, (t7) // write the configuration byte
+ mb // synchronize
+
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_UCHAR
+
+//++
+//
+// ULONG
+// READ_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a short from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ LEAF_ENTRY( READ_CONFIG_USHORT )
+
+//
+// Set the flag indicating the number of the processor upon which a PCI master abort
+// may be expected by the machine check handler.
+//
+
+#if !defined(AXP_FIRMWARE)
+ GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = prcb base address
+ ldl t0, PbNumber(v0) // capture current processor number
+#else
+ bis zero,zero,t0 // Force processor zero in fw
+#endif
+ extbl t0, 0, t0 // PbNumber is of type CCHAR
+ lda t4, HalpMasterAbortExpected // get address of flag
+ stl t0, MabNumber(t4) // save current processor number
+
+//
+// Perform the read from configuration space.
+//
+ lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c
+ sll t7, 28, t7 // 0xffff fc81 c000 0000
+
+ extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress
+ sll t0, 33, t0 // shift McDevId into position @ bit 33
+ bis t7, t0, t7 // superpage mode
+
+ and a0, 0x3, t3 // capture word offset
+ zapnot a0, 0x7,a0 // Clear McDevid from ConfigAddress
+ sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position
+ bis t7, t1, t7 //
+
+ bis t7, IO_WORD_LEN, t7 // or in the byte enables
+ stq t7, MabAddr(t4) // save current access address
+
+ .set noreorder // cannot reorder these instructions
+
+ mb // order the write
+ ldl v0, (t7) // read the longword
+ mb // stall the pipe waiting for mchk
+ mb //
+ extwl v0, t3, v0 // return word from requested lanes
+
+ .set reorder // reordering can begin again
+
+ lda t5, MASTER_ABORT_NOT_EXPECTED(zero)
+ stl t5, MabNumber(t4) // "clear" flag
+
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_USHORT
+
+//++
+//
+// VOID
+// WRITE_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// UCHAR ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write a short to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ LEAF_ENTRY( WRITE_CONFIG_USHORT )
+
+//
+// Perform the write to configuration space.
+//
+
+ lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c
+ sll t7, 28, t7 // 0xffff fc81 c000 0000
+
+ extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress
+ sll t0, 33, t0 // shift McDevId into position @ bit 33
+ bis t7, t0, t7 // superpage mode
+
+ and a0, 0x3, t3 // capture word offset
+ zapnot a0, 0x7,a0 // Clear McDevid from ConfigAddress
+ sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position
+ bis t7, t1, t7 //
+
+ bis t7, IO_WORD_LEN, t7 // or in the byte enables
+
+ inswl a1, t3, t4 // put byte in the appropriate lane
+ stl t4, (t7) // write the configuration byte
+ mb // synchronize
+
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_USHORT
+
+//++
+//
+// ULONG
+// READ_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ LEAF_ENTRY( READ_CONFIG_ULONG )
+
+//
+// Set the flag indicating the number of the processor upon which a PCI master abort
+// may be expected by the machine check handler.
+//
+
+#if !defined(AXP_FIRMWARE)
+ GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = prcb base address
+ ldl t0, PbNumber(v0) // capture current processor number
+#else
+ bis zero,zero,t0 // Force processor zero in fw
+#endif
+ extbl t0, 0, t0 // PbNumber is of type CCHAR
+ lda t4, HalpMasterAbortExpected // get address of flag
+ stl t0, MabNumber(t4) // save current processor number
+
+//
+// Perform the read from configuration space.
+//
+ lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c
+ sll t7, 28, t7 // 0xffff fc81 c000 0000
+
+ extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress
+ sll t0, 33, t0 // shift McDevId into position @ bit 33
+ bis t7, t0, t7 // superpage mode
+
+ zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress
+ sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position
+ bis t7, t1, t7 //
+
+ bis t7, IO_LONG_LEN, t7 // or in the byte enables
+ stq t7, MabAddr(t4) // save current access address
+
+ .set noreorder // cannot reorder these instructions
+
+ mb // order the writes
+ ldl v0, (t7) // read the longword
+ mb // stall the pipe waiting for mchk
+ mb //
+
+ .set reorder // reordering can begin again
+
+ lda t5, MASTER_ABORT_NOT_EXPECTED(zero)
+ stl t5, MabNumber(t4) // "clear" flag
+
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_ULONG
+
+
+//++
+//
+// VOID
+// WRITE_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ LEAF_ENTRY( WRITE_CONFIG_ULONG )
+
+//
+// Perform the write to configuration space.
+//
+
+ lda t7, IOD_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c81c
+ sll t7, 28, t7 // 0xffff fc81 c000 0000
+
+ extbl a0, 0x3, t0 // Extract McDevId from ConfigAddress
+ sll t0, 33, t0 // shift McDevId into position @ bit 33
+ bis t7, t0, t7 // superpage mode
+
+ zapnot a0, 0x7, a0 // Clear McDevid from ConfigAddress
+ sll a0, IO_BIT_SHIFT, t1 // Shift the rest into position
+ bis t7, t1, t7 //
+
+ bis t7, IO_LONG_LEN, t7 // or in the byte enables
+
+ stl a1, (t7) // write the longword
+ mb // synchronize
+
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_ULONG
+
+//++
+//
+// ULONG
+// INTERRUPT_ACKNOWLEDGE(
+// VOID
+// )
+//
+// Routine Description:
+//
+// Perform an interrupt acknowledge cycle on PCI bus 0
+//
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// (v0) Returns the vector returned by the interrupt acknowledge
+// read.
+//
+//--
+
+
+ LEAF_ENTRY( INTERRUPT_ACKNOWLEDGE )
+
+ lda t0, IOD_PCI0_REGISTER_SVA(zero) // 0xffff ffff ffff cf9e
+ sll t0, 28, t0 // 0xffff fcf9 e000 0000
+ lda t0, 0x480(t0) // 0xffff fcf9 e000 0480
+
+ ldl v0, 0(t0) // perform PCI0 IACK, get vector
+
+ ret zero, (ra) // return
+
+ .end INTERRUPT_ACKNOWLEDGE
+
+ SBTTL( "IOD Interrupt Acknowledge" )
+//++
+//
+// VOID
+// IOD_INTERRUPT_ACKNOWEDGE
+// IN ULONG McDeviceId,
+// IN ULONG Target
+// )
+//
+// Routine Description:
+//
+// Perform an IOD interrupt acknowledge to the selected
+// interrupt target.
+//
+// Arguments:
+//
+// McDeviceId(a0) - MC Bus Device ID of the IOD to acknowledge
+//
+// Target(a1) - Which one of two interrupt targets generated
+// the interrupt. Must be 0 or 1.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(IOD_INTERRUPT_ACKNOWLEDGE)
+
+//
+// Generate the superpage address of the requested IOD INT_ACK register
+//
+ mb
+
+ extbl a0, zero, a0 // McDevId
+
+ sll a1, 6, a1 // Which target?
+ lda t4, IOD_TARGET0_OFFSET // If target = 0, offset = 0x3f00
+ bis a1, t4, t4 // If target = 1, offset = 0x3f40
+
+ lda t0, IOD_INT_ACK_SVA(zero) //0xffff ffff ffff c81f
+ sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId
+ bis t0, t1, t0 // 0xffff fc81 f000 0000
+ sll t0, 28, t0 // 0xffff fcXX f000 0000
+
+ or t0, t4, t0 // 0xffff fcXX f000 3f00/3f40
+ stl zero, (t0) // write the longword
+ mb // order the write
+ mb // SPECIAL 2nd MB for Rawhide
+
+ ret zero, (ra) // return
+
+ .end IOD_INTERRUPT_ACKNOWLEDGE
+
+
+ SBTTL( "CPU Clock Interrupt Acknowledge" )
+//++
+//
+// VOID
+// CPU_CLOCK_ACKNOWEDGE
+// IN ULONG McDeviceId
+// )
+//
+// Routine Description:
+//
+// Perform an clock (interval timer) interrupt acknowledge to the
+// selected CPU.
+//
+// Arguments:
+//
+// McDevid(a0) - MC Bus Device ID of the CPU to acknowledge.
+//
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(CPU_CLOCK_ACKNOWLEDGE)
+
+//
+// Generate the superpage address of the requested CUD's INTTIM_ACK register
+//
+
+
+ extbl a0, zero, a0 // McDeviceId
+
+ lda t0, IOD_INTTIM_SVA(zero) //0xffff ffff ffff c810
+ sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId
+ bis t0, t1, t0 // 0xffff fc81 0000 0000
+ sll t0, 28, t0 // 0xffff fcXX 0000 0000
+
+ stl zero, (t0) // write the longword
+ mb // order the write
+ mb // SPECIAL 2nd MB for Rawhide
+
+ ret zero, (ra) // return
+
+ .end CPU_CLOCK_ACKNOWLEDGE
+
+
+
+ SBTTL( "Interprocessor Interrupt Request" )
+//++
+//
+// VOID
+// IP_INTERRUPT_REQUEST
+// IN ULONG McDeviceId
+// )
+//
+// Routine Description:
+//
+// Perform an inteprocessor interrupt request to the
+// selected CPU.
+//
+// Arguments:
+//
+// McDevid(a0) - MC Bus Device ID of the CPU to send an IPI request.
+//
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(IP_INTERRUPT_REQUEST)
+
+//
+// Generate the superpage address of the requested CUD's IP_INTR register
+//
+
+
+ extbl a0, zero, a0 // McDeviceId
+
+ lda t0, IOD_IP_INTR_SVA(zero) // 0xffff ffff ffff c801
+ sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId
+ bis t0, t1, t0 // 0xffff fc80 1000 0000
+ sll t0, 28, t0 // 0xffff fcXX 1000 0000
+
+ stl zero, (t0) // write the longword
+ mb // order the write
+ mb // SPECIAL 2nd MB for Rawhide
+
+ ret zero, (ra) // return
+
+ .end IP_INTERRUPT_REQUEST
+
+
+ SBTTL( "Interprocessor Interrupt Acknowledge" )
+//++
+//
+// VOID
+// IP_INTERRUPT_ACKNOWEDGE
+// IN ULONG McDeviceId
+// )
+//
+// Routine Description:
+//
+// Perform an inteprocessor interrupt acknowledge to the
+// selected CPU.
+//
+// Arguments:
+//
+// McDevid(a0) - MC Bus Device ID of the CPU to send an IPI acknowledge.
+//
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(IP_INTERRUPT_ACKNOWLEDGE)
+
+//
+// Generate the superpage address of the requested CUD's IP_ACK register
+//
+
+
+ extbl a0, zero, a0 // McDeviceId
+
+ lda t0, IOD_IP_ACK_SVA(zero) // 0xffff ffff ffff c811
+ sll a0, 5, t1 // 0x0000000mc 0000 0000 McDeviceId
+ bis t0, t1, t0 // 0xffff fc81 1000 0000
+ sll t0, 28, t0 // 0xffff fcXX 1000 0000
+
+ stl zero, (t0) // write the longword
+ mb // order the write
+ mb // SPECIAL 2nd MB for Rawhide
+
+ ret zero, (ra) // return
+
+ .end IP_INTERRUPT_ACKNOWLEDGE