Annotation of tme/machine/sun4/sun44c-mmu.c, revision 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.