mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 19:12:58 -04:00
361 lines
11 KiB
C
361 lines
11 KiB
C
/* $Id: stp222x-stc.c,v 1.4 2010/06/05 18:59:29 fredette Exp $ */
|
|
|
|
/* ic/stp222x-stc.c - emulation of the STC of the UPA to SBus
|
|
interface controller (STP2220) and the UPA to PCI interface
|
|
controller (STP2222): */
|
|
|
|
/*
|
|
* Copyright (c) 2009 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: stp222x-stc.c,v 1.4 2010/06/05 18:59:29 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include "stp222x-impl.h"
|
|
|
|
/* macros: */
|
|
|
|
/* streaming buffer register offsets: */
|
|
#define TME_STP222X_STC_REGGROUP_INDEX_CR TME_STP222X_REGGROUP_INDEX(0x00)
|
|
#define TME_STP222X_STC_REGGROUP_INDEX_PGFLUSH TME_STP222X_REGGROUP_INDEX(0x08)
|
|
#define TME_STP222X_STC_REGGROUP_INDEX_FLUSHSYNC TME_STP222X_REGGROUP_INDEX(0x10)
|
|
|
|
/* an STC control register: */
|
|
#define TME_STP222X_STC_CR_LPTR ((2 << 7) - (1 << 4))
|
|
#define TME_STP222X_STC_CR_LE (1 << 3)
|
|
#define TME_STP222X_STC_CR_RR_DIS (1 << 2)
|
|
#define TME_STP222X_STC_CR_DE (1 << 1)
|
|
#define TME_STP222X_STC_CR_SB_EN (1 << 0)
|
|
|
|
/* the size of the stp222x flush blocks: */
|
|
#define TME_STP2220_STC_FLUSHSYNC_SIZE ((tme_uint64_t) 4)
|
|
#define TME_STP2222_STC_FLUSHSYNC_SIZE ((tme_uint64_t) 64)
|
|
|
|
/* the number of entries in each streaming buffer: */
|
|
#define TME_STP222X_STC_ENTRY_COUNT (16)
|
|
|
|
/* this flushes a streaming cache: */
|
|
int
|
|
tme_stp222x_stc_flush(struct tme_stp222x *stp222x)
|
|
{
|
|
struct tme_stp222x_stc *stc;
|
|
tme_uint64_t address;
|
|
struct tme_bus_tlb *tlb;
|
|
struct tme_bus_connection *slave_conn_bus;
|
|
struct tme_bus_connection *slave_conn_bus_other;
|
|
#if TME_STP22XX_BUS_TRANSITION
|
|
int rc;
|
|
#endif /* TME_STP22XX_BUS_TRANSITION */
|
|
tme_shared tme_uint8_t *memory;
|
|
|
|
stc = &stp222x->tme_stp222x_stcs[0];
|
|
if (!stc->tme_stp222x_stc_pgflush) {
|
|
stc = &stp222x->tme_stp222x_stcs[1];
|
|
if (!stc->tme_stp222x_stc_pgflush) {
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
/* get the flushsync address: */
|
|
address
|
|
= (stc->tme_stp222x_stc_flushsync
|
|
& (TME_STP222X_IS_2220(stp222x)
|
|
? ((((tme_uint64_t) 2) << 40)
|
|
- TME_STP2220_STC_FLUSHSYNC_SIZE)
|
|
: ((((tme_uint64_t) 2) << 40)
|
|
- TME_STP2222_STC_FLUSHSYNC_SIZE)));
|
|
|
|
/* busy the flushsync TLB: */
|
|
tlb = &stc->tme_stp222x_stc_flushsync_tlb;
|
|
tme_bus_tlb_busy(tlb);
|
|
|
|
/* if the flushsync TLB is invalid or doesn't apply: */
|
|
if (tme_bus_tlb_is_invalid(tlb)
|
|
|| address < (tme_bus_addr64_t) tlb->tme_bus_tlb_addr_first
|
|
|| address > (tme_bus_addr64_t) tlb->tme_bus_tlb_addr_last) {
|
|
|
|
/* unbusy the flushsync TLB for filling: */
|
|
tme_bus_tlb_unbusy_fill(tlb);
|
|
|
|
/* busy the UPA connection: */
|
|
slave_conn_bus = tme_stp222x_slave_busy_bus(stp222x, TME_STP222X_CONN_UPA);
|
|
|
|
/* leave: */
|
|
tme_stp222x_leave(stp222x);
|
|
|
|
/* fill the TLB entry: */
|
|
slave_conn_bus_other = (struct tme_bus_connection *) slave_conn_bus->tme_bus_connection.tme_connection_other;
|
|
#if TME_STP22XX_BUS_TRANSITION
|
|
rc =
|
|
#endif /* TME_STP22XX_BUS_TRANSITION */
|
|
(*slave_conn_bus_other->tme_bus_tlb_fill)
|
|
(slave_conn_bus_other,
|
|
tlb,
|
|
address,
|
|
TME_BUS_CYCLE_WRITE);
|
|
#if TME_STP22XX_BUS_TRANSITION
|
|
assert (rc == TME_OK);
|
|
#endif /* TME_STP22XX_BUS_TRANSITION */
|
|
|
|
/* reenter: */
|
|
stp222x = tme_stp222x_enter_bus(slave_conn_bus);
|
|
|
|
/* unbusy the UPA connection: */
|
|
tme_stp222x_slave_unbusy(stp222x);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/* the flushsync TLB must allow fast writing of the entire block: */
|
|
memory = tlb->tme_bus_tlb_emulator_off_write;
|
|
assert (memory != TME_EMULATOR_OFF_UNDEF
|
|
&& ((address
|
|
+ (TME_STP222X_IS_2220(stp222x)
|
|
? TME_STP2220_STC_FLUSHSYNC_SIZE
|
|
: TME_STP2222_STC_FLUSHSYNC_SIZE)
|
|
- 1)
|
|
<= (tme_bus_addr64_t) tlb->tme_bus_tlb_addr_last));
|
|
|
|
/* write the flush doublewords: */
|
|
memory += address;
|
|
|
|
/* if this is an stp2220: */
|
|
if (TME_STP222X_IS_2220(stp222x)) {
|
|
|
|
/* the stp2220 only writes four bytes: */
|
|
tme_memory_atomic_write32(((tme_shared tme_uint32_t *) memory) + 0,
|
|
tme_htobe_u32(1),
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint32_t));
|
|
}
|
|
|
|
/* otherwise, this is an stp2222: */
|
|
else {
|
|
|
|
/* the stp2222 writes 64 bytes: */
|
|
|
|
/* XXX FIXME - all of these doublewords are actually written as
|
|
one atomic transaction. the best we can do is either 64- or
|
|
128-bit atomic writes: */
|
|
#ifdef tme_memory_atomic_write128
|
|
tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 0,
|
|
tme_htobe_u128(((tme_uint128_t) 1) << (128 - 32)),
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint128_t));
|
|
tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 1,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint128_t));
|
|
tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 2,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint128_t));
|
|
tme_memory_atomic_write128(((tme_shared tme_uint128_t *) memory) + 3,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint128_t));
|
|
#else /* !tme_memory_atomic_write128 */
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 0,
|
|
tme_htobe_u64(((tme_uint64_t) 1) << (64 - 32)),
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 1,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 2,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 3,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 4,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 5,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 6,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
tme_memory_atomic_write64(((tme_shared tme_uint64_t *) memory) + 7,
|
|
0,
|
|
tlb->tme_bus_tlb_rwlock,
|
|
sizeof(tme_uint64_t));
|
|
#endif /* !tme_memory_atomic_write128 */
|
|
}
|
|
|
|
/* unbusy the flushsync TLB: */
|
|
tme_bus_tlb_unbusy(tlb);
|
|
|
|
/* the flush has been done: */
|
|
stc->tme_stp222x_stc_pgflush = FALSE;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/* the STC register handler: */
|
|
void
|
|
tme_stp222x_stc_regs(struct tme_stp222x *stp222x,
|
|
unsigned long stc_i,
|
|
struct tme_stp222x_reg *reg)
|
|
{
|
|
struct tme_stp222x_stc *stc;
|
|
tme_uint32_t reggroup_index;
|
|
const char *name;
|
|
|
|
/* get the streaming cache: */
|
|
stc = &stp222x->tme_stp222x_stcs[stc_i];
|
|
|
|
/* get the register: */
|
|
reggroup_index = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
|
|
|
|
/* if this is a write: */
|
|
if (reg->tme_stp222x_reg_write) {
|
|
|
|
/* dispatch on the register: */
|
|
switch (reggroup_index) {
|
|
|
|
case TME_STP222X_STC_REGGROUP_INDEX_CR:
|
|
stc->tme_stp222x_stc_cr
|
|
= (reg->tme_stp222x_reg_value
|
|
& (TME_STP222X_STC_CR_LPTR
|
|
| TME_STP222X_STC_CR_LE
|
|
| TME_STP222X_STC_CR_RR_DIS
|
|
| TME_STP222X_STC_CR_DE
|
|
| TME_STP222X_STC_CR_SB_EN));
|
|
name = "CR";
|
|
break;
|
|
|
|
case TME_STP222X_STC_REGGROUP_INDEX_PGFLUSH:
|
|
name = "PGFLUSH";
|
|
break;
|
|
|
|
case TME_STP222X_STC_REGGROUP_INDEX_FLUSHSYNC:
|
|
stc->tme_stp222x_stc_flushsync = reg->tme_stp222x_reg_value;
|
|
stc->tme_stp222x_stc_pgflush = TRUE;
|
|
name = "FLUSHSYNC";
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* otherwise, this is a read: */
|
|
else {
|
|
|
|
/* dispatch on the register: */
|
|
switch (reggroup_index) {
|
|
case TME_STP222X_STC_REGGROUP_INDEX_CR:
|
|
reg->tme_stp222x_reg_value = stc->tme_stp222x_stc_cr;
|
|
name = "CR";
|
|
break;
|
|
case TME_STP222X_STC_REGGROUP_INDEX_PGFLUSH:
|
|
case TME_STP222X_STC_REGGROUP_INDEX_FLUSHSYNC:
|
|
reg->tme_stp222x_reg_completed = TRUE;
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
tme_log(TME_STP222X_LOG_HANDLE(stp222x), 2000, TME_OK,
|
|
(TME_STP222X_LOG_HANDLE(stp222x),
|
|
_("STC%lu %s %s 0x%" TME_PRIx64),
|
|
stc_i,
|
|
name,
|
|
(reg->tme_stp222x_reg_write
|
|
? "<-"
|
|
: "->"),
|
|
reg->tme_stp222x_reg_value));
|
|
|
|
/* this register access has been completed: */
|
|
reg->tme_stp222x_reg_completed = TRUE;
|
|
}
|
|
|
|
/* the STC diagnostic register handler: */
|
|
void
|
|
tme_stp222x_stc_regs_diag(struct tme_stp222x *stp222x,
|
|
unsigned long stc_i,
|
|
struct tme_stp222x_reg *reg)
|
|
{
|
|
struct tme_stp222x_stc *stc;
|
|
tme_uint32_t reggroup_0_3;
|
|
tme_uint32_t reggroup_index;
|
|
|
|
/* get the streaming cache: */
|
|
stc = &stp222x->tme_stp222x_stcs[stc_i];
|
|
|
|
/* get the register: */
|
|
reggroup_0_3 = TME_STP222X_REGGROUP_WHICH(reg->tme_stp222x_reg_address) & 0xf;
|
|
reggroup_index = TME_STP222X_REGGROUP_INDEX(reg->tme_stp222x_reg_address);
|
|
|
|
/* if this is a write: */
|
|
if (reg->tme_stp222x_reg_write) {
|
|
|
|
abort();
|
|
}
|
|
|
|
/* otherwise, this is a read: */
|
|
else {
|
|
|
|
switch (reggroup_0_3) {
|
|
case 0x8: /* STP2220 0x58, STP2222 0xb4 or 0xc4 */
|
|
if (__tme_predict_false(reggroup_index >= TME_STP222X_STC_ENTRY_COUNT)) {
|
|
abort();
|
|
}
|
|
reg->tme_stp222x_reg_value = 0;
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/* this register access has been completed: */
|
|
reg->tme_stp222x_reg_completed = TRUE;
|
|
}
|
|
|
|
/* this initializes a streaming cache: */
|
|
void
|
|
tme_stp222x_stc_init(struct tme_stp222x_stc *stc)
|
|
{
|
|
|
|
/* initialize the flushsync TLB: */
|
|
tme_token_init(&stc->tme_stp222x_stc_flushsync_tlb_token);
|
|
stc->tme_stp222x_stc_flushsync_tlb.tme_bus_tlb_token = &stc->tme_stp222x_stc_flushsync_tlb_token;
|
|
}
|