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