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

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

unix.superglobalmegacorp.com

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