|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.