/*++
Copyright (c) 1993 Digital Equipment Corporation
Module Name:
alphaio.s
Abstract:
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.
(We are using EV4 64-bit superpage mode.)
Author:
Joe Notarangelo 25-Oct-1993
Environment:
Executes in kernel mode.
Revision History:
12-Jul-1994 - Eric Rehm - Added dense space I/O
27-July-1994 - Sameer Dekate
Make a common file for all machines and optimize Read/Write
register buffer routines. Made a common routine with different
entry points for READ & WRITE_REGISTER_BUFFER routines
--*/
#include "halalpha.h"
#include "apoc.h"
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
.struct 0
.space 8 // filler for octaword alignment
IoRa: .space 8 // space for return address
IoS0: .space 8 // space for S0
IoS1: .space 8 // space for S1
IoS2: .space 8 // space for S2
IoIrql: .space 8 // space for local variable
IoFrameLength: //
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
#define EV4_IO(FastIoRoutine) \
ldq t0, HalpPciDenseBasePhysicalSuperPage; \
ldl t1, HalpIoArchitectureType; \
beq t1, FastIoRoutine; \
and a0, DTI_QVA_SELECTORS, t1; \
xor t1, DTI_QVA_ENABLE, t1; \
bne t1, FastIoRoutine; \
lda sp, -IoFrameLength(sp); \
stq ra, IoRa(sp); \
stq s0, IoS0(sp); \
stq s1, IoS1(sp); \
stq s2, IoS2(sp); \
or a0, a0, s0; \
or a1, a1, s1; \
or a2, a2, s2; \
or zero, HIGH_LEVEL, a0; \
addq sp, IoIrql, a1; \
bsr ra, KeRaiseIrql; \
or s0, s0, a0; \
bsr ra, HalpMiniTlbResolve; \
or v0, v0, a0; \
or s1, s1, a1; \
or s2, s2, a2; \
ldq t0, HalpPciDenseBasePhysicalSuperPage; \
bsr ra, FastIoRoutine; \
or v0, v0, s0; \
ldq a0, IoIrql(sp); \
and a0, 0xff, a0; \
bsr ra, KeLowerIrql; \
or s0, s0, v0; \
ldq s2, IoS2(sp); \
ldq s1, IoS1(sp); \
ldq s0, IoS0(sp); \
ldq ra, IoRa(sp); \
lda sp, IoFrameLength(sp); \
ret zero, (ra)
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
LEAF_ENTRY(READ_REGISTER_UCHAR)
ALTERNATE_ENTRY(READ_PORT_UCHAR)
EV4_IO(EV5_READ_PORT_UCHAR)
.end READ_REGISTER_UCHAR
LEAF_ENTRY(READ_REGISTER_USHORT)
ALTERNATE_ENTRY(READ_PORT_USHORT)
EV4_IO(EV5_READ_PORT_USHORT)
.end READ_REGISTER_USHORT
LEAF_ENTRY(READ_REGISTER_ULONG)
ALTERNATE_ENTRY(READ_PORT_ULONG)
EV4_IO(EV5_READ_PORT_ULONG)
.end READ_REGISTER_ULONG
LEAF_ENTRY(WRITE_REGISTER_UCHAR)
ALTERNATE_ENTRY(WRITE_PORT_UCHAR)
EV4_IO(EV5_WRITE_PORT_UCHAR)
.end WRITE_REGISTER_UCHAR
LEAF_ENTRY(WRITE_REGISTER_USHORT)
ALTERNATE_ENTRY(WRITE_PORT_USHORT)
EV4_IO(EV5_WRITE_PORT_USHORT)
.end WRITE_REGISTER_USHORT
LEAF_ENTRY(WRITE_REGISTER_ULONG)
ALTERNATE_ENTRY(WRITE_PORT_ULONG)
EV4_IO(EV5_WRITE_PORT_ULONG)
.end WRITE_REGISTER_ULONG
LEAF_ENTRY(READ_PORT_BUFFER_UCHAR)
EV4_IO(EV5_READ_PORT_BUFFER_UCHAR)
.end READ_PORT_BUFFER_UCHAR
LEAF_ENTRY(READ_PORT_BUFFER_USHORT)
EV4_IO(EV5_READ_PORT_BUFFER_USHORT)
.end READ_PORT_BUFFER_USHORT
LEAF_ENTRY(READ_PORT_BUFFER_ULONG)
EV4_IO(EV5_READ_PORT_BUFFER_ULONG)
.end READ_PORT_BUFFER_ULONG
LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR)
EV4_IO(EV5_WRITE_PORT_BUFFER_UCHAR)
.end WRITE_PORT_BUFFER_UCHAR
LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT)
EV4_IO(EV5_WRITE_PORT_BUFFER_USHORT)
.end WRITE_PORT_BUFFER_USHORT
LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG)
EV4_IO(EV5_WRITE_PORT_BUFFER_ULONG)
.end WRITE_PORT_BUFFER_ULONG
LEAF_ENTRY(READ_REGISTER_BUFFER_UCHAR)
EV4_IO(EV5_READ_REGISTER_BUFFER_UCHAR)
.end READ_REGISTER_BUFFER_UCHAR
LEAF_ENTRY(READ_REGISTER_BUFFER_USHORT)
EV4_IO(EV5_READ_REGISTER_BUFFER_USHORT)
.end READ_REGISTER_BUFFER_USHORT
LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG)
EV4_IO(EV5_READ_REGISTER_BUFFER_ULONG)
.end READ_REGISTER_BUFFER_ULONG
LEAF_ENTRY(WRITE_REGISTER_BUFFER_UCHAR)
EV4_IO(EV5_WRITE_REGISTER_BUFFER_UCHAR)
.end WRITE_REGISTER_BUFFER_UCHAR
LEAF_ENTRY(WRITE_REGISTER_BUFFER_USHORT)
EV4_IO(EV5_WRITE_REGISTER_BUFFER_USHORT)
.end WRITE_REGISTER_BUFFER_USHORT
LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG)
EV4_IO(EV5_WRITE_REGISTER_BUFFER_ULONG)
.end WRITE_REGISTER_BUFFER_ULONG
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
SBTTL( "Read I/O byte" )
//++
//
// UCHAR
// READ_REGISTER_UCHAR(
// IN PVOID RegisterQva
// )
//
// Routine Description:
//
// Reads a byte location in PCI bus memory or 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(EV5_READ_REGISTER_UCHAR)
ALTERNATE_ENTRY(EV5_READ_PORT_UCHAR)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
and a0, 3, t3 // get byte we need if eisa
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_QVA_ENABLE set in selectors
bne t1, 2f // if ne, iff failed
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // 0xffff ffff ffff cf80
sll t4, 28, t4 // 0xffff fcf8 0000 0000
or t0, t4, t0 // superpage mode
mb
ldl v0, (t0) // get the longword
extbl v0, t3, v0 // get correct byte if eisa
ret zero, (ra) // return
//
// Dense space access: QVA is an offset into dense space
//
2:
and a0, 3, t3 // get byte we need
zap a0, 0xf0, a0 // clear <63:32>
bic a0, 3, a0 // clear <1:0> to get aligned longword
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
or a0, t0, a0 // superpage mode: add offset to base
ldl v0, (a0) // get the longword
extbl v0, t3, v0 // get correct byte
ret zero, (ra) // return
.end EV5_READ_REGISTER_UCHAR
SBTTL( "Read I/O word(16 bits)" )
//++
//
// USHORT
// READ_REGISTER_USHORT(
// IN PVOID RegisterQva
// )
//
// Routine Description:
//
// Reads a word location in PCI bus memory or I/O space.
//
// Arguments:
//
// RegisterQva(a0) - Supplies the QVA of the I/O word to read.
//
// Return Value:
//
// v0 - Returns the value read from I/O space.
//
//--
LEAF_ENTRY(EV5_READ_REGISTER_USHORT)
ALTERNATE_ENTRY(EV5_READ_PORT_USHORT)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
and a0, 3, t3 // get word
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_QVA_ENABLE set in selectors
bne t1, 2f // if ne, iff failed
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 //
ldiq t4, -0x3080 //
sll t4, 28, t4 //
or t0, t4, t0 // superpage mode
or t0, IO_WORD_LEN, t0 // or in the byte enables
mb
ldl v0, (t0) // get the longword
extwl v0,t3,v0 // get the correct word
ret zero, (ra) // return
//
// Dense space access: QVA is an offset into dense space
//
2:
and a0, 3, t3 // get word we need
zap a0, 0xf0, a0 // clear <63:32>
bic a0, 3, a0 // clear <1:0> to get aligned longword
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
or a0,t0, a0 // superpage mode: add offset to base
ldl v0, (a0) // get the longword
extwl v0, t3, v0 // get correct word
ret zero, (ra) // return
.end EV5_READ_REGISTER_USHORT
SBTTL( "Read I/O longword(32 bits)" )
//++
//
// ULONG
// READ_REGISTER_ULONG(
// IN PVOID RegisterQva
// )
//
// Routine Description:
//
// Reads a longword location in PCI bus memory or I/O space.
//
// Arguments:
//
// RegisterQva(a0) - Supplies the QVA of the I/O longword to read.
//
// Return Value:
//
// v0 - Returns the value read from I/O space.
//
//--
LEAF_ENTRY(EV5_READ_REGISTER_ULONG)
ALTERNATE_ENTRY(EV5_READ_PORT_ULONG)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_QVA_ENABLE set in selectors
bne t1, 2f // if ne, iff failed
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 //
ldiq t4, -0x3080 //
sll t4, 28, t4 //
or t0, t4, t0 // superpage mode
or t0, IO_LONG_LEN, t0 // or in the byte enables
mb
ldl v0, (t0) // read the longword
ret zero, (ra) // return
//
// Dense space access: QVA is an offset into dense space
//
2:
zap a0, 0xf0, a0 // clear <63:32>
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
or a0, t0, a0 // superpage mode: add offset to base
ldl v0, (a0) // get the longword
ret zero, (ra) // return
.end EV5_READ_REGISTER_ULONG
SBTTL( "Write I/O byte" )
//++
//
// VOID
// WRITE_REGISTER_UCHAR(
// IN PVOID RegisterQva,
// IN UCHAR Value
// )
//
// Routine Description:
//
// Writes a byte location in PCI bus memory or I/O space.
//
// Arguments:
//
// RegisterQva(a0) - Supplies the QVA of the I/O byte to write.
//
// Value(a1) - Supplies the value written to I/O space.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(EV5_WRITE_REGISTER_UCHAR)
ALTERNATE_ENTRY(EV5_WRITE_PORT_UCHAR)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
and a0, 3, t3 // get byte we need if eisa
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_QVA_ENABLE set in selectors
bne t1, 2f // if ne, iff failed
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 //
sll t4, 28, t4 //
or t0, t4, t0 // superpage mode
insbl a1,t3,t4 // put the byte in the correct position
stl t4, (t0) // write the byte
mb // order the write
ret zero, (ra) // return
//
// Dense space access: QVA is an offset into dense space
//
2:
and a0, 3, t3 // get byte we need if eisa
zap a0, 0xf0, a0 // clear <63:32>
bic a0, 3, a0 // clear <1:0> to get aligned longword
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
or a0, t0, a0 // superpage mode: add offset to base
ldl t1, (a0) // get the long
mskbl t1, t3, t1 // mask the proper byte
insbl a1, t3, t2 // put byte into position
bis t1, t2, t1 // merge byte in result
stl t1, (a0) // store the result
mb // order the write
ret zero, (ra) // return
.end EV5_WRITE_REGISTER_UCHAR
SBTTL( "Write I/O word (16 bits)" )
//++
//
// VOID
// WRITE_REGISTER_USHORT(
// IN PVOID RegisterQva,
// IN USHORT Value
// )
//
// Routine Description:
//
// Writes a word location in PCI bus memory or I/O space.
//
// Arguments:
//
// RegisterQva(a0) - Supplies the QVA of the I/O word to write.
//
// Value(a1) - Supplies the value written to I/O space.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(EV5_WRITE_REGISTER_USHORT)
ALTERNATE_ENTRY(EV5_WRITE_PORT_USHORT)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
and a0, 3, t3 // get word
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_QVA_ENABLE set in selectors
bne t1, 2f // if ne, iff failed
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 //
ldiq t4, -0x3080 //
sll t4, 28, t4 //
or t0, t4, t0 // superpage mode
or t0, IO_WORD_LEN, t0 // or in the byte enables
inswl a1,t3,t2 // put the word in the correct place
stl t2, (t0) // write the word
mb // order the write
ret zero, (ra) // return
//
// Dense space access: QVA is an offset into dense space
//
2:
and a0, 3, t3 // get byte we need if eisa
zap a0, 0xf0, a0 // clear <63:32>
bic a0, 3, a0 // clear <1:0> to get aligned longword
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
or a0, t0, a0 // superpage mode: add offset to base
ldl t1, (a0) // get the long
mskwl t1, t3, t1 // mask the proper word
inswl a1, t3, t2 // put word into position
bis t1, t2, t1 // merge in result
stl t1, (a0) // store the result
mb // order the write
ret zero, (ra) // return
.end EV5_WRITE_REGISTER_USHORT
SBTTL( "Write I/O longword (32 bits)" )
//++
//
// VOID
// WRITE_REGISTER_ULONG(
// IN PVOID RegisterQva,
// IN ULONG Value
// )
//
// Routine Description:
//
// Writes a longword location in PCI bus memory or I/O space.
//
// Arguments:
//
// RegisterQva(a0) - Supplies the QVA of the I/O longword to write.
//
// Value(a1) - Supplies the value written to I/O space.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(EV5_WRITE_REGISTER_ULONG)
ALTERNATE_ENTRY(EV5_WRITE_PORT_ULONG)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_QVA_ENABLE set in selectors
bne t1, 2f // if ne, iff failed
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 //
ldiq t4, -0x3080 //
sll t4, 28, t4 //
or t0, t4, t0 // superpage mode
or t0, IO_LONG_LEN, t0 // or in the byte enables
stl a1, (t0) // write the longword
mb // order the write
ret zero, (ra) // return
//
// Dense space access: QVA is an offset into dense space
//
2:
zap a0, 0xf0, a0 // clear <63:32>
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
or a0, t0, a0 // superpage mode: add offset to base
stl a1, (a0) // store the longword
mb // order the write
ret zero, (ra) // return
.end EV5_WRITE_REGISTER_ULONG
//++
//
// 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(EV5_READ_PORT_BUFFER_UCHAR)
and a0, 3, t3 // get byte we need if eisa
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // t4=ffff ffff ffff c000
sll t4, 28, t4 // t4=ffff fc00 0000 0000
or t0, t4, t0 // superpage mode
beq a2, 3f // if count==0 return
2:
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
bne a2, 2b // while count != 0
3:
ret zero, (ra) // return
.end EV5_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(EV5_READ_PORT_BUFFER_USHORT)
and a0, 3, t3 // get word we need
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // t4=ffff ffff ffff c000
sll t4, 28, t4 // t4=ffff fc00 0000 0000
or t0, t4, t0 // superpage mode
or t0, IO_WORD_LEN, t0 // or in the byte enables
beq a2, 3f // if count==0 return
2:
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
bne a2, 2b // while count != 0
3:
ret zero, (ra) // return
.end EV5_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(EV5_READ_PORT_BUFFER_ULONG)
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // t4=ffff ffff ffff c000
sll t4, 28, t4 // t4=ffff fc00 0000 0000
or t0, t4, t0 // superpage mode
or t0, IO_LONG_LEN, t0 // or in the byte enables
beq a2, 3f // if count==0 return
2:
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
bne a2, 2b // while count != 0
3:
ret zero, (ra) // return
.end EV5_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(EV5_WRITE_PORT_BUFFER_UCHAR)
and a0, 3, t3 // get byte we need if eisa
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // t4=ffff ffff ffff c000
sll t4, 28, t4 // t4=ffff fc00 0000 0000
or t0, t4, t0 // superpage mode
beq a2, 3f // if count==0 return
2:
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
bne a2, 2b // while count != 0
3:
ret zero, (ra) // return
.end EV5_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(EV5_WRITE_PORT_BUFFER_USHORT)
and a0, 3, t3 // get word we need
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // t4=ffff ffff ffff c000
sll t4, 28, t4 // t4=ffff fc00 0000 0000
or t0, t4, t0 // superpage mode
or t0, IO_WORD_LEN, t0 // or in the byte enables
beq a2, 3f // if count==0 return
2:
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 writes off chip
bne a2, 2b // while count != 0
3:
ret zero, (ra) // return
.end EV5_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(EV5_WRITE_PORT_BUFFER_ULONG)
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // t4=ffff ffff ffff c000
sll t4, 28, t4 // t4=ffff fc00 0000 0000
or t0, t4, t0 // superpage mode
or t0, IO_LONG_LEN, t0 // or in the byte enables
beq a2, 3f // if count==0 return
2:
ldl t1, 0(a1) // a1 must be longword aligned
subl a2, 1, a2 // decrement count
stl t1, 0(t0) // store to port
mb // push writes off chip
addl a1, 4, a1 // increment buffer
bne a2, 2b // while count != 0
3:
ret zero, (ra) // return
.end EV5_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(EV5_READ_REGISTER_BUFFER_ULONG)
sll a2, 1, a2 // convert number of longs to words
ALTERNATE_ENTRY(EV5_READ_REGISTER_BUFFER_USHORT)
sll a2, 1, a2 // convert number of words to chars
ALTERNATE_ENTRY(EV5_READ_REGISTER_BUFFER_UCHAR)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_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>
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
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>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // 0xffff ffff ffff c000
sll t4, 28, t4 // 0xffff fc00 0000 0000
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)
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:
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:
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)
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
//
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
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:
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 EV5_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(EV5_WRITE_REGISTER_BUFFER_ULONG)
sll a2, 1, a2 // convert number of longs to words
ALTERNATE_ENTRY(EV5_WRITE_REGISTER_BUFFER_USHORT)
sll a2, 1, a2 // convert number of words to chars
ALTERNATE_ENTRY(EV5_WRITE_REGISTER_BUFFER_UCHAR)
and a0, DTI_QVA_SELECTORS, t1 // get qva selector bits
xor t1, DTI_QVA_ENABLE, t1 // ok iff DTI_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>
// ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
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:
zap a0, 0xf0, a0 // clear <63:32>
bic a0, DTI_QVA_ENABLE,a0 // clear QVA fields so shift is correct
sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
ldiq t4, -0x3080 // 0xffff ffff ffff c000
sll t4, 28, t4 // 0xffff fc00 0000 0000
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
stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
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
stl t1, 0(t0) // store to buffer
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
stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
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
stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
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 EV5_WRITE_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
//++
//
// VOID
// HalpWriteAbsoluteUlong(
// IN ULONG HighPart,
// IN ULONG LowPart,
// IN ULONG Value
// )
//
// Routine Description:
//
// Writes Value to the processor address given in HighPart and LowPart.
//
// Arguments:
//
// HighPart(a0) - Upper 32 bits of address
//
// LowPart(a1) - Lower 32 bits of address
//
// Value(a2) - Value to write
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(HalpWriteAbsoluteUlong)
sll a0, 32, t0 // Shift Upper 32 bits of address into position
zap t0, 0x0f, t0 // Clear lower 32 bits of shifted address
zap a1, 0xf0, a1 // Clear upper 32 of lower part of address
or a1, t0, t0 // Build 64 bit address
stl a2, 0x0(t0) // Write value to address
mb // Memory Barrier
ret zero, (ra) // return
.end HalpWriteAbsoluteUlong
//++
//
// ULONG
// HalpReadAbsoluteUlong(
// IN ULONG HighPart,
// IN ULONG LowPart
// )
//
// Routine Description:
//
// Reads a value from the processor address given in HighPart and LowPart.
//
// Arguments:
//
// HighPart(a0) - Upper 32 bits of address
//
// LowPart(a1) - Lower 32 bits of address
//
// Return Value:
//
// 32 bit value read from the processor address.
//
//--
LEAF_ENTRY(HalpReadAbsoluteUlong)
sll a0, 32, t0 // Shift Upper 32 bits of address into position
zap t0, 0x0f, t0 // Clear lower 32 bits of shifted address
zap a1, 0xf0, a1 // Clear upper 32 of lower part of address
or a1, t0, t0 // Build 64 bit address
mb // Memory Barrier
ldl v0, 0x0(t0) // Read value from address
ret zero, (ra) // return
.end HalpReadAbsoluteUlong