Annotation of tme/machine/sun4/sun44c-mmu.c, revision 1.1.1.1

1.1       root        1: /* $Id: sun44c-mmu.c,v 1.3 2007/09/06 23:25:20 fredette Exp $ */
                      2: 
                      3: /* machine/sun4/sun44c-mmu.c - implementation of Sun 4/4c MMU emulation: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2005, 2006 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
                     37: _TME_RCSID("$Id: sun44c-mmu.c,v 1.3 2007/09/06 23:25:20 fredette Exp $");
                     38: 
                     39: /* includes: */
                     40: #include "sun4-impl.h"
                     41: 
                     42: /* macros: */
                     43: 
                     44: /* real sun4/4c PTE page types: */
                     45: #define TME_SUN44C_PGTYPE_OBMEM                (0)
                     46: #define TME_SUN44C_PGTYPE_OBIO         (1)
                     47: #define TME_SUN4_PGTYPE_VME_D16                (2)
                     48: #define TME_SUN4_PGTYPE_VME_D32                (3)
                     49: 
                     50: /* real sun4 bus error register bits: */
                     51: #define TME_SUN4_BUSERR_WATCHDOG       TME_BIT(0)      /* watchdog or user reset */
                     52: #define TME_SUN4_BUSERR_SIZE           TME_BIT(1)      /* size error */
                     53:                                        /* bit 2 unused */
                     54:                                        /* bit 3 unused */
                     55: #define TME_SUN4_BUSERR_VMEBUSERR      TME_BIT(4)      /* VME bus error */
                     56: #define TME_SUN4_BUSERR_TIMEOUT                TME_BIT(5)      /* timeout error */
                     57: #define TME_SUN4_BUSERR_PROTERR                TME_BIT(6)      /* MMU protection error */
                     58: #define TME_SUN4_BUSERR_INVALID                TME_BIT(7)      /* MMU page invalid error */
                     59: 
                     60: /* real sun4c synchronous error register bits: */
                     61: #define TME_SUN4C_SYNC_ERR_WATCHDOG    TME_BIT(0)      /* watchdog or user reset */
                     62: #define TME_SUN4C_SYNC_ERR_SIZE                TME_BIT(1)      /* size error */
                     63:                                        /* bit 2 unused */
                     64: #define TME_SUN4C_SYNC_ERR_MEMORY      TME_BIT(3)      /* memory error */
                     65: #define TME_SUN4C_SYNC_ERR_SBUS                TME_BIT(4)      /* SBus error */
                     66: #define TME_SUN4C_SYNC_ERR_TIMEOUT     TME_BIT(5)      /* timeout error */
                     67: #define TME_SUN4C_SYNC_ERR_PROTERR     TME_BIT(6)      /* MMU protection error */
                     68: #define TME_SUN4C_SYNC_ERR_INVALID     TME_BIT(7)      /* MMU page invalid error */
                     69: #define TME_SUN4C_SYNC_ERR_WRITE       TME_BIT(15)     /* error happened on write */
                     70: 
                     71: /* real sun4c asynchronous error register bits: */
                     72: #define TME_SUN4C_ASYNC_ERR_MULTIPLE   TME_BIT(0)      /* multiple errors detected */
                     73: #define TME_SUN4C_ASYNC_ERR_SBUS       TME_BIT(1)      /* SBus error */
                     74:                                        /* bit 2 unused */
                     75: #define TME_SUN4C_ASYNC_ERR_MEMORY     TME_BIT(3)      /* memory error */
                     76: #define TME_SUN4C_ASYNC_ERR_DVMA       TME_BIT(4)      /* DVMA error */
                     77: #define TME_SUN4C_ASYNC_ERR_TIMEOUT    TME_BIT(5)      /* timeout error */
                     78: #define TME_SUN4C_ASYNC_ERR_PROTERR    TME_BIT(6)      /* MMU protection error */
                     79: #define TME_SUN4C_ASYNC_ERR_INVALID    TME_BIT(7)      /* MMU page invalid error (not 4/60?) */
                     80: #define TME_SUN4C_ASYNC_ERR_SIZE_MASK  (0x0300)        /* log2 of access size */
                     81: 
                     82: /* common bus error bits: */
                     83: #define TME_SUN44C_BUSERR_COMMON_INVALID       TME_BIT(0)
                     84: #define TME_SUN44C_BUSERR_COMMON_PROTERR       TME_BIT(1)
                     85: #define TME_SUN44C_BUSERR_COMMON_TIMEOUT       TME_BIT(2)
                     86: #define TME_SUN44C_BUSERR_COMMON_MEMORY                TME_BIT(3)
                     87: #define TME_SUN4C_BUSERR_COMMON_SBUS           TME_BIT(4)
                     88: #define TME_SUN4_BUSERR_COMMON_VMEBUS          TME_BIT(5)
                     89: #define TME_SUN4C_BUSERR_COMMON_PGTYPE         TME_BIT(6)
                     90: 
                     91: /* this logs a bus error: */
                     92: static inline void
                     93: _tme_sun44c_buserr_log(struct tme_sun4 *sun4,
                     94:                       tme_uint32_t vaddr,
                     95:                       const struct tme_bus_cycle *cycle,
                     96:                       unsigned int async,
                     97:                       tme_uint32_t common_err,
                     98:                       tme_uint32_t spec_err)
                     99: {
                    100:   struct tme_sun_mmu_pte pte;
                    101:   tme_uint32_t pte_sun44c;
                    102:   tme_uint32_t paddr;
                    103:   const char *bus_name;
                    104:   const char *err_type;
                    105:   const char *err_name;
                    106:   int rc;
                    107: 
                    108:   /* get the PTE involved.  NB we wrap this call so this entire
                    109:      function will get optimized away under TME_NO_LOG: */
                    110:   /* XXX FIXME - this uses the system context register, which may not
                    111:      be right for DVMA? */
                    112: #ifndef TME_NO_LOG
                    113:   rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, 
                    114:                           sun4->tme_sun44c_context,
                    115:                           vaddr,
                    116:                           &pte);
                    117: #else  /* TME_NO_LOG */
                    118:   rc = TME_OK;
                    119:   pte.tme_sun_mmu_pte_raw = 0;
                    120: #endif /* TME_NO_LOG */
                    121:   assert (rc == TME_OK);
                    122:   pte_sun44c = pte.tme_sun_mmu_pte_raw;
                    123: 
                    124:   /* get the physical address: */
                    125:   if (TME_SUN4_IS_SUN4C(sun4)) {
                    126:     paddr = (((pte_sun44c & TME_SUN4C_PTE_PGFRAME) * TME_SUN4C_PAGE_SIZE)
                    127:             | (vaddr % TME_SUN4C_PAGE_SIZE));
                    128:   }
                    129:   else {
                    130:     paddr = (((pte_sun44c & TME_SUN4_PTE_PGFRAME) * TME_SUN4_PAGE_SIZE)
                    131:             | (vaddr % TME_SUN4_PAGE_SIZE));
                    132:   }
                    133: 
                    134:   /* this silences gcc -Wuninitialized: */
                    135:   bus_name = NULL;
                    136: 
                    137:   /* get the bus name: */
                    138:   switch (TME_FIELD_MASK_EXTRACTU(pte_sun44c, TME_SUN44C_PTE_PGTYPE)) {
                    139:   case TME_SUN44C_PGTYPE_OBMEM:
                    140:     bus_name = "obmem";
                    141:     break;
                    142:   case TME_SUN44C_PGTYPE_OBIO:
                    143:     if (TME_SUN4_IS_SUN4C(sun4)) {
                    144:       paddr |= 0xf0000000;
                    145:       bus_name = (paddr >= TME_SUN4C_OBIO_SBUS
                    146:                  ? "SBus"
                    147:                  : "mainbus");
                    148:     }
                    149:     else {
                    150:       bus_name = "obio";
                    151:     }
                    152:     break;
                    153:   case TME_SUN4_PGTYPE_VME_D16:
                    154:     bus_name = (TME_SUN4_IS_SUN4C(sun4) ? "TYPE_2" : "VME_D16");
                    155:     break;
                    156:   case TME_SUN4_PGTYPE_VME_D32:
                    157:     bus_name = (TME_SUN4_IS_SUN4C(sun4) ? "TYPE_3" : "VME_D32");
                    158:     break;
                    159:   }
                    160: 
                    161:   /* get the error type and name: */
                    162:   err_type = (TME_SUN4_IS_SUN4C(sun4)
                    163:              ? (async
                    164:                 ? "async "
                    165:                 : "sync ")
                    166:              : "");
                    167:   err_name = "other";
                    168:   if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) err_name = "timeout";
                    169:   if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) err_name = "memory";
                    170:   if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) err_name = "page invalid";
                    171:   if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) err_name = "page protection";
                    172: 
                    173:   /* log this bus error: */
                    174:   tme_log(TME_SUN4_LOG_HANDLE(sun4), 500, TME_OK,
                    175:          (TME_SUN4_LOG_HANDLE(sun4), 
                    176:           _("%s%s buserr, virtual 0x%08x, %s 0x%08x, %serr = 0x%02x"),
                    177:           err_type,
                    178:           err_name,
                    179:           vaddr,
                    180:           bus_name,
                    181:           paddr,
                    182:           err_type,
                    183:           spec_err));
                    184: }
                    185: 
                    186: /* our sun4/4c common bus error handler: */
                    187: static int
                    188: _tme_sun44c_buserr_common(const void *_conn_bus_init,
                    189:                          const struct tme_bus_tlb *tlb,
                    190:                          const struct tme_bus_cycle *cycle,
                    191:                          unsigned int common_err)
                    192: {
                    193:   const struct tme_bus_connection *conn_bus_init;
                    194:   struct tme_sun4 *sun4;
                    195:   tme_uint32_t vaddr;
                    196:   unsigned int log2_size;
                    197:   tme_uint32_t async_err;
                    198:   tme_uint32_t sync_err;
                    199: 
                    200:   /* recover the initiator's bus connection and sun4: */
                    201:   conn_bus_init = (struct tme_bus_connection *) _conn_bus_init;
                    202:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    203: 
                    204:   /* get the virtual address.  certain errors, like memory errors,
                    205:      still allow the cycle to complete, and for those we have to
                    206:      subtract the cycle size from the post-cycle address: */
                    207:   vaddr = cycle->tme_bus_cycle_address;
                    208:   if (tlb != NULL) {
                    209:     vaddr -= tlb->tme_bus_tlb_addr_offset;
                    210:   }
                    211:   if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) {
                    212:     vaddr -= cycle->tme_bus_cycle_size;
                    213:   }
                    214: 
                    215:   /* calculate the log2 of the cycle size: */
                    216:   for (log2_size = 0;
                    217:        (1 << log2_size) < cycle->tme_bus_cycle_size;
                    218:        log2_size++);
                    219: 
                    220:   /* if this is a sun4c: */
                    221:   if (TME_SUN4_IS_SUN4C(sun4)) {
                    222: 
                    223:     /* if this is any cycle not initiated by the CPU, or if this is a
                    224:        CPU write cycle that was not faulted by the MMU: */
                    225:     if (conn_bus_init->tme_bus_connection.tme_connection_type != TME_CONNECTION_BUS_SPARC
                    226:        || (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
                    227:            && !(common_err
                    228:                 & (TME_SUN44C_BUSERR_COMMON_INVALID
                    229:                    | TME_SUN44C_BUSERR_COMMON_PROTERR
                    230:                    | TME_SUN4C_BUSERR_COMMON_PGTYPE)))) {
                    231: 
                    232:       /* this is an asynchronous error: */
                    233:       async_err = 0;
                    234:       if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) async_err |= TME_SUN4C_ASYNC_ERR_TIMEOUT;
                    235:       if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) async_err |= TME_SUN4C_ASYNC_ERR_MEMORY;
                    236:       if (common_err & TME_SUN4C_BUSERR_COMMON_SBUS) async_err |= TME_SUN4C_ASYNC_ERR_SBUS;
                    237:       if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) async_err |= TME_SUN4C_ASYNC_ERR_INVALID;
                    238:       if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) async_err |= TME_SUN4C_ASYNC_ERR_PROTERR;
                    239:       if (conn_bus_init->tme_bus_connection.tme_connection_type != TME_CONNECTION_BUS_SPARC) {
                    240:        async_err |= TME_SUN4C_ASYNC_ERR_DVMA;
                    241:       }
                    242: 
                    243:       /* if this is the first asynchronous error: */
                    244:       if (sun4->tme_sun4c_async_err == 0) {
                    245: 
                    246:        /* set the asynchronous virtual address register: */
                    247:        sun4->tme_sun4c_async_vaddr = vaddr;
                    248: 
                    249:        /* add the cycle size to the asynchronous error register value: */
                    250:        TME_FIELD_MASK_DEPOSITU(async_err, TME_SUN4C_ASYNC_ERR_SIZE_MASK, log2_size);
                    251:       }
                    252: 
                    253:       /* otherwise, this is not the first asynchronous error: */
                    254:       else {
                    255: 
                    256:        /* there are multiple asynchronous errors: */
                    257:        async_err |= TME_SUN4C_ASYNC_ERR_MULTIPLE;
                    258:       }
                    259: 
                    260:       /* update the asynchronous error register: */
                    261:       sun4->tme_sun4c_async_err |= async_err;
                    262: 
                    263:       /* send an NMI to the CPU: */
                    264:       sun4->tme_sun4_int_signals[TME_SPARC_IPL_NMI / 8] |= TME_BIT(TME_SPARC_IPL_NMI % 8);
                    265:       _tme_sun4_ipl_check(sun4);
                    266: 
                    267:       /* log this bus error: */
                    268:       _tme_sun44c_buserr_log(sun4,
                    269:                             vaddr,
                    270:                             cycle,
                    271:                             TRUE,
                    272:                             common_err,
                    273:                             async_err);
                    274: 
                    275:       /* asynchronous errors aren't reported to the CPU as faults, but
                    276:         they are reported as faults to another bus master (for whom
                    277:         the error is really synchronous): */
                    278:       return (conn_bus_init->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_SPARC
                    279:              ? TME_OK
                    280:              : (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY)
                    281:              ? EIO
                    282:              : (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT)
                    283:              ? ENOENT
                    284:              : EFAULT);
                    285:     }
                    286: 
                    287:     /* this is a synchronous error.  NB that the cycle is only
                    288:        considered a write if it's only a write cycle; read cycles and
                    289:        all parts of read/modify/write cycles are considered reads: */
                    290:     sync_err = 0;
                    291:     if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) sync_err |= TME_SUN4C_SYNC_ERR_TIMEOUT;
                    292:     if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) sync_err |= TME_SUN4C_SYNC_ERR_MEMORY;
                    293:     if (common_err & TME_SUN4C_BUSERR_COMMON_SBUS) sync_err |= TME_SUN4C_SYNC_ERR_SBUS;
                    294:     if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) sync_err |= TME_SUN4C_SYNC_ERR_INVALID;
                    295:     if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) sync_err |= TME_SUN4C_SYNC_ERR_PROTERR;
                    296:     if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
                    297:       sync_err |= TME_SUN4C_SYNC_ERR_WRITE;
                    298:     }
                    299:     
                    300:     /* set the synchronous virtual address register: */
                    301:     sun4->tme_sun4c_sync_vaddr = vaddr;
                    302: 
                    303:     /* update the synchronous error register: */
                    304:     sun4->tme_sun4c_sync_err
                    305:       = ((sun4->tme_sun4c_sync_err
                    306:          & ~TME_SUN4C_SYNC_ERR_WRITE)
                    307:         | sync_err);
                    308:     sync_err = sun4->tme_sun4c_sync_err;
                    309:   }
                    310: 
                    311:   /* otherwise, this is a sun4: */
                    312:   else {
                    313: 
                    314:     /* this is a synchronous bus error: */
                    315:     sync_err = 0;
                    316:     if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) sync_err |= TME_SUN4_BUSERR_TIMEOUT;
                    317:     if (common_err & TME_SUN4_BUSERR_COMMON_VMEBUS) sync_err |= TME_SUN4_BUSERR_VMEBUSERR;
                    318:     if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) sync_err |= TME_SUN4_BUSERR_INVALID;
                    319:     if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) sync_err |= TME_SUN4_BUSERR_PROTERR;
                    320: 
                    321:     /* set the bus error register: */
                    322:     sun4->tme_sun4_buserr = sync_err;
                    323:   }
                    324: 
                    325:   /* log this bus error: */
                    326:   _tme_sun44c_buserr_log(sun4,
                    327:                         vaddr,
                    328:                         cycle,
                    329:                         FALSE,
                    330:                         common_err,
                    331:                         sync_err);
                    332: 
                    333:   /* return a bus fault code: */
                    334:   return ((common_err & TME_SUN44C_BUSERR_COMMON_MEMORY)
                    335:          ? EIO
                    336:          : (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT)
                    337:          ? ENOENT
                    338:          : EFAULT);
                    339: }
                    340: 
                    341: /* this maps a bus fault code to a common bus error: */
                    342: static inline unsigned int
                    343: _tme_sun44c_bus_fault_error(int rc)
                    344: {
                    345:   switch (rc) {
                    346:   default: abort();
                    347:   case ENOENT: return (TME_SUN44C_BUSERR_COMMON_TIMEOUT);
                    348:   case EIO: return (TME_SUN44C_BUSERR_COMMON_MEMORY);
                    349:   }
                    350: }
                    351: 
                    352: /* our page-invalid cycle handler: */
                    353: static int
                    354: _tme_sun44c_mmu_invalid(void *_conn_bus_init, struct tme_bus_cycle *cycle)
                    355: {
                    356: 
                    357:   /* call the common bus error handler: */
                    358:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    359:                                    NULL,
                    360:                                    cycle,
                    361:                                    TME_SUN44C_BUSERR_COMMON_INVALID));
                    362: }
                    363: 
                    364: /* our protection error cycle handler: */
                    365: int
                    366: _tme_sun44c_mmu_proterr(void *_conn_bus_init, struct tme_bus_cycle *cycle)
                    367: {
                    368: 
                    369:   /* call the common bus error handler: */
                    370:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    371:                                    NULL,
                    372:                                    cycle,
                    373:                                    TME_SUN44C_BUSERR_COMMON_PROTERR));
                    374: }
                    375: 
                    376: /* the sun4/4c obio and obmem bus fault handler: */
                    377: int
                    378: _tme_sun44c_ob_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    379: {
                    380: 
                    381:   /* call the common bus error handler: */
                    382:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    383:                                    tlb,
                    384:                                    cycle,
                    385:                                    _tme_sun44c_bus_fault_error(rc)));
                    386: }
                    387: 
                    388: /* the sun4c obmem bus fault handler: */
                    389: static int
                    390: _tme_sun4c_obmem_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    391: {
                    392:   tme_uint8_t *buffer;
                    393:   unsigned int bytes;
                    394: 
                    395:   /* sun4c obmem (at least on an SS2) apparently doesn't give timeout
                    396:      errors, because while an SS2 PROM's memory probe code seems to
                    397:      tolerate faults, it never clears the synchronous error register
                    398:      when they happen, which causes problems in later self tests that
                    399:      check that register: */
                    400:   if (rc == ENOENT) {
                    401: 
                    402:     /* nonexistent obmem discards writes and reads as all-bits-one: */
                    403:     if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
                    404:       for (bytes = cycle->tme_bus_cycle_size, buffer = cycle->tme_bus_cycle_buffer;
                    405:           bytes > 0;
                    406:           bytes--, buffer += cycle->tme_bus_cycle_buffer_increment) {
                    407:        *buffer = 0xff;
                    408:       }
                    409:     }
                    410: 
                    411:     return (TME_OK);
                    412:   }
                    413: 
                    414:   /* call the common bus error handler: */
                    415:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    416:                                    tlb,
                    417:                                    cycle,
                    418:                                    _tme_sun44c_bus_fault_error(rc)));
                    419: }
                    420: 
                    421: /* the sun4c sbus fault handler: */
                    422: static int
                    423: _tme_sun4c_sbus_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    424: {
                    425: 
                    426:   /* call the common bus error handler: */
                    427:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    428:                                    tlb,
                    429:                                    cycle,
                    430:                                    (TME_SUN4C_BUSERR_COMMON_SBUS
                    431:                                     | _tme_sun44c_bus_fault_error(rc))));
                    432: }
                    433: 
                    434: /* the sun4c page type (type-2 and type-3) fault handler: */
                    435: static int
                    436: _tme_sun4c_pgtype_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    437: {
                    438: 
                    439:   /* call the common bus error handler: */
                    440:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    441:                                    tlb,
                    442:                                    cycle,
                    443:                                    (TME_SUN4C_BUSERR_COMMON_PGTYPE
                    444:                                     | _tme_sun44c_bus_fault_error(rc))));
                    445: }
                    446: 
                    447: /* the sun4 VMEbus fault handler: */
                    448: static int
                    449: _tme_sun4_vmebus_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    450: {
                    451: 
                    452:   /* call the common bus error handler: */
                    453:   return (_tme_sun44c_buserr_common(_conn_bus_init,
                    454:                                    tlb,
                    455:                                    cycle,
                    456:                                    (TME_SUN4_BUSERR_COMMON_VMEBUS
                    457:                                     | _tme_sun44c_bus_fault_error(rc))));
                    458: }
                    459: 
                    460: /* our bus timeout cycle handler: */
                    461: static int
                    462: _tme_sun44c_bus_timeout(void *_sun4, struct tme_bus_cycle *cycle)
                    463: {
                    464:   return (ENOENT);
                    465: }
                    466: 
                    467: /* this fills memory TLBs from the MMU: */
                    468: int
                    469: _tme_sun44c_tlb_fill_mmu(const struct tme_bus_connection *conn_bus_init,
                    470:                         struct tme_bus_tlb *tlb,
                    471:                         tme_uint32_t *_asi_mask,
                    472:                         tme_uint32_t address,
                    473:                         unsigned int cycles)
                    474: {
                    475:   struct tme_sun4 *sun4;
                    476:   tme_uint32_t asi_mask;
                    477:   tme_uint32_t asi_mask_si;
                    478:   unsigned short access;
                    479:   struct tme_bus_tlb tlb_bus;
                    480:   unsigned int tlb_i;
                    481:   unsigned short tlb_flags;
                    482: 
                    483:   /* recover our sun4: */
                    484:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    485: 
                    486:   /* recover the ASI mask: */
                    487:   asi_mask = *_asi_mask;
                    488: 
                    489:   /* this ASI mask must be a single ASI, for user or supervisor
                    490:      instruction or data: */
                    491:   assert (asi_mask == TME_SPARC32_ASI_MASK_UD
                    492:          || asi_mask == TME_SPARC32_ASI_MASK_UI
                    493:          || asi_mask == TME_SPARC32_ASI_MASK_SD
                    494:          || asi_mask == TME_SPARC32_ASI_MASK_SI);
                    495: 
                    496:   /* assume that if this TLB entry ends up good for the supervisor,
                    497:      it's good for the supervisor instruction ASI mask: */
                    498:   asi_mask_si = TME_SPARC32_ASI_MASK_SI;
                    499: 
                    500:   /* if we're in the boot state: */
                    501:   if (__tme_predict_false((sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0)) {
                    502: 
                    503:     /* if this is the supervisor instruction ASI: */
                    504:     if (asi_mask == TME_SPARC32_ASI_MASK_SI) {
                    505: 
                    506:       /* fill this TLB entry directly from the obio (sun4c, sbus) or
                    507:          obmem (sun4) bus: */
                    508:       if (TME_SUN4_IS_SUN4C(sun4)) {
                    509:        (*sun4->tme_sun4_32_obio->tme_bus_tlb_fill)
                    510:          (sun4->tme_sun4_32_obio,
                    511:           tlb,
                    512:           TME_SUN44C_PROM_BASE | (address & (TME_SUN44C_PROM_SIZE - 1)),
                    513:           cycles);
                    514:       }
                    515:       else {
                    516:        (*sun4->tme_sun4_32_obmem->tme_bus_tlb_fill)
                    517:          (sun4->tme_sun4_32_obmem,
                    518:           tlb,
                    519:           TME_SUN44C_PROM_BASE | (address & (TME_SUN44C_PROM_SIZE - 1)),
                    520:           cycles);
                    521:       }
                    522:        
                    523:       /* create the mapping TLB entry: */
                    524:       tlb_bus.tme_bus_tlb_addr_first = address & (((tme_bus_addr_t) 0) - TME_SUN44C_PROM_SIZE);
                    525:       tlb_bus.tme_bus_tlb_addr_last = address | (TME_SUN44C_PROM_SIZE - 1);
                    526:       tlb_bus.tme_bus_tlb_cycles_ok
                    527:        = TME_BUS_CYCLE_READ;
                    528:   
                    529:       /* map the filled TLB entry: */
                    530:       tme_bus_tlb_map(tlb, TME_SUN44C_PROM_BASE | (address % TME_SUN44C_PROM_SIZE), &tlb_bus, address);
                    531:        
                    532:       /* this is good for the supervisor instruction ASI only: */
                    533:       *_asi_mask = TME_SPARC32_ASI_MASK_SI;
                    534: 
                    535:       /* done: */
                    536:       return(TME_OK);
                    537:     }
                    538: 
                    539:     /* this should be the supervisor data ASI only: */
                    540:     assert (asi_mask == TME_SPARC32_ASI_MASK_SD);
                    541: 
                    542:     /* update the head pointer for the active boot state TLB entry
                    543:        list: */
                    544:     tlb_i = sun4->tme_sun44c_boot_state_tlb_next
                    545:       = ((sun4->tme_sun44c_boot_state_tlb_next
                    546:          + 1)
                    547:         % TME_SUN44C_BOOT_STATE_TLBS);
                    548: 
                    549:     /* if the new head pointer already has a TLB entry, and it doesn't
                    550:        happen to be the same as this TLB entry, invalidate it: */
                    551:     if (sun4->tme_sun44c_boot_state_tlbs[tlb_i] != NULL
                    552:        && (sun4->tme_sun44c_boot_state_tlbs[tlb_i]
                    553:            != tlb->tme_bus_tlb_global)) {
                    554:       tme_bus_tlb_invalidate(sun4->tme_sun44c_boot_state_tlbs[tlb_i]);
                    555:     }
                    556: 
                    557:     /* add this TLB entry to the active list: */
                    558:     sun4->tme_sun44c_boot_state_tlbs[tlb_i] = tlb->tme_bus_tlb_global;
                    559: 
                    560:     /* if this TLB entry ends up good for the supervisor, it's not
                    561:        good for the supervisor instruction ASI: */
                    562:     asi_mask_si = 0;
                    563:   }
                    564: 
                    565:   /* thread the initiator's bus connection down to
                    566:      _tme_sun44c_tlb_fill_pte(): */
                    567:   tlb->tme_bus_tlb_fault_handlers[0]
                    568:     .tme_bus_tlb_fault_handler_private = (void *) conn_bus_init;
                    569: 
                    570:   /* fill this TLB entry from the MMU: */
                    571:   access
                    572:     = ((cycles & TME_BUS_CYCLE_WRITE)
                    573:        ? TME_SUN_MMU_PTE_PROT_RW
                    574:        : TME_SUN_MMU_PTE_PROT_RO);
                    575:   access
                    576:     = ((asi_mask == TME_SPARC32_ASI_MASK_UD
                    577:        || asi_mask == TME_SPARC32_ASI_MASK_UI)
                    578:        ? TME_SUN_MMU_PTE_PROT_USER(access)
                    579:        : TME_SUN_MMU_PTE_PROT_SYSTEM(access));
                    580:   tlb_flags = tme_sun_mmu_tlb_fill(sun4->tme_sun44c_mmu,
                    581:                                   tlb,
                    582:                                   TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus),
                    583:                                   address,
                    584:                                   access);
                    585: 
                    586:   /* this TLB entry is good for the program and instruction ASIs
                    587:      for the user and/or the supervisor: */
                    588:   *_asi_mask 
                    589:     = (((tlb_flags & TME_SUN_MMU_TLB_USER)
                    590:        ? (TME_SPARC32_ASI_MASK_UD
                    591:           | TME_SPARC32_ASI_MASK_UI)
                    592:        : 0)
                    593:        | ((tlb_flags & TME_SUN_MMU_TLB_SYSTEM)
                    594:          ? (TME_SPARC32_ASI_MASK_SD
                    595:             | asi_mask_si)
                    596:          : 0));
                    597: 
                    598:   return (TME_OK);
                    599: }
                    600: 
                    601: /* our sparc TLB filler: */
                    602: int
                    603: _tme_sun44c_tlb_fill_sparc(struct tme_sparc_bus_connection *conn_sparc,
                    604:                           struct tme_sparc_tlb *tlb_sparc,
                    605:                           tme_uint32_t asi_mask,
                    606:                           tme_bus_addr_t address,
                    607:                           unsigned int cycles)
                    608: {
                    609:   struct tme_sun4 *sun4;
                    610:   struct tme_bus_tlb *tlb;
                    611:   struct tme_bus_tlb tlb_bus;
                    612: 
                    613:   /* recover our sun4: */
                    614:   sun4 = (struct tme_sun4 *) conn_sparc->tme_sparc_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
                    615: 
                    616:   /* get the generic bus TLB: */
                    617:   tlb = &tlb_sparc->tme_sparc_tlb_bus_tlb;
                    618: 
                    619:   /* if this is the for user or supervisor data or instruction address
                    620:      spaces: */
                    621:   if (__tme_predict_true(TME_SPARC_ASI_MASK_OVERLAP(asi_mask,
                    622:                                                    (TME_SPARC32_ASI_MASK_UI
                    623:                                                     | TME_SPARC32_ASI_MASK_SI
                    624:                                                     | TME_SPARC32_ASI_MASK_UD
                    625:                                                     | TME_SPARC32_ASI_MASK_SD)))) {
                    626: 
                    627:     /* call the current TLB filler: */
                    628:     tlb_sparc->tme_sparc_tlb_asi_mask = asi_mask;
                    629:     return ((*sun4->tme_sun4_tlb_fill)(&conn_sparc->tme_sparc_bus_connection,
                    630:                                       tlb,
                    631:                                       &tlb_sparc->tme_sparc_tlb_asi_mask,
                    632:                                       address,
                    633:                                       cycles));
                    634:   }
                    635: 
                    636: 
                    637:   /* assume that we need a TLB entry that allows reading and writing
                    638:      over the entire address space, using the control cycle handler: */
                    639:   tme_bus_tlb_initialize(tlb);
                    640:   tlb->tme_bus_tlb_addr_first = 0;
                    641:   tlb->tme_bus_tlb_addr_last = (((tme_uint32_t) 0) - 1);
                    642:   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    643:   tlb_sparc->tme_sparc_tlb_asi_mask = asi_mask;
                    644:   tlb->tme_bus_tlb_cycle = _tme_sun44c_control_cycle_handler;
                    645:   tlb->tme_bus_tlb_cycle_private = &sun4->tme_sun4_asis[TME_SPARC_ASI_MASK_WHICH(asi_mask)];
                    646: 
                    647:   /* if this address space isn't defined: */
                    648:   if (__tme_predict_false(sun4->tme_sun4_asis[TME_SPARC_ASI_MASK_WHICH(asi_mask)].tme_sun4_asi_sun4 == NULL)) {
                    649:     abort();
                    650:   }
                    651: 
                    652:   /* if this is for control space: */
                    653:   if (__tme_predict_false(asi_mask == TME_SPARC_ASI_MASK(TME_SUN4_32_ASI_CONTROL))) {
                    654: 
                    655:     /* if this address is before the UART bypass: */
                    656:     if (__tme_predict_true(address < TME_SUN44C_CONTROL_UART_BYPASS)) {
                    657: 
                    658:       /* we cover the address space before the UART bypass: */
                    659:       tlb->tme_bus_tlb_addr_last = TME_SUN44C_CONTROL_UART_BYPASS - 1;
                    660:     }
                    661: 
                    662:     /* otherwise, this address is within the UART bypass: */
                    663:     else {
                    664: 
                    665:       /* fill this TLB entry directly from the obio bus: */
                    666:       (*sun4->tme_sun4_32_obio->tme_bus_tlb_fill)
                    667:        (sun4->tme_sun4_32_obio,
                    668:         tlb,
                    669:         (address % TME_SUN_Z8530_SIZE) + TME_SUN44C_OBIO_ZS0,
                    670:         cycles);
                    671: 
                    672:       /* create the mapping TLB entry: */
                    673:       tlb_bus.tme_bus_tlb_addr_first = address & (((tme_uint32_t) 0) - TME_SUN_Z8530_SIZE);
                    674:       tlb_bus.tme_bus_tlb_addr_last = address | (TME_SUN_Z8530_SIZE - 1);
                    675:       tlb_bus.tme_bus_tlb_cycles_ok
                    676:        = (TME_BUS_CYCLE_READ
                    677:           | TME_BUS_CYCLE_WRITE);
                    678:   
                    679:       /* map the filled TLB entry: */
                    680:       tme_bus_tlb_map(tlb, (address % TME_SUN_Z8530_SIZE) + TME_SUN44C_OBIO_ZS0, &tlb_bus, address);
                    681:     }
                    682:   }
                    683: 
                    684:   /* done: */
                    685:   return (TME_OK);
                    686: }
                    687: 
                    688: /* our bus TLB filler: */
                    689: int
                    690: _tme_sun44c_tlb_fill_bus(struct tme_bus_connection *conn_bus_init,
                    691:                         struct tme_bus_tlb *tlb,
                    692:                         tme_uint32_t address,
                    693:                         unsigned int cycles)
                    694: {
                    695:   struct tme_sun4 *sun4;
                    696:   struct tme_sun4_bus_connection *conn_sun4;
                    697:   tme_uint32_t base, mask;
                    698:   tme_uint32_t asi_mask;
                    699:   struct tme_bus_tlb tlb_bus;
                    700:   unsigned int tlb_i;
                    701: 
                    702:   /* recover our sun4: */
                    703:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    704: 
                    705:   /* recover the internal sun4 mainbus, or sun4c board, connection: */
                    706:   conn_sun4 = (struct tme_sun4_bus_connection *) conn_bus_init;
                    707: 
                    708:   /* dispatch on the internal connection.  this turns the bus address
                    709:      into a DVMA base address and size, except for the register
                    710:      connections, which are handled specially: */
                    711:   switch (conn_sun4->tme_sun4_bus_connection_which) {
                    712: 
                    713:   case TME_SUN4_32_CONN_BUS_OBIO:
                    714:     if (TME_SUN4_IS_SUN4C(sun4)) {
                    715:       base = 0x00000000;
                    716:       mask = ((tme_uint32_t) 0) - 1;
                    717:     }
                    718:     else {
                    719:       abort();
                    720:     }
                    721:     break;
                    722: 
                    723:   case TME_SUN4_32_CONN_REG_TIMER:
                    724: 
                    725:     /* return a TLB entry that allows reading and writing the two timers: */
                    726:     tme_bus_tlb_initialize(tlb);
                    727:     tlb->tme_bus_tlb_addr_first = 0;
                    728:     tlb->tme_bus_tlb_addr_last = (TME_SUN44C_TIMER_SIZ_REG * 2) - 1;
                    729:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    730:     tlb->tme_bus_tlb_cycle_private = sun4;
                    731:     tlb->tme_bus_tlb_cycle = _tme_sun4_timer_cycle_control;
                    732:     return (TME_OK);
                    733: 
                    734:   case TME_SUN4_32_CONN_REG_INTREG:
                    735:   case TME_SUN4C4M_CONN_REG_AUXREG:
                    736: 
                    737:     /* return a TLB entry that allows reading and writing these 8-bit
                    738:        registers: */
                    739:     tme_bus_tlb_initialize(tlb);
                    740:     tlb->tme_bus_tlb_addr_first = 0;
                    741:     tlb->tme_bus_tlb_addr_last = sizeof(tme_uint8_t) - 1;
                    742:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    743:     tlb->tme_bus_tlb_cycle_private = sun4;
                    744:     tlb->tme_bus_tlb_cycle
                    745:       = (conn_sun4->tme_sun4_bus_connection_which == TME_SUN4C4M_CONN_REG_AUXREG
                    746:         ? _tme_sun4c_auxreg_cycle_control
                    747:         : _tme_sun44c_intreg_cycle_control);
                    748:     return (TME_OK);
                    749: 
                    750: 
                    751:   case TME_SUN4_32_CONN_REG_MEMERR:
                    752:     
                    753:     /* return a TLB entry that allows reading and writing the memory
                    754:        error register(s): */
                    755:     tme_bus_tlb_initialize(tlb);
                    756:     tlb->tme_bus_tlb_addr_first = 0;
                    757:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    758:     tlb->tme_bus_tlb_cycle_private = sun4;
                    759:     tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_control;
                    760: 
                    761:     /* the size of the memory error register(s) depends on
                    762:        the model: */
                    763:     tlb->tme_bus_tlb_addr_last
                    764:       = (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)
                    765:         ? (TME_SUN44C_MEMERR_SIZ_REG * 2)
                    766:         : TME_SUN44C_MEMERR_SIZ_REG) - 1;
                    767: 
                    768:     return (TME_OK);
                    769: 
                    770:   default: abort();
                    771:   }
                    772: 
                    773:   /* update the head pointer for the active SDVMA TLB entry list: */
                    774:   tlb_i = sun4->tme_sun44c_sdvma_tlb_next
                    775:     = ((sun4->tme_sun44c_sdvma_tlb_next
                    776:        + 1)
                    777:        & (TME_SUN44C_SDVMA_TLBS - 1));
                    778: 
                    779:   /* if the new head pointer already has a TLB entry, and it doesn't
                    780:      happen to be the same as this TLB entry, invalidate it: */
                    781:   if (sun4->tme_sun44c_sdvma_tlbs[tlb_i] != NULL
                    782:       && (sun4->tme_sun44c_sdvma_tlbs[tlb_i]
                    783:          != tlb->tme_bus_tlb_global)) {
                    784:     tme_bus_tlb_invalidate(sun4->tme_sun44c_sdvma_tlbs[tlb_i]);
                    785:   }
                    786: 
                    787:   /* add this TLB entry to the active list: */
                    788:   sun4->tme_sun44c_sdvma_tlbs[tlb_i] = tlb->tme_bus_tlb_global;
                    789: 
                    790:   /* if system DVMA is disabled: */
                    791:   if (__tme_predict_false(!(sun4->tme_sun44c_enable & TME_SUN44C_ENA_SDVMA))) {
                    792: 
                    793:     /* return a TLB entry that will generate a bus fault: */
                    794:     tme_bus_tlb_initialize(tlb);
                    795:     tlb->tme_bus_tlb_addr_first = 0;
                    796:     tlb->tme_bus_tlb_addr_last = mask;
                    797:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    798:     tlb->tme_bus_tlb_cycle_private = sun4;
                    799:     tlb->tme_bus_tlb_cycle = _tme_sun44c_bus_timeout;
                    800:     TME_BUS_TLB_FAULT_HANDLER(tlb, 
                    801:                              (TME_SUN4_IS_SUN4C(sun4)
                    802:                               ? _tme_sun4c_sbus_fault_handler
                    803:                               : _tme_sun4_vmebus_fault_handler),
                    804:                              conn_bus_init);
                    805:     return (TME_OK);
                    806:   }
                    807: 
                    808:   assert (!(address & base)
                    809:          && (address <= mask));
                    810: 
                    811:   /* call the current TLB filler: */
                    812:   asi_mask = TME_SPARC32_ASI_MASK_SD;
                    813:   (*sun4->tme_sun4_tlb_fill)(conn_bus_init,
                    814:                             tlb,
                    815:                             &asi_mask,
                    816:                             address,
                    817:                             cycles);
                    818: 
                    819:   /* create the mapping TLB entry.  we do this even if base == 0,
                    820:      because the TLB entry as currently filled may cover more address
                    821:      space than DVMA space on this machine is supposed to cover: */
                    822:   tlb_bus.tme_bus_tlb_addr_first = 0;
                    823:   tlb_bus.tme_bus_tlb_addr_last = mask;
                    824:   tlb_bus.tme_bus_tlb_cycles_ok
                    825:     = (TME_BUS_CYCLE_READ
                    826:        | TME_BUS_CYCLE_WRITE);
                    827:   
                    828:   /* map the filled TLB entry: */
                    829:   tme_bus_tlb_map(tlb, address | base, &tlb_bus, address);
                    830: 
                    831:   return (TME_OK);
                    832: }
                    833: 
                    834: /* our post-MMU TLB filler: */
                    835: static int
                    836: _tme_sun44c_tlb_fill_pte(void *_sun4,
                    837:                         struct tme_bus_tlb *tlb, 
                    838:                         struct tme_sun_mmu_pte *pte,
                    839:                         tme_uint32_t *_address,
                    840:                         unsigned int cycles)
                    841: {
                    842:   struct tme_sun4 *sun4;
                    843:   tme_uint32_t address;
                    844:   unsigned int bus_type;
                    845:   void *_conn_bus_init;
                    846:   struct tme_bus_connection *conn_bus_resp;
                    847:   tme_bus_fault_handler bus_fault_handler;
                    848:   int rc;
                    849: 
                    850:   /* recover our sun4: */
                    851:   sun4 = (struct tme_sun4 *) _sun4;
                    852: 
                    853:   /* recover the initiator's bus connection.  this is threaded down
                    854:      from _tme_sun44c_tlb_fill_mmu(): */
                    855:   _conn_bus_init = 
                    856:     tlb->tme_bus_tlb_fault_handlers[0]
                    857:     .tme_bus_tlb_fault_handler_private;
                    858: 
                    859:   /* get the initial physical address and bus type: */
                    860:   address = pte->tme_sun_mmu_pte_raw;
                    861:   if (TME_SUN4_IS_SUN4C(sun4)) {
                    862:     address = (address & TME_SUN4C_PTE_PGFRAME) * TME_SUN4C_PAGE_SIZE;
                    863:     address += *_address % TME_SUN4C_PAGE_SIZE;
                    864:   }
                    865:   else {
                    866:     address = (address & TME_SUN4_PTE_PGFRAME) * TME_SUN4_PAGE_SIZE;
                    867:     address += *_address % TME_SUN4_PAGE_SIZE;
                    868:   }
                    869:   bus_type = TME_FIELD_MASK_EXTRACTU(pte->tme_sun_mmu_pte_raw, TME_SUN44C_PTE_PGTYPE);
                    870: 
                    871:   /* if this is obio: */
                    872:   if (bus_type == TME_SUN44C_PGTYPE_OBIO) {
                    873:     conn_bus_resp = sun4->tme_sun4_32_obio;
                    874:     bus_fault_handler = _tme_sun44c_ob_fault_handler;
                    875:     if (TME_SUN4_IS_SUN4C(sun4)) {
                    876:       address |= 0xf0000000;
                    877:       if (address >= TME_SUN4C_OBIO_SBUS) {
                    878:        bus_fault_handler = _tme_sun4c_sbus_fault_handler;
                    879:       }
                    880:     }
                    881:     else {
                    882:       abort();
                    883:     }
                    884:   }
                    885:   
                    886:   /* if this is obmem: */
                    887:   else if (bus_type == TME_SUN44C_PGTYPE_OBMEM) {
                    888:     if (TME_SUN4_IS_SUN4C(sun4)) {
                    889:       conn_bus_resp = sun4->tme_sun4_32_obio;
                    890:       bus_fault_handler = _tme_sun4c_obmem_fault_handler;
                    891:     }
                    892:     else {
                    893:       conn_bus_resp = sun4->tme_sun4_32_obmem;
                    894:       bus_fault_handler = _tme_sun44c_ob_fault_handler;
                    895:     }
                    896:   }
                    897: 
                    898:   /* if this is the VME bus: */
                    899:   else {
                    900:     assert ((bus_type == TME_SUN4_PGTYPE_VME_D16
                    901:             || bus_type == TME_SUN4_PGTYPE_VME_D32));
                    902:     conn_bus_resp = sun4->tme_sun4_vmebus;
                    903:     bus_fault_handler = _tme_sun4_vmebus_fault_handler;
                    904: 
                    905:     /* SS2 PROMs will try to map type-2 and type-3 space to test
                    906:        synchronous timeouts: */
                    907:     if (TME_SUN4_IS_SUN4C(sun4)) {
                    908: 
                    909:       /* return the real physical address: */
                    910:       *_address = address;
                    911: 
                    912:       /* return a TLB entry that will generate a bus fault: */
                    913:       tme_bus_tlb_initialize(tlb);
                    914:       tlb->tme_bus_tlb_addr_first = 0;
                    915:       tlb->tme_bus_tlb_addr_last = (((tme_uint32_t) 0) - 1);
                    916:       tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    917:       tlb->tme_bus_tlb_cycle_private = sun4;
                    918:       tlb->tme_bus_tlb_cycle = _tme_sun44c_bus_timeout;
                    919:       TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun4c_pgtype_fault_handler, _conn_bus_init);
                    920:       return (TME_OK);
                    921:     }
                    922:   }
                    923: 
                    924:   /* return the real physical address: */
                    925:   *_address = address;
                    926: 
                    927:   /* call the bus TLB filler: */
                    928:   rc = ((*conn_bus_resp->tme_bus_tlb_fill)
                    929:        (conn_bus_resp, tlb, address, cycles));
                    930: 
                    931:   /* if the bus TLB filler succeeded, add our bus fault handler: */
                    932:   if (rc == TME_OK) {
                    933:     TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, _conn_bus_init);
                    934:   }
                    935: 
                    936:   return (rc);
                    937: }
                    938: 
                    939: /* this gets a PTE from the MMU: */
                    940: int
                    941: _tme_sun44c_mmu_pte_get(struct tme_sun4 *sun4, tme_uint32_t address, tme_uint32_t *_pte_sun44c)
                    942: {
                    943:   struct tme_sun_mmu_pte pte;
                    944:   tme_uint32_t pte_sun44c;
                    945:   unsigned int pte_flags;
                    946:   int rc;
                    947: 
                    948:   /* get the PTE from the MMU: */
                    949:   rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, 
                    950:                           sun4->tme_sun44c_context,
                    951:                           address,
                    952:                           &pte);
                    953:   assert(rc == TME_OK);
                    954:     
                    955:   /* form the Sun 4/4c PTE: */
                    956:   pte_sun44c = pte.tme_sun_mmu_pte_raw;
                    957:   pte_flags = pte.tme_sun_mmu_pte_flags;
                    958:   if (pte_flags & TME_SUN_MMU_PTE_REF) {
                    959:     pte_sun44c |= TME_SUN44C_PTE_REF;
                    960:   }
                    961:   if (pte_flags & TME_SUN_MMU_PTE_MOD) {
                    962:     pte_sun44c |= TME_SUN44C_PTE_MOD;
                    963:   }
                    964: 
                    965:   /* done: */
                    966:   *_pte_sun44c = pte_sun44c;
                    967:   tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
                    968:          (TME_SUN4_LOG_HANDLE(sun4),
                    969:           _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"), 
                    970:           sun4->tme_sun44c_context,
                    971:           address,
                    972:           pte_sun44c));
                    973:   return (TME_OK);
                    974: }
                    975: 
                    976: /* this sets a PTE into the MMU: */
                    977: int
                    978: _tme_sun44c_mmu_pte_set(struct tme_sun4 *sun4, tme_uint32_t address, tme_uint32_t pte_sun44c)
                    979: {
                    980:   struct tme_sun_mmu_pte pte;
                    981:   unsigned int pte_flags;
                    982: #ifndef TME_NO_LOG
                    983:   const char *bus_name;
                    984:   tme_bus_addr_t physical_address;
                    985:       
                    986:   /* this silences gcc -Wuninitialized: */
                    987:   bus_name = NULL;
                    988: 
                    989:   /* log this setting: */
                    990:   if (TME_SUN4_IS_SUN4C(sun4)) {
                    991:     physical_address = (pte_sun44c & TME_SUN4C_PTE_PGFRAME) * TME_SUN4C_PAGE_SIZE;
                    992:   }
                    993:   else {
                    994:     physical_address = (pte_sun44c & TME_SUN4_PTE_PGFRAME) * TME_SUN4_PAGE_SIZE;
                    995:   }
                    996:   switch (TME_FIELD_MASK_EXTRACTU(pte_sun44c, TME_SUN44C_PTE_PGTYPE)) {
                    997:   case TME_SUN44C_PGTYPE_OBMEM: bus_name = "obmem"; break;
                    998:   case TME_SUN44C_PGTYPE_OBIO:
                    999:     if (TME_SUN4_IS_SUN4C(sun4)) {
                   1000:       physical_address |= 0xf0000000;
                   1001:       bus_name = (physical_address >= TME_SUN4C_OBIO_SBUS
                   1002:                  ? "SBus"
                   1003:                  : "mainbus");
                   1004:     }
                   1005:     else {
                   1006:       bus_name = "obio";
                   1007:     }
                   1008:     break;
                   1009:   case TME_SUN4_PGTYPE_VME_D16: bus_name = "VME_D16"; break;
                   1010:   case TME_SUN4_PGTYPE_VME_D32: bus_name = "VME_D32"; break;
                   1011:   }
                   1012:   tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
                   1013:          (TME_SUN4_LOG_HANDLE(sun4),
                   1014:           _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"), 
                   1015:           sun4->tme_sun44c_context,
                   1016:           address,
                   1017:           pte_sun44c,
                   1018:           bus_name,
                   1019:           physical_address));
                   1020: #endif /* !TME_NO_LOG */
                   1021: 
                   1022:   /* store only the bits that the real hardware stores: */
                   1023:   pte_sun44c
                   1024:     &= (TME_SUN44C_PTE_VALID
                   1025:        | TME_SUN44C_PTE_WRITE
                   1026:        | TME_SUN44C_PTE_SYSTEM
                   1027:        | TME_SUN44C_PTE_NC
                   1028:        | TME_SUN44C_PTE_REF
                   1029:        | TME_SUN44C_PTE_MOD
                   1030:        | (TME_SUN4_IS_SUN4C(sun4)
                   1031:           ? (TME_SUN44C_PTE_PGTYPE
                   1032:              | TME_SUN4C_PTE_PGFRAME)
                   1033:           : (TME_SUN44C_PTE_PGTYPE
                   1034:              | TME_SUN4_PTE_PGFRAME)));
                   1035: 
                   1036:   pte.tme_sun_mmu_pte_raw = pte_sun44c;
                   1037:       
                   1038:   pte_flags = (pte_sun44c & TME_SUN44C_PTE_WRITE
                   1039:               ? TME_SUN_MMU_PTE_PROT_RW
                   1040:               : TME_SUN_MMU_PTE_PROT_RO);
                   1041:   pte_flags = (TME_SUN_MMU_PTE_PROT_SYSTEM(pte_flags)
                   1042:               | TME_SUN_MMU_PTE_PROT_USER(pte_sun44c & TME_SUN44C_PTE_SYSTEM
                   1043:                                           ? TME_SUN_MMU_PTE_PROT_ERROR
                   1044:                                           : pte_flags));
                   1045:   if (pte_sun44c & TME_SUN44C_PTE_MOD) {
                   1046:     pte_flags |= TME_SUN_MMU_PTE_MOD;
                   1047:   }
                   1048:   if (pte_sun44c & TME_SUN44C_PTE_REF) {
                   1049:     pte_flags |= TME_SUN_MMU_PTE_REF;
                   1050:   }
                   1051:   if (pte_sun44c & TME_SUN44C_PTE_VALID) {
                   1052:     pte_flags |= TME_SUN_MMU_PTE_VALID;
                   1053:   }
                   1054:   pte.tme_sun_mmu_pte_flags = pte_flags;
                   1055:   
                   1056:   return (tme_sun_mmu_pte_set(sun4->tme_sun44c_mmu, 
                   1057:                              sun4->tme_sun44c_context,
                   1058:                              address,
                   1059:                              &pte));
                   1060: }
                   1061: 
                   1062: /* this is called when the SDVMA bit is changed in the enable register: */
                   1063: void
                   1064: _tme_sun44c_mmu_sdvma_change(struct tme_sun4 *sun4)
                   1065: {
                   1066:   unsigned int tlb_i;
                   1067: 
                   1068:   /* whenever the SDVMA bit changes, we have to invalidate all SDVMA
                   1069:      TLB entries: */
                   1070:   for (tlb_i = 0; tlb_i < TME_SUN44C_SDVMA_TLBS; tlb_i++) {
                   1071:     if (sun4->tme_sun44c_sdvma_tlbs[tlb_i] != NULL) {
                   1072:       tme_bus_tlb_invalidate(sun4->tme_sun44c_sdvma_tlbs[tlb_i]);
                   1073:       sun4->tme_sun44c_sdvma_tlbs[tlb_i] = NULL;
                   1074:     }
                   1075:   }
                   1076: }
                   1077: 
                   1078: /* this is called when the context register is set: */
                   1079: void
                   1080: _tme_sun44c_mmu_context_set(struct tme_sun4 *sun4)
                   1081: {
                   1082:   unsigned int tlb_i;
                   1083: 
                   1084:   /* every TLB set has an extra context's worth of TLB entries.
                   1085:      context zero is used for the "boot state", and the remaining
                   1086:      contexts correspond to the normal MMU contexts.
                   1087: 
                   1088:      context zero is used for the boot state because at TLB set
                   1089:      allocation time, TLB sets are initialized pointing to the context
                   1090:      zero TLBs (by tme_sun_mmu_tlb_set_allocate), and TLBs must be
                   1091:      initialized to the boot state TLBs.
                   1092: 
                   1093:      in the boot state, TLB fills for supervisor program references
                   1094:      bypass the MMU and are filled to reference the PROM, and data
                   1095:      fills are filled as normal using the current context.  since context
                   1096:      register changes can happen while in the boot state, but we only
                   1097:      have one boot state context in the TLB sets, we have to track 
                   1098:      the data TLBs we fill in the boot state.
                   1099: 
                   1100:      we don't bother to track the supervisor program TLB fills, since
                   1101:      they never change.  */
                   1102: 
                   1103:   /* in the not-boot (i.e., normal, state): */
                   1104:   if (__tme_predict_true(sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT)) {
                   1105: 
                   1106:     tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
                   1107:            (TME_SUN4_LOG_HANDLE(sun4),
                   1108:             _("context now #%d"),
                   1109:             sun4->tme_sun44c_context));
                   1110: 
                   1111:     /* update all TLB sets to reflect the context change: */
                   1112:     tme_sun_mmu_tlbs_context_set(sun4->tme_sun44c_mmu, sun4->tme_sun44c_context + 1);
                   1113:   }
                   1114: 
                   1115:   /* in the boot state: */
                   1116:   else {
                   1117: 
                   1118:     tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
                   1119:            (TME_SUN4_LOG_HANDLE(sun4),
                   1120:             _("context now #%d (boot state)"),
                   1121:             sun4->tme_sun44c_context));
                   1122: 
                   1123:     /* update all TLB sets to reflect the pseudo-context change: */
                   1124:     tme_sun_mmu_tlbs_context_set(sun4->tme_sun44c_mmu, 0);
                   1125: 
                   1126:     /* invalidate all of the boot-state data TLBs: */
                   1127:     for (tlb_i = 0; tlb_i < TME_SUN44C_BOOT_STATE_TLBS; tlb_i++) {
                   1128:       if (sun4->tme_sun44c_boot_state_tlbs[tlb_i] != NULL) {
                   1129:        tme_bus_tlb_invalidate(sun4->tme_sun44c_boot_state_tlbs[tlb_i]);
                   1130:        sun4->tme_sun44c_boot_state_tlbs[tlb_i] = NULL;
                   1131:       }
                   1132:     }
                   1133:   }
                   1134: }
                   1135: 
                   1136: /* this allocates a new TLB set: */
                   1137: int
                   1138: _tme_sun44c_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
                   1139:                                 unsigned int count, unsigned int sizeof_one, 
                   1140:                                 struct tme_bus_tlb * tme_shared * _tlbs,
                   1141:                                 tme_rwlock_t *_tlbs_rwlock)
                   1142: {
                   1143:   struct tme_sun4 *sun4;
                   1144:   int rc;
                   1145: 
                   1146:   /* recover our sun4: */
                   1147:   sun4 = (struct tme_sun4 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
                   1148: 
                   1149:   /* get the MMU to allocate the TLB set: */
                   1150:   rc = tme_sun_mmu_tlb_set_allocate(sun4->tme_sun44c_mmu, count, sizeof_one, _tlbs, _tlbs_rwlock);
                   1151: 
                   1152:   return (rc);
                   1153: }
                   1154: 
                   1155: /* this creates a sun4/4c MMU: */
                   1156: void
                   1157: _tme_sun44c_mmu_new(struct tme_sun4 *sun4)
                   1158: {
                   1159:   struct tme_sun_mmu_info mmu_info;
                   1160: 
                   1161:   memset(&mmu_info, 0, sizeof(mmu_info));
                   1162:   mmu_info.tme_sun_mmu_info_element = sun4->tme_sun4_element;
                   1163:   mmu_info.tme_sun_mmu_info_address_bits = 32;
                   1164:   if (TME_SUN4_IS_SUN4C(sun4)) {
                   1165:     mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN4C_PAGE_SIZE_LOG2;
                   1166:     mmu_info.tme_sun_mmu_info_topindex_bits = -3; /* the address hole makes the top 3 address bits the same */
                   1167:   }
                   1168:   else {
                   1169:     mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN4_PAGE_SIZE_LOG2;
                   1170:   }
                   1171:   mmu_info.tme_sun_mmu_info_pteindex_bits = 18 - mmu_info.tme_sun_mmu_info_pgoffset_bits;
                   1172:   if (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)) {
                   1173:     mmu_info.tme_sun_mmu_info_contexts = 16;
                   1174:     mmu_info.tme_sun_mmu_info_pmegs = 256;
                   1175:   }
                   1176:   else if (TME_SUN4_IS_SUN4C(sun4)) {
                   1177:     mmu_info.tme_sun_mmu_info_contexts = 8;
                   1178:     mmu_info.tme_sun_mmu_info_pmegs = 128;
                   1179:   }
                   1180:   else {
                   1181:     abort();
                   1182:   }
                   1183:   mmu_info.tme_sun_mmu_info_contexts++; /* internal context zero is for the boot state */
                   1184:   mmu_info.tme_sun_mmu_info_tlb_fill_private = sun4;
                   1185:   mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun44c_tlb_fill_pte;
                   1186:   mmu_info.tme_sun_mmu_info_proterr_private = &sun4->tme_sun4_dummy_connection_sparc;
                   1187:   mmu_info.tme_sun_mmu_info_proterr = _tme_sun44c_mmu_proterr;
                   1188:   mmu_info.tme_sun_mmu_info_invalid_private = &sun4->tme_sun4_dummy_connection_sparc;
                   1189:   mmu_info.tme_sun_mmu_info_invalid = _tme_sun44c_mmu_invalid;
                   1190:   sun4->tme_sun44c_mmu = tme_sun_mmu_new(&mmu_info);
                   1191:   sun4->tme_sun44c_mmu_pmegs = mmu_info.tme_sun_mmu_info_pmegs;
                   1192:   sun4->tme_sun4_dummy_connection_sparc.tme_connection_type = TME_CONNECTION_BUS_SPARC;
                   1193:   sun4->tme_sun4_dummy_connection_sparc.tme_connection_element = sun4->tme_sun4_element;
                   1194: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.