|
|
1.1.1.2 ! root 1: /* $Id: sun44c-memerr.c,v 1.3 2010/06/05 19:29:11 fredette Exp $ */ 1.1 root 2: 3: /* machine/sun4/sun44c-memerr.c - implementation of Sun 4/4c memory error emulation: */ 4: 5: /* 6: * Copyright (c) 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-memerr.c,v 1.3 2010/06/05 19:29:11 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include "sun4-impl.h" 41: 42: /* this calls out a memory error interrupt change: */ 43: static void 44: _tme_sun44c_memerr_callout(struct tme_sun4 *sun4) 45: { 46: unsigned int int_asserted; 47: struct tme_bus_connection *conn_bus; 48: int rc; 49: 50: /* on a sun4c, asynchronous memory errors can't really be tested, so 51: we never need to assert the memory error interrupt: */ 52: if (TME_SUN4_IS_SUN4C(sun4)) { 53: return; 54: } 55: 56: /* see if the memory error interrupt should be asserted: */ 57: int_asserted 58: = ((sun4->tme_sun44c_memerr_csr[0] 59: & (TME_SUN4_MEMERR_X_INT_ACTIVE 60: | TME_SUN4_MEMERR_X_ENABLE_INT)) 61: == (TME_SUN4_MEMERR_X_INT_ACTIVE 62: | TME_SUN4_MEMERR_X_ENABLE_INT)); 63: 64: /* if we need to call out an interrupt change: */ 65: if (!int_asserted != !sun4->tme_sun4_memerr_int_asserted) { 66: 67: /* get our bus connection: */ 68: conn_bus = sun4->tme_sun4_buses[TME_SUN4_32_CONN_REG_MEMERR]; 69: 70: /* call out the bus interrupt signal edge: */ 71: rc = (*conn_bus->tme_bus_signal) 72: (conn_bus, 73: TME_BUS_SIGNAL_INT(TME_SPARC_IPL_NMI) 74: | (int_asserted 75: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 76: : TME_BUS_SIGNAL_LEVEL_NEGATED)); 77: 78: /* if this callout was successful, note the new state of the 79: interrupt signal: */ 80: if (rc == TME_OK) { 81: sun4->tme_sun4_memerr_int_asserted = int_asserted; 82: } 83: 84: /* otherwise, abort: */ 85: else { 86: abort(); 87: } 88: } 89: } 90: 91: /* this updates bad memory: */ 92: void 93: _tme_sun44c_memerr_update(struct tme_sun4 *sun4, 94: tme_uint32_t pte, 95: const tme_shared tme_uint8_t *memory, 96: unsigned int cycle_size) 97: { 98: unsigned int address_i; 99: unsigned int address_i_free; 100: int which_csr; 101: int memory_bad; 102: int visible_before; 103: 104: /* on the SS2, code name "Calvin", the second 64MB of memory is on 105: an expansion board, which uses the second memory error register: */ 106: which_csr = (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN) 107: && (pte & TME_SUN4C_PTE_PGFRAME) >= ((64 * 1024 * 1024) / TME_SUN4C_PAGE_SIZE)); 108: 109: /* if the memory is being written with bad parity: */ 110: memory_bad = (sun4->tme_sun44c_memerr_csr[which_csr] & TME_SUN44C_MEMERR_PAR_TEST) != 0; 111: 112: /* see if the memory error registers are visible before: */ 113: visible_before = TME_SUN44C_MEMERR_VISIBLE(sun4); 114: 115: /* this is obviously a poor implementation, but this is not used 116: during normal operation: */ 117: 118: /* loop over all of the written memory: */ 119: for (; cycle_size > 0; memory++, cycle_size--) { 120: 121: /* search the bad memory list for this memory, and for a free 122: entry in the list: */ 123: address_i = 0; 124: address_i_free = TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory); 125: do { 126: if (sun4->tme_sun4_memerr_bad_memory[address_i] == NULL) { 127: address_i_free = address_i; 128: } 129: else if (sun4->tme_sun4_memerr_bad_memory[address_i] == memory) { 130: address_i_free = address_i; 131: break; 132: } 133: } while (++address_i < TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory)); 134: 135: /* if the memory is being written with bad parity: */ 136: if (memory_bad) { 137: 138: /* if the bad memory list is full: */ 139: if (address_i_free == TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory)) { 140: abort(); 141: } 142: 143: /* if this bad memory isn't already on the list: */ 144: if (sun4->tme_sun4_memerr_bad_memory[address_i_free] == NULL) { 145: 146: /* this memory is now bad: */ 147: sun4->tme_sun4_memerr_bad_memory[address_i_free] = memory; 148: sun4->tme_sun4_memerr_bad_memory_count++; 149: } 150: } 151: 152: /* otherwise, the memory is being written with good parity: */ 153: else { 154: 155: /* if this memory was previously written with bad parity: */ 156: if (address_i_free < TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory) 157: && sun4->tme_sun4_memerr_bad_memory[address_i] == memory) { 158: 159: /* this memory is good again: */ 160: sun4->tme_sun4_memerr_bad_memory[address_i] = NULL; 161: sun4->tme_sun4_memerr_bad_memory_count--; 162: } 163: } 164: } 165: 166: /* if the memory error registers were visible before, and are no 167: longer visible: */ 168: if (visible_before 169: && !TME_SUN44C_MEMERR_VISIBLE(sun4)) { 170: 171: /* unless the cache is visible, update the TLB fill function: */ 172: if (!sun4->tme_sun4_cache_visible) { 173: sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_mmu; 174: } 175: } 176: } 177: 178: /* this checks for bad memory during a read: */ 179: int 180: _tme_sun44c_memerr_check(const struct tme_bus_connection *conn_bus_init, 181: tme_uint32_t address, 182: tme_uint32_t pte, 183: const tme_shared tme_uint8_t *memory, 184: unsigned int cycle_size) 185: { 186: struct tme_sun4 *sun4; 187: unsigned int address_i; 188: tme_uint32_t csr; 189: int write_csr; 190: 191: /* recover our sun4: */ 192: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private; 193: 194: /* this is obviously a poor implementation, but this is not used 195: during normal operation: */ 196: 197: /* loop over all of the bad memory: */ 198: csr = 0; 199: for (; cycle_size > 0; address++, memory++, cycle_size--) { 200: 201: /* see if this byte is bad: */ 202: address_i = 0; 203: do { 204: if (sun4->tme_sun4_memerr_bad_memory[address_i] == memory) { 205: csr 206: |= (TME_SUN4_IS_SUN4C(sun4) 207: ? TME_SUN44C_MEMERR_PAR_ERR_BL0 << (address % sizeof(tme_uint32_t)) 208: : TME_SUN44C_MEMERR_PAR_ERR_BL3 >> (address % sizeof(tme_uint32_t))); 209: break; 210: } 211: } while (++address_i < TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory)); 212: } 213: 214: /* if no bad memory was accessed, return now: */ 215: if (csr == 0) { 216: return (FALSE); 217: } 218: 219: /* if this is a sun4c: */ 220: if (TME_SUN4_IS_SUN4C(sun4)) { 221: 222: /* on the SS2, code name "Calvin", the second 64MB of memory is on 223: an expansion board, which uses the second memory error 224: register: */ 225: write_csr = (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN) 226: && (pte & TME_SUN4C_PTE_PGFRAME) >= ((64 * 1024 * 1024) / TME_SUN4C_PAGE_SIZE)); 227: 228: sun4->tme_sun44c_memerr_csr[write_csr] 229: |= (csr 230: | TME_SUN4C_MEMERR_PAR_ERROR 231: | ((sun4->tme_sun44c_memerr_csr[write_csr] & TME_SUN4C_MEMERR_PAR_ERROR) 232: ? TME_SUN4C_MEMERR_PAR_MULTI 233: : 0)); 234: } 235: 236: /* otherwise, this is a sun4: */ 237: else { 238: abort(); 239: } 240: 241: /* call out an interrupt: */ 242: _tme_sun44c_memerr_callout(sun4); 243: 244: /* a memory error has happened: */ 245: return (TRUE); 246: } 247: 248: /* the bus cycle handler for the memory error register: */ 249: int 250: _tme_sun44c_memerr_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init) 251: { 252: struct tme_sun4 *sun4; 1.1.1.2 ! root 253: tme_uint32_t memerr_reg[2][TME_SUN44C_MEMERR_SIZ_REG / sizeof(tme_uint32_t)]; 1.1 root 254: int write_csr, unlatch; 255: int write_parctl; 256: tme_uint32_t csr_old; 257: tme_uint32_t csr_new; 258: tme_uint32_t csr_ro; 259: int visible_before; 260: 261: /* recover our sun4: */ 262: sun4 = (struct tme_sun4 *) _sun4; 263: 264: /* start filling the memory error register(s): */ 1.1.1.2 ! root 265: memerr_reg[0][TME_SUN44C_MEMERR_REG_CSR / sizeof(tme_uint32_t)] 1.1 root 266: = tme_htobe_u32(sun4->tme_sun44c_memerr_csr[0]); 267: 268: /* assume this cycle won't write or unlatch a memory error register: */ 269: write_csr = -1; 270: unlatch = -1; 271: write_parctl = -1; 272: 273: /* we only tolerate aligned 32-bit accesses: */ 274: if (!((cycle_init->tme_bus_cycle_address % sizeof(tme_uint32_t)) == 0 275: && cycle_init->tme_bus_cycle_size == sizeof(tme_uint32_t))) { 276: abort(); 277: } 278: 279: /* if this is a sun4c: */ 280: if (TME_SUN4_IS_SUN4C(sun4)) { 281: 282: /* finish filling the memory error registers: */ 1.1.1.2 ! root 283: memerr_reg[0][TME_SUN4C_MEMERR_REG_PARCTL / sizeof(tme_uint32_t)] 1.1 root 284: = tme_htobe_u32(sun4->tme_sun4c_memerr_parctl[0]); 1.1.1.2 ! root 285: memerr_reg[1][TME_SUN44C_MEMERR_REG_CSR / sizeof(tme_uint32_t)] 1.1 root 286: = tme_htobe_u32(sun4->tme_sun44c_memerr_csr[1]); 1.1.1.2 ! root 287: memerr_reg[1][TME_SUN4C_MEMERR_REG_PARCTL / sizeof(tme_uint32_t)] 1.1 root 288: = tme_htobe_u32(sun4->tme_sun4c_memerr_parctl[1]); 289: 290: assert ((cycle_init->tme_bus_cycle_address 291: + cycle_init->tme_bus_cycle_size 292: - 1) < sizeof(memerr_reg)); 293: 294: /* if this access is to a parity control register: */ 295: if (cycle_init->tme_bus_cycle_address & TME_SUN4C_MEMERR_REG_PARCTL) { 296: 297: /* if this is a write: */ 298: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { 299: write_parctl = (cycle_init->tme_bus_cycle_address / TME_SUN44C_MEMERR_SIZ_REG); 300: } 301: } 302: 303: /* otherwise, this access is to a CSR: */ 304: else { 305: 306: /* "The information bits in the memory error register are 307: cleared by reading it." */ 308: 309: /* any write writes either of the CSRs, and any read reads one 310: of the CSRs: */ 311: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) { 312: unlatch = (cycle_init->tme_bus_cycle_address / TME_SUN44C_MEMERR_SIZ_REG); 313: } 314: else { 315: write_csr = (cycle_init->tme_bus_cycle_address / TME_SUN44C_MEMERR_SIZ_REG); 316: } 317: } 318: } 319: 320: /* otherwise, this is a sun4: */ 321: else { 322: 323: /* finish filling the memory error register: */ 1.1.1.2 ! root 324: memerr_reg[0][TME_SUN4_MEMERR_REG_VADDR / sizeof(tme_uint32_t)] 1.1 root 325: = tme_htobe_u32(sun4->tme_sun4_memerr_vaddr); 326: 327: assert ((cycle_init->tme_bus_cycle_address 328: + cycle_init->tme_bus_cycle_size 329: - 1) < TME_SUN44C_MEMERR_SIZ_REG); 330: 331: /* if this is a write: */ 332: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { 333: 334: /* "The interrupt is held pending and the error information in 335: the memory error register is latched (frozen) until it is 336: cleared (unfrozen) by a write to bits <31..24> of the memory 337: error address register." */ 338: 339: /* see if this writes the vaddr or the CSR: */ 340: if (cycle_init->tme_bus_cycle_address & TME_SUN4_MEMERR_REG_VADDR) { 341: unlatch = 0; 342: } 343: else { 344: write_csr = 0; 345: } 346: } 347: } 348: 349: /* do the transfer: */ 350: tme_bus_cycle_xfer_memory(cycle_init, 1.1.1.2 ! root 351: (tme_uint8_t *) memerr_reg, 1.1 root 352: sizeof(memerr_reg) - 1); 353: 354: /* if this is a write: */ 355: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { 356: 357: /* if the sun4c parity control register has been written: */ 358: if (write_parctl >= 0) { 359: sun4->tme_sun4c_memerr_parctl[write_parctl] 1.1.1.2 ! root 360: = tme_betoh_u32(memerr_reg[write_parctl][TME_SUN4C_MEMERR_REG_PARCTL / sizeof(tme_uint32_t)]); 1.1 root 361: } 362: 363: /* if the sun4 vaddr register has been written: */ 364: if (TME_SUN4_IS_SUN4(sun4) 365: && unlatch) { 366: sun4->tme_sun4c_memerr_parctl[0] 1.1.1.2 ! root 367: = tme_betoh_u32(memerr_reg[0][TME_SUN4_MEMERR_REG_VADDR / sizeof(tme_uint32_t)]); 1.1 root 368: } 369: } 370: 371: /* assume that there are no CSR changes: */ 372: csr_old = csr_new = 0; 373: csr_ro = ~(TME_SUN44C_MEMERR_PAR_TEST 374: | TME_SUN44C_MEMERR_PAR_ENABLE 375: | (TME_SUN4_IS_SUN4C(sun4) 376: ? 0 377: : TME_SUN4_MEMERR_X_ENABLE_INT)); 378: 379: /* if a CSR register has been written: */ 380: if (write_csr >= 0) { 381: 382: /* get the new and old CSR values, preserving the read-only bits: */ 383: csr_old = sun4->tme_sun44c_memerr_csr[write_csr]; 1.1.1.2 ! root 384: csr_new = tme_betoh_u32(memerr_reg[write_csr][TME_SUN44C_MEMERR_REG_CSR / sizeof(tme_uint32_t)]); 1.1 root 385: csr_new = ((csr_old & csr_ro) 386: | (csr_new & ~csr_ro)); 387: } 388: 389: /* otherwise, if a CSR register has been unlatched: */ 390: else if (unlatch >= 0) { 391: 392: /* get the old and new CSR values, clearing the read-only bits: */ 393: csr_old = sun4->tme_sun44c_memerr_csr[unlatch]; 394: csr_new &= ~csr_ro; 395: write_csr = unlatch; 396: } 397: 398: /* if a CSR register has changed: */ 399: if (csr_new != csr_old) { 400: 401: /* see if the memory error registers were visible before: */ 402: visible_before = TME_SUN44C_MEMERR_VISIBLE(sun4); 403: 404: /* set the new CSR value and call out an interrupt change: */ 405: sun4->tme_sun44c_memerr_csr[write_csr] = csr_new; 406: _tme_sun44c_memerr_callout(sun4); 407: 408: /* if the write-inverse-parity testing feature is being enabled or 409: disabled: */ 410: if ((csr_new ^ csr_old) & TME_SUN44C_MEMERR_PAR_TEST) { 411: 412: /* if this feature is being enabled: */ 413: if (csr_new & TME_SUN44C_MEMERR_PAR_TEST) { 414: 415: /* if the memory error registers weren't visible before: */ 416: if (!visible_before) { 417: 418: /* the memory error registers are now visible: */ 419: assert (sun4->tme_sun4_memerr_bad_memory_count == 0); 420: 421: /* unless the cache is visible, update the TLB fill function: */ 422: if (!sun4->tme_sun4_cache_visible) { 423: sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_memerr; 424: } 425: 426: /* invalidate all TLBs: */ 427: tme_sun_mmu_tlbs_invalidate(sun4->tme_sun44c_mmu); 428: } 429: } 430: 431: /* otherwise, this feature is being disabled: */ 432: else { 433: 434: assert (visible_before); 435: 436: /* if the memory error registers are no longer visible: */ 437: if (!TME_SUN44C_MEMERR_VISIBLE(sun4)) { 438: 439: /* unless the cache is visible, update the TLB fill function: */ 440: if (!sun4->tme_sun4_cache_visible) { 441: sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_mmu; 442: } 443: 444: /* invalidate all TLBs: */ 445: tme_sun_mmu_tlbs_invalidate(sun4->tme_sun44c_mmu); 446: } 447: } 448: } 449: } 450: 451: return (TME_OK); 452: } 453: 454: /* the bus cycle handler for memory error testing: */ 455: int 456: _tme_sun44c_memerr_cycle_bus(void *_conn_bus_init, 457: struct tme_bus_cycle *cycle_init) 458: { 459: const struct tme_bus_connection *conn_bus_init; 460: struct tme_sun4 *sun4; 461: struct tme_bus_tlb *tlb; 462: tme_uint32_t address; 463: unsigned int cycle_size; 1.1.1.2 ! root 464: union { ! 465: tme_uint8_t memory_buffer_8s[sizeof(tme_uint32_t) / sizeof(tme_uint8_t)]; ! 466: tme_uint16_t memory_buffer_16s[sizeof(tme_uint32_t) / sizeof(tme_uint16_t)]; ! 467: tme_uint32_t memory_buffer_32s[sizeof(tme_uint32_t) / sizeof(tme_uint32_t)]; ! 468: } memory_buffer; 1.1 root 469: struct tme_sun_mmu_pte pte_mmu; 470: const tme_shared tme_uint8_t *memory_data_read; 471: tme_shared tme_uint8_t *memory_data_write; 472: int rc; 473: 474: /* recover our initiator's bus connection and sun4: */ 475: conn_bus_init = (struct tme_bus_connection *) _conn_bus_init; 476: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private; 477: 478: /* get the address and size for this cycle: */ 479: address = cycle_init->tme_bus_cycle_address; 480: cycle_size = cycle_init->tme_bus_cycle_size; 481: 482: /* recover the TLB entry for this cycle: */ 483: tlb = sun4->tme_sun4_memtest_tlb; 484: assert (tlb != NULL); 485: 486: /* busy the TLB entry that triggered this cycle: */ 487: tme_bus_tlb_busy(tlb); 488: 489: /* if the TLB entry is invalid, return now: */ 490: if (tme_bus_tlb_is_invalid(tlb)) { 491: 492: /* unbusy the TLB entry and return now: */ 493: tme_bus_tlb_unbusy(tlb); 494: return (EBADF); 495: } 496: 497: /* get the PTE for this address and context from the MMU: */ 498: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, 499: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init), 500: address, 501: &pte_mmu); 502: assert (rc == TME_OK); 503: 504: /* if this cycle is a read: */ 505: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) { 506: 507: /* get a pointer to the data to read: */ 508: memory_data_read 509: = (sun4->tme_sun4_memerr_tlb_emulator_off_read 510: + address); 511: 512: /* dispatch on the cycle size, to transfer the data from memory 513: into the memory buffer: */ 514: switch (cycle_size) { 515: default: 516: assert (FALSE); 517: /* FALLTHROUGH */ 518: case sizeof(tme_uint8_t): 1.1.1.2 ! root 519: memory_buffer.memory_buffer_8s[0] ! 520: = tme_memory_bus_read8(memory_data_read, ! 521: tlb->tme_bus_tlb_rwlock, ! 522: sizeof(tme_uint8_t), ! 523: sizeof(tme_uint32_t)); 1.1 root 524: break; 525: case sizeof(tme_uint16_t): 1.1.1.2 ! root 526: memory_buffer.memory_buffer_16s[0] ! 527: = tme_memory_bus_read16((const tme_shared tme_uint16_t *) memory_data_read, ! 528: tlb->tme_bus_tlb_rwlock, ! 529: sizeof(tme_uint16_t), ! 530: sizeof(tme_uint32_t)); 1.1 root 531: break; 532: case sizeof(tme_uint32_t): 1.1.1.2 ! root 533: memory_buffer.memory_buffer_32s[0] ! 534: = tme_memory_bus_read32((const tme_shared tme_uint32_t *) memory_data_read, ! 535: tlb->tme_bus_tlb_rwlock, ! 536: sizeof(tme_uint32_t), ! 537: sizeof(tme_uint32_t)); 1.1 root 538: break; 539: } 540: 541: /* run the bus cycle against the memory buffer: */ 542: tme_bus_cycle_xfer_memory(cycle_init, 1.1.1.2 ! root 543: &memory_buffer.memory_buffer_8s[0] - address, 1.1 root 544: address + cycle_size - 1); 545: assert (cycle_init->tme_bus_cycle_size == cycle_size); 546: 547: /* check for memory errors on this cache line fill: */ 548: rc = (_tme_sun44c_memerr_check(conn_bus_init, 549: address, 550: pte_mmu.tme_sun_mmu_pte_raw, 551: memory_data_read, 552: cycle_size) 553: ? EIO 554: : TME_OK); 555: } 556: 557: /* otherwise, this cycle must be a write: */ 558: else { 559: assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); 560: 561: /* run the bus cycle against the memory buffer: */ 562: tme_bus_cycle_xfer_memory(cycle_init, 1.1.1.2 ! root 563: &memory_buffer.memory_buffer_8s[0] - address, 1.1 root 564: address + cycle_size - 1); 565: assert (cycle_init->tme_bus_cycle_size == cycle_size); 566: 567: /* get a pointer to the data to write: */ 568: memory_data_write 569: = (sun4->tme_sun4_memerr_tlb_emulator_off_write 570: + address); 571: 572: /* dispatch on the cycle size, to transfer the data from the 573: memory buffer to memory: */ 574: switch (cycle_size) { 575: default: 576: assert (FALSE); 577: /* FALLTHROUGH */ 578: case sizeof(tme_uint8_t): 579: tme_memory_bus_write8(memory_data_write, 1.1.1.2 ! root 580: memory_buffer.memory_buffer_8s[0], 1.1 root 581: tlb->tme_bus_tlb_rwlock, 582: sizeof(tme_uint8_t), 583: sizeof(tme_uint32_t)); 584: break; 585: case sizeof(tme_uint16_t): 586: tme_memory_bus_write16((tme_shared tme_uint16_t *) memory_data_write, 1.1.1.2 ! root 587: memory_buffer.memory_buffer_16s[0], 1.1 root 588: tlb->tme_bus_tlb_rwlock, 589: sizeof(tme_uint16_t), 590: sizeof(tme_uint32_t)); 591: break; 592: case sizeof(tme_uint32_t): 593: tme_memory_bus_write32((tme_shared tme_uint32_t *) memory_data_write, 1.1.1.2 ! root 594: memory_buffer.memory_buffer_32s[0], 1.1 root 595: tlb->tme_bus_tlb_rwlock, 596: sizeof(tme_uint32_t), 597: sizeof(tme_uint32_t)); 598: break; 599: } 600: 601: /* add any memory errors caused by this write: */ 602: _tme_sun44c_memerr_update(sun4, 603: pte_mmu.tme_sun_mmu_pte_raw, 604: memory_data_write, 605: cycle_size); 606: rc = TME_OK; 607: } 608: 609: /* unbusy the TLB entry and invalidate it. this hurts performance, 610: since it keeps TLB entries valid only for one cycle at a time, 611: but it's simple and handles the problem of memory error testing 612: in the presence of virtual address aliases (addresses that have 613: never been written to can suddenly have read errors): */ 614: tme_bus_tlb_unbusy(tlb); 1.1.1.2 ! root 615: tme_token_invalidate(tlb->tme_bus_tlb_token); 1.1 root 616: sun4->tme_sun4_memtest_tlb = NULL; 617: 618: return (rc); 619: } 620: 621: /* this fills TLBs when memory error testing is visible: */ 622: int 623: _tme_sun44c_tlb_fill_memerr(const struct tme_bus_connection *conn_bus_init, 624: struct tme_bus_tlb *tlb, 625: tme_uint32_t *_asi_mask, 626: tme_uint32_t address, 627: unsigned int cycle_type) 628: { 629: struct tme_sun4 *sun4; 630: tme_uint32_t asi_mask; 631: struct tme_sun_mmu_pte pte_mmu; 632: int rc; 633: 634: /* recover our sun4: */ 635: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private; 636: 637: /* recover the ASI mask: */ 638: asi_mask = *_asi_mask; 639: 640: /* this ASI mask must be a single ASI, for user or supervisor 641: instruction or data: */ 642: assert (asi_mask == TME_SPARC32_ASI_MASK_UD 643: || asi_mask == TME_SPARC32_ASI_MASK_UI 644: || asi_mask == TME_SPARC32_ASI_MASK_SD 645: || asi_mask == TME_SPARC32_ASI_MASK_SI); 646: 647: /* invalidate any other memory test TLB entry: */ 648: if (sun4->tme_sun4_memtest_tlb != NULL 649: && sun4->tme_sun4_memtest_tlb != tlb) { 1.1.1.2 ! root 650: tme_token_invalidate(sun4->tme_sun4_memtest_tlb->tme_bus_tlb_token); 1.1 root 651: } 652: sun4->tme_sun4_memtest_tlb = NULL; 653: #ifndef NDEBUG 654: sun4->tme_sun4_memerr_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 655: sun4->tme_sun4_memerr_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 656: #endif /* !NDEBUG */ 657: 658: /* memory error testing must be active: */ 659: assert (TME_SUN44C_MEMERR_VISIBLE(sun4)); 660: 661: /* fill this TLB entry from the MMU: */ 662: rc = _tme_sun44c_tlb_fill_mmu(conn_bus_init, 663: tlb, 664: _asi_mask, 665: address, 666: cycle_type); 667: assert (rc == TME_OK); 668: 669: /* get the PTE for this address and context from the MMU: */ 670: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, 671: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init), 672: address, 673: &pte_mmu); 674: assert (rc == TME_OK); 675: 676: /* if this PTE is valid and for onboard memory: */ 677: if ((pte_mmu.tme_sun_mmu_pte_raw 678: & (TME_SUN44C_PTE_VALID 679: | TME_SUN44C_PTE_PGTYPE)) 680: == (TME_SUN44C_PTE_VALID 681: | 0 /* TME_SUN44C_PGTYPE_OBMEM */)) { 682: 683: /* this TLB entry should have no shift: */ 684: if (tlb->tme_bus_tlb_addr_shift != 0) { 685: abort(); 686: } 687: 688: /* if this is a read: */ 689: if (cycle_type == TME_BUS_CYCLE_READ) { 690: 691: /* invalidate this TLB entry for writes: */ 692: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 693: 694: /* if this TLB entry allows fast reading, and there are bad 695: memory addresses: */ 696: if (tlb->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF 697: && sun4->tme_sun4_memerr_bad_memory_count > 0) { 698: 699: /* we will handle this read: */ 700: sun4->tme_sun4_memerr_tlb_emulator_off_read = tlb->tme_bus_tlb_emulator_off_read; 701: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 702: tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init; 703: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus; 704: } 705: } 706: 707: /* otherwise, this must be a write: */ 708: else { 709: if (cycle_type != TME_BUS_CYCLE_WRITE) { 710: abort(); 711: } 712: 713: /* invalidate this TLB entry for reads: */ 714: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 715: 716: /* if this TLB entry allows fast writing: */ 717: if (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) { 718: 719: /* we will handle this write: */ 720: sun4->tme_sun4_memerr_tlb_emulator_off_write = tlb->tme_bus_tlb_emulator_off_write; 721: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 722: tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init; 723: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus; 724: } 725: } 726: 727: /* finish invalidating this TLB entry for the other cycle type: */ 728: assert (tlb->tme_bus_tlb_cycles_ok & cycle_type); 729: tlb->tme_bus_tlb_cycles_ok = cycle_type; 730: tlb->tme_bus_tlb_addr_offset = 0; 731: } 732: 733: /* remember this TLB entry: */ 734: sun4->tme_sun4_memtest_tlb = tlb; 735: 736: /* return success: */ 737: return (TME_OK); 738: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.