NT4/private/ntos/nthals/halraw/alpha/iodio.s
2020-09-30 17:12:29 +02:00

2998 lines
92 KiB
ArmAsm
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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