957 lines
32 KiB
ArmAsm
957 lines
32 KiB
ArmAsm
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1993 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
sableio.s
|
|||
|
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This contains assembler code routines for the Sable system.
|
|||
|
|
|||
|
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:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "sable.h"
|
|||
|
#include "halalpha.h"
|
|||
|
|
|||
|
.set noreorder
|
|||
|
|
|||
|
|
|||
|
LEAF_ENTRY(WRITE_T2_REGISTER)
|
|||
|
|
|||
|
ALTERNATE_ENTRY(WRITE_CPU_REGISTER)
|
|||
|
|
|||
|
ALTERNATE_ENTRY(WRITE_MEM_REGISTER)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
Writes a T2, Memory Module or a CPU CSR.
|
|||
|
|
|||
|
Arguments:
|
|||
|
a0 QVA of register to be written.
|
|||
|
a1 Longword to be written.
|
|||
|
|
|||
|
Return Value:
|
|||
|
None.
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
|
|||
|
bne t1, 2f // 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
|
|||
|
ldiq t4, -0x4000
|
|||
|
sll t4, 28, t4
|
|||
|
or t0, t4, t0 // superpage mode
|
|||
|
stq a1, (t0) // write the quadword
|
|||
|
mb // order the write
|
|||
|
mb
|
|||
|
ret zero, (ra)
|
|||
|
|
|||
|
2:
|
|||
|
BREAK_DEBUG_STOP // Bad Qva
|
|||
|
ret zero, (ra)
|
|||
|
|
|||
|
.end WRITE_T2_REGISTER
|
|||
|
|
|||
|
|
|||
|
|
|||
|
LEAF_ENTRY(READ_T2_REGISTER)
|
|||
|
|
|||
|
ALTERNATE_ENTRY(READ_CPU_REGISTER)
|
|||
|
|
|||
|
ALTERNATE_ENTRY(READ_MEM_REGISTER)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Read a T2, Memory Module or CPU CSR.
|
|||
|
|
|||
|
Arguments:
|
|||
|
a0 QVA of register to be read.
|
|||
|
|
|||
|
Return Value:
|
|||
|
The quadword read from the register.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
|
|||
|
bne t1, 2f // 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
|
|||
|
ldiq t4, -0x4000
|
|||
|
sll t4, 28, t4
|
|||
|
or t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
ldq v0, (t0) // read the register
|
|||
|
mb // synchronize
|
|||
|
mb //
|
|||
|
|
|||
|
ret zero, (ra)
|
|||
|
|
|||
|
2:
|
|||
|
BREAK_DEBUG_STOP // Bad Qva
|
|||
|
ret zero, (ra)
|
|||
|
|
|||
|
.end READ_T2_REGISTER
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Values and structures used to access configuration space.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Define the QVA for the Configuration Cycle Type register within the
|
|||
|
// IOC.
|
|||
|
//
|
|||
|
|
|||
|
// PASS 1 SABLE SUPPORT
|
|||
|
|
|||
|
#define T2_HAE0_2_QVA (0xbc700008)
|
|||
|
#define T2_HAE02_CYCLETYPE_SHIFT 30
|
|||
|
#define T2_HAE02_CYCLETYPE_MASK 0xc0000000
|
|||
|
|
|||
|
// PASS 2 SABLE SUPPORT
|
|||
|
|
|||
|
#define T2_HAE0_3_QVA (0xbc700012)
|
|||
|
#define T2_HAE03_CYCLETYPE_SHIFT 30
|
|||
|
#define T2_HAE03_CYCLETYPE_MASK 0xc0000000
|
|||
|
#define T2_CONFIG_ADDR_QVA (0xbc800000)
|
|||
|
|
|||
|
// T4 SUPPORT
|
|||
|
|
|||
|
#define T4_HAE0_3_QVA (0xbc780012)
|
|||
|
#define T4_CONFIG_ADDR_QVA (0xbcc00000)
|
|||
|
|
|||
|
#define T2_OR_T4 (0x00400000)
|
|||
|
|
|||
|
//
|
|||
|
// Define the configuration routines stack frame.
|
|||
|
//
|
|||
|
|
|||
|
.struct 0
|
|||
|
CfgRa: .space 8 // return address
|
|||
|
CfgA0: .space 8 // saved ConfigurationAddress
|
|||
|
CfgA1: .space 8 // saved ConfigurationData
|
|||
|
CfgA2: .space 8 // padding for 16 byte alignment
|
|||
|
CfgFrameLength:
|
|||
|
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// 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)
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero )
|
|||
|
|
|||
|
lda sp, -CfgFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, CfgRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END // end prologue
|
|||
|
|
|||
|
//
|
|||
|
// Depending on whether it's a pass 1 or pass 2 sable the configuration
|
|||
|
// cycle type is in different registers
|
|||
|
//
|
|||
|
ldl t0, T2VersionNumber // load version number
|
|||
|
beq t0, 1f // if 0 then pass 1 sable
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// PASS 2 sable or Xio access:
|
|||
|
// Cycle type are the only bits in HAE0_3 register
|
|||
|
//
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
|
|||
|
//
|
|||
|
// See if this was a request on the T4 or the T2 by looking at the
|
|||
|
// Config address passed in.
|
|||
|
//
|
|||
|
|
|||
|
ldil t1, T2_HAE0_3_QVA // address of T2's HAE0_3
|
|||
|
ldil t2, T4_HAE0_3_QVA // address of T4's HAE0_3
|
|||
|
|
|||
|
ldil t0, T2_OR_T4 // Load mask to tell if T2 or T4
|
|||
|
and a0, t0, t3 // mask out other bits
|
|||
|
cmoveq t3, t1, a0 // if t3 == 0 then t1 -> a0
|
|||
|
cmovne t3, t2, a0 // if t3 != 0 then t2 -> a0
|
|||
|
|
|||
|
sll a1, T2_HAE03_CYCLETYPE_SHIFT, a1 // put cycle type in position
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
br zero, 2f // go do actual read
|
|||
|
|
|||
|
//
|
|||
|
// PASS 1 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
1:
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, READ_T2_REGISTER // read current value
|
|||
|
|
|||
|
ldq a1, CfgA1(sp) // restore config cycle type
|
|||
|
ldil t0, T2_HAE02_CYCLETYPE_MASK // get cycle type field mask
|
|||
|
bic v0, t0, t0 // clear config cycle type field
|
|||
|
|
|||
|
sll a1, T2_HAE02_CYCLETYPE_SHIFT, a1// put cycle type in position
|
|||
|
bis a1, t0, a1 // merge config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
//
|
|||
|
// Perform the read from configuration space after restoring the
|
|||
|
// configuration space address.
|
|||
|
//
|
|||
|
|
|||
|
2:
|
|||
|
|
|||
|
ldq a0, CfgA0(sp) // restore config space address
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
and a0, 0x3, t3 // capture byte lane
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set
|
|||
|
bne t1, 3f // if ne, iff failed
|
|||
|
|
|||
|
zap a0, 0xf0, a0 // clear <63:32>
|
|||
|
bic a0, QVA_ENABLE, a0 // clear QVA fields
|
|||
|
sll a0, IO_BIT_SHIFT, t0 //
|
|||
|
ldiq t4, -0x4000 //
|
|||
|
sll t4, 28, t4 //
|
|||
|
bis t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
bis t0, IO_BYTE_LEN, t0 // or in the byte enables
|
|||
|
|
|||
|
ldl v0, (t0) // read the longword
|
|||
|
extbl v0, t3, v0 // return byte from requested lane
|
|||
|
// also, consume loaded value
|
|||
|
// to cause a pipeline stall
|
|||
|
mb // Sable requires MBs or the
|
|||
|
mb // machine check may happen
|
|||
|
// much later
|
|||
|
|
|||
|
3: //
|
|||
|
ldq ra, CfgRa(sp) // restore return address
|
|||
|
lda sp, CfgFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end READ_CONFIG_UCHAR
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// WRITE_CONFIG_UCHAR(
|
|||
|
// ULONG ConfigurationAddress,
|
|||
|
// UCHAR ConfigurationData,
|
|||
|
// ULONG ConfigurationCycleType
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// Read an unsigned byte from PCI configuration space.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// ConfigurationAddress(a0) - Supplies the QVA to write.
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero )
|
|||
|
|
|||
|
lda sp, -CfgFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, CfgRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END // end prologue
|
|||
|
|
|||
|
//
|
|||
|
// Depending on whether it's a pass 1 or pass 2 sable the configuration
|
|||
|
// cycle type is in different registers
|
|||
|
//
|
|||
|
ldl t0, T2VersionNumber // load version number
|
|||
|
beq t0, 1f // if 0 then pass 1 sable
|
|||
|
|
|||
|
//
|
|||
|
// PASS 2 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_3 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config data
|
|||
|
|
|||
|
//
|
|||
|
// See if this was a request on the T4 or the T2 by looking at the
|
|||
|
// Config address passed in.
|
|||
|
//
|
|||
|
|
|||
|
ldil t1, T2_HAE0_3_QVA // address of T2's HAE0_3
|
|||
|
ldil t2, T4_HAE0_3_QVA // address of T4's HAE0_3
|
|||
|
|
|||
|
ldil t0, T2_OR_T4 // Load mask to tell if T2 or T4
|
|||
|
and a0, t0, t3 // mask out other bits
|
|||
|
cmoveq t3, t1, a0 // if t3 == 0 then t1 -> a0
|
|||
|
cmovne t3, t2, a0 // if t3 != 0 then t2 -> a0
|
|||
|
|
|||
|
sll a2, T2_HAE03_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
br zero, 2f
|
|||
|
|
|||
|
//
|
|||
|
// Merge the configuration cycle type into the HAE0_3 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
1:
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config data
|
|||
|
stq a2, CfgA2(sp) // save config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, READ_T2_REGISTER // read current value
|
|||
|
|
|||
|
ldq a1, CfgA2(sp) // restore config cycle type
|
|||
|
ldil t0, T2_HAE02_CYCLETYPE_MASK // get cycle type field mask
|
|||
|
bic v0, t0, t0 // clear config cycle type field
|
|||
|
|
|||
|
sll a1, T2_HAE02_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bis a1, t0, a1 // merge config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
//
|
|||
|
// Perform the read from configuration space after restoring the
|
|||
|
// configuration space address and data.
|
|||
|
//
|
|||
|
2:
|
|||
|
|
|||
|
ldq a0, CfgA0(sp) // restore config space address
|
|||
|
ldq a1, CfgA1(sp) // restore config data
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
and a0, 0x3, t3 // capture byte lane
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE
|
|||
|
bne t1, 3f // if ne, iff failed
|
|||
|
|
|||
|
zap a0, 0xf0, a0 // clear <63:32>
|
|||
|
bic a0, QVA_ENABLE, a0 // clear QVA fields
|
|||
|
sll a0, IO_BIT_SHIFT, t0 //
|
|||
|
ldiq t4, -0x4000 //
|
|||
|
sll t4, 28, t4 //
|
|||
|
bis t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator
|
|||
|
|
|||
|
insbl a1, t3, t4 // put byte in the appropriate lane
|
|||
|
stl t4, (t0) // write the configuration byte
|
|||
|
mb // synchronize
|
|||
|
mb // synchronize
|
|||
|
|
|||
|
3:
|
|||
|
ldq ra, CfgRa(sp) // restore return address
|
|||
|
lda sp, CfgFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end WRITE_CONFIG_UCHAR
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// ULONG
|
|||
|
// READ_CONFIG_USHORT(
|
|||
|
// ULONG ConfigurationAddress,
|
|||
|
// ULONG ConfigurationCycleType
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// Read a longword from PCI configuration space.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// ConfigurationAddress(a0) - Supplies the QVA of quadword 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)
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero )
|
|||
|
|
|||
|
lda sp, -CfgFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, CfgRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END // end prologue
|
|||
|
|
|||
|
//
|
|||
|
// Depending on whether it's a pass 1 or pass 2 sable the configuration
|
|||
|
// cycle type is in different registers
|
|||
|
//
|
|||
|
ldl t0, T2VersionNumber // load version number
|
|||
|
beq t0, 1f // if 0 then pass 1 sable
|
|||
|
|
|||
|
//
|
|||
|
// Pass 2 Sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
|
|||
|
//
|
|||
|
// See if this was a request on the T4 or the T2 by looking at the
|
|||
|
// Config address passed in.
|
|||
|
//
|
|||
|
|
|||
|
ldil t1, T2_HAE0_3_QVA // address of T2's HAE0_3
|
|||
|
ldil t2, T4_HAE0_3_QVA // address of T4's HAE0_3
|
|||
|
|
|||
|
ldil t0, T2_OR_T4 // Load mask to tell if T2 or T4
|
|||
|
and a0, t0, t3 // mask out other bits
|
|||
|
cmoveq t3, t1, a0 // if t3 == 0 then t1 -> a0
|
|||
|
cmovne t3, t2, a0 // if t3 != 0 then t2 -> a0
|
|||
|
|
|||
|
sll a1, T2_HAE03_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
br zero, 2f // go do actual io
|
|||
|
|
|||
|
//
|
|||
|
// Pass 1 Sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
1:
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, READ_T2_REGISTER // read current value
|
|||
|
|
|||
|
ldq a1, CfgA1(sp) // restore configuration cycle type
|
|||
|
ldil t0, T2_HAE02_CYCLETYPE_MASK // get cycle type field mask
|
|||
|
bic v0, t0, t0 // clear config cycle type field
|
|||
|
|
|||
|
sll a1, T2_HAE02_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bis a1, t0, a1 // merge config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
//
|
|||
|
// Perform the read from configuration space after restoring the
|
|||
|
// configuration space address.
|
|||
|
//
|
|||
|
2:
|
|||
|
ldq a0, CfgA0(sp) // restore config space address
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
and a0, 0x3, t3 // capture word offset
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set
|
|||
|
bne t1, 3f // if ne, iff failed
|
|||
|
|
|||
|
zap a0, 0xf0, a0 // clear <63:32>
|
|||
|
bic a0, QVA_ENABLE, a0 // clear QVA fields
|
|||
|
sll a0, IO_BIT_SHIFT, t0 //
|
|||
|
ldiq t4, -0x4000 //
|
|||
|
sll t4, 28, t4 //
|
|||
|
bis t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
bis t0, IO_WORD_LEN, t0 // or in the byte enables
|
|||
|
|
|||
|
ldl v0, (t0) // read the longword
|
|||
|
extwl v0, t3, v0 // return word from requested lanes
|
|||
|
// also, consume loaded value
|
|||
|
// to cause a pipeline stall
|
|||
|
mb // Sable requires MBs or the
|
|||
|
mb // machine check may happen
|
|||
|
// much later
|
|||
|
|
|||
|
3:
|
|||
|
|
|||
|
ldq ra, CfgRa(sp) // restore return address
|
|||
|
lda sp, CfgFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end READ_CONFIG_USHORT
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// WRITE_CONFIG_USHORT(
|
|||
|
// ULONG ConfigurationAddress,
|
|||
|
// USHORT ConfigurationData,
|
|||
|
// ULONG ConfigurationCycleType
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// Read a longword from PCI configuration space.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// ConfigurationAddress(a0) - Supplies the QVA to write.
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero )
|
|||
|
|
|||
|
lda sp, -CfgFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, CfgRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END // end prologue
|
|||
|
|
|||
|
//
|
|||
|
// Depending on whether it's a pass 1 or pass 2 sable the configuration
|
|||
|
// cycle type is in different registers
|
|||
|
//
|
|||
|
|
|||
|
ldl t0, T2VersionNumber // load version number
|
|||
|
beq t0, 1f // if 0 then pass 1 sable
|
|||
|
|
|||
|
//
|
|||
|
// Pass 2 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config data
|
|||
|
|
|||
|
//
|
|||
|
// See if this was a request on the T4 or the T2 by looking at the
|
|||
|
// Config address passed in.
|
|||
|
//
|
|||
|
|
|||
|
ldil t1, T2_HAE0_3_QVA // address of T2's HAE0_3
|
|||
|
ldil t2, T4_HAE0_3_QVA // address of T4's HAE0_3
|
|||
|
|
|||
|
ldil t0, T2_OR_T4 // Load mask to tell if T2 or T4
|
|||
|
and a0, t0, t3 // mask out other bits
|
|||
|
cmoveq t3, t1, a0 // if t3 == 0 then t1 -> a0
|
|||
|
cmovne t3, t2, a0 // if t3 != 0 then t2 -> a0
|
|||
|
|
|||
|
sll a2, T2_HAE03_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
br zero, 2f // go do actual transfer
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pass 1 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
1:
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config data
|
|||
|
stq a2, CfgA2(sp) // save config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, READ_T2_REGISTER // read current value
|
|||
|
|
|||
|
ldq a1, CfgA2(sp) // restore configuration cycle type
|
|||
|
ldil t0, T2_HAE02_CYCLETYPE_MASK // get cycle type field mask
|
|||
|
bic v0, t0, t0 // clear config cycle type field
|
|||
|
|
|||
|
sll a1, T2_HAE02_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bis a1, t0, a1 // merge config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Perform the read from configuration space after restoring the
|
|||
|
// configuration space address and data.
|
|||
|
//
|
|||
|
2:
|
|||
|
|
|||
|
ldq a0, CfgA0(sp) // restore config space address
|
|||
|
ldq a1, CfgA1(sp) // restore config data
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
and a0, 0x3, t3 // capture word offset
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set
|
|||
|
bne t1, 3f // if ne, iff failed
|
|||
|
|
|||
|
zap a0, 0xf0, a0 // clear <63:32>
|
|||
|
bic a0, QVA_ENABLE, a0 // clear QVA fields
|
|||
|
sll a0, IO_BIT_SHIFT, t0 //
|
|||
|
ldiq t4, -0x4000 //
|
|||
|
sll t4, 28, t4 //
|
|||
|
bis t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
bis t0, IO_WORD_LEN, t0 // or in the byte enables
|
|||
|
|
|||
|
inswl a1, t3, t4 // put data to appropriate lane
|
|||
|
stl t4, (t0) // read the longword
|
|||
|
mb // synchronize
|
|||
|
mb // synchronize
|
|||
|
3:
|
|||
|
ldq ra, CfgRa(sp) // restore return address
|
|||
|
lda sp, CfgFrameLength(sp) // deallocate stack frame
|
|||
|
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 quadword 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)
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero )
|
|||
|
|
|||
|
lda sp, -CfgFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, CfgRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END // end prologue
|
|||
|
|
|||
|
//
|
|||
|
// Depending on whether it's a pass 1 or pass 2 sable the configuration
|
|||
|
// cycle type is in different registers
|
|||
|
//
|
|||
|
ldl t0, T2VersionNumber // load version number
|
|||
|
beq t0, 1f // if 0 then pass 1 sable
|
|||
|
|
|||
|
//
|
|||
|
// PASS 2 sable:
|
|||
|
// Cycle type are the only bits in HAE0_3 register
|
|||
|
//
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
|
|||
|
//
|
|||
|
// See if this was a request on the T4 or the T2 by looking at the
|
|||
|
// Config address passed in.
|
|||
|
//
|
|||
|
|
|||
|
ldil t1, T2_HAE0_3_QVA // address of T2's HAE0_3
|
|||
|
ldil t2, T4_HAE0_3_QVA // address of T4's HAE0_3
|
|||
|
|
|||
|
ldil t0, T2_OR_T4 // Load mask to tell if T2 or T4
|
|||
|
and a0, t0, t3 // mask out other bits
|
|||
|
cmoveq t3, t1, a0 // if t3 == 0 then t1 -> a0
|
|||
|
cmovne t3, t2, a0 // if t3 != 0 then t2 -> a0
|
|||
|
|
|||
|
sll a1, T2_HAE03_CYCLETYPE_SHIFT, a1 // put cycle type in position
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
br zero, 2f // go do actual read
|
|||
|
|
|||
|
//
|
|||
|
// PASS 1 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
1:
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, READ_T2_REGISTER // read current value
|
|||
|
|
|||
|
ldq a1, CfgA1(sp) // restore config cycle type
|
|||
|
ldil t0, T2_HAE02_CYCLETYPE_MASK // get cycle type field mask
|
|||
|
bic v0, t0, t0 // clear config cycle type field
|
|||
|
|
|||
|
sll a1, T2_HAE02_CYCLETYPE_SHIFT, a1// put cycle type in position
|
|||
|
bis a1, t0, a1 // merge config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
//
|
|||
|
// Perform the read from configuration space after restoring the
|
|||
|
// configuration space address.
|
|||
|
//
|
|||
|
|
|||
|
2:
|
|||
|
ldq a0, CfgA0(sp) // restore config space address
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set
|
|||
|
bne t1, 3f // if ne, iff failed
|
|||
|
|
|||
|
zap a0, 0xf0, a0 // clear <63:32>
|
|||
|
bic a0, QVA_ENABLE,a0 // clear QVA fields
|
|||
|
sll a0, IO_BIT_SHIFT, t0 //
|
|||
|
ldiq t4, -0x4000 //
|
|||
|
sll t4, 28, t4 //
|
|||
|
or t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
or t0, IO_LONG_LEN, t0 // or in the byte enables
|
|||
|
|
|||
|
ldl v0, (t0) // read the longword
|
|||
|
bis v0, zero, t1 // consume loaded value to cause
|
|||
|
// a pipeline stall
|
|||
|
mb // Sable requires MBs or the
|
|||
|
mb // machine check may happen
|
|||
|
// much later
|
|||
|
3:
|
|||
|
ldq ra, CfgRa(sp) // restore return address
|
|||
|
lda sp, CfgFrameLength(sp) // deallocate stack frame
|
|||
|
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 to write.
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero )
|
|||
|
|
|||
|
lda sp, -CfgFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, CfgRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END // end prologue
|
|||
|
|
|||
|
//
|
|||
|
// Depending on whether it's a pass 1 or pass 2 sable the configuration
|
|||
|
// cycle type is in different registers
|
|||
|
//
|
|||
|
|
|||
|
ldl t0, T2VersionNumber // load version number
|
|||
|
beq t0, 1f // if 0 then pass 1 sable
|
|||
|
|
|||
|
//
|
|||
|
// Pass 2 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config data
|
|||
|
|
|||
|
//
|
|||
|
// See if this was a request on the T4 or the T2 by looking at the
|
|||
|
// Config address passed in.
|
|||
|
//
|
|||
|
|
|||
|
ldil t1, T2_HAE0_3_QVA // address of T2's HAE0_3
|
|||
|
ldil t2, T4_HAE0_3_QVA // address of T4's HAE0_3
|
|||
|
|
|||
|
ldil t0, T2_OR_T4 // Load mask to tell if T2 or T4
|
|||
|
and a0, t0, t3 // mask out other bits
|
|||
|
cmoveq t3, t1, a0 // if t3 == 0 then t1 -> a0
|
|||
|
cmovne t3, t2, a0 // if t3 != 0 then t2 -> a0
|
|||
|
|
|||
|
sll a2, T2_HAE03_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
br zero, 2f // go do actual transfer
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pass 1 sable
|
|||
|
// Merge the configuration cycle type into the HAE0_2 register within
|
|||
|
// the T2.
|
|||
|
//
|
|||
|
1:
|
|||
|
|
|||
|
stq a0, CfgA0(sp) // save config space address
|
|||
|
stq a1, CfgA1(sp) // save config data
|
|||
|
stq a2, CfgA2(sp) // save config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, READ_T2_REGISTER // read current value
|
|||
|
|
|||
|
ldq a1, CfgA2(sp) // restore configuration cycle type
|
|||
|
ldil t0, T2_HAE02_CYCLETYPE_MASK // get cycle type field mask
|
|||
|
bic v0, t0, t0 // clear config cycle type field
|
|||
|
|
|||
|
sll a1, T2_HAE02_CYCLETYPE_SHIFT, a1 // put cycle type into position
|
|||
|
bis a1, t0, a1 // merge config cycle type
|
|||
|
|
|||
|
ldil a0, T2_HAE0_2_QVA // address of HAE0_2
|
|||
|
bsr ra, WRITE_T2_REGISTER // write updated HAE
|
|||
|
|
|||
|
//
|
|||
|
// Perform the read from configuration space after restoring the
|
|||
|
// configuration space address and data.
|
|||
|
//
|
|||
|
2:
|
|||
|
|
|||
|
ldq a0, CfgA0(sp) // restore config space address
|
|||
|
ldq a1, CfgA1(sp) // restore config data
|
|||
|
|
|||
|
and a0, QVA_SELECTORS, t1 // get qva selector bits
|
|||
|
xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set
|
|||
|
bne t1, 3f // if ne, iff failed
|
|||
|
|
|||
|
zap a0, 0xf0, a0 // clear <63:32>
|
|||
|
bic a0, QVA_ENABLE, a0 // clear QVA fields
|
|||
|
sll a0, IO_BIT_SHIFT, t0 //
|
|||
|
ldiq t4, -0x4000 //
|
|||
|
sll t4, 28, t4 //
|
|||
|
bis t0, t4, t0 // superpage mode
|
|||
|
|
|||
|
bis t0, IO_LONG_LEN, t0 // or in the byte enables
|
|||
|
|
|||
|
stl a1, (t0) // write the longword
|
|||
|
mb // synchronize
|
|||
|
mb // synchronize
|
|||
|
|
|||
|
3: //
|
|||
|
ldq ra, CfgRa(sp) // restore return address
|
|||
|
lda sp, CfgFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end WRITE_CONFIG_ULONG
|