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