|
|
1.1 ! root 1: /* $Id: sun44c-memerr.c,v 1.1 2006/09/30 12:56:00 fredette Exp $ */ ! 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> ! 37: _TME_RCSID("$Id: sun44c-memerr.c,v 1.1 2006/09/30 12:56:00 fredette Exp $"); ! 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; ! 253: tme_uint8_t memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 2]; ! 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): */ ! 265: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN44C_MEMERR_REG_CSR]) ! 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: */ ! 283: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN4C_MEMERR_REG_PARCTL]) ! 284: = tme_htobe_u32(sun4->tme_sun4c_memerr_parctl[0]); ! 285: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 1 + TME_SUN44C_MEMERR_REG_CSR]) ! 286: = tme_htobe_u32(sun4->tme_sun44c_memerr_csr[1]); ! 287: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 1 + TME_SUN4C_MEMERR_REG_PARCTL]) ! 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: */ ! 324: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN4_MEMERR_REG_VADDR]) ! 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, ! 351: memerr_reg, ! 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] ! 360: = tme_betoh_u32(*((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * write_parctl + TME_SUN4C_MEMERR_REG_PARCTL])); ! 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] ! 367: = tme_betoh_u32(*((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN4_MEMERR_REG_VADDR])); ! 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]; ! 384: csr_new = tme_betoh_u32(*((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * write_csr + TME_SUN44C_MEMERR_REG_CSR])); ! 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; ! 464: tme_uint8_t memory_buffer[sizeof(tme_uint32_t)]; ! 465: struct tme_sun_mmu_pte pte_mmu; ! 466: const tme_shared tme_uint8_t *memory_data_read; ! 467: tme_shared tme_uint8_t *memory_data_write; ! 468: int rc; ! 469: ! 470: /* recover our initiator's bus connection and sun4: */ ! 471: conn_bus_init = (struct tme_bus_connection *) _conn_bus_init; ! 472: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private; ! 473: ! 474: /* get the address and size for this cycle: */ ! 475: address = cycle_init->tme_bus_cycle_address; ! 476: cycle_size = cycle_init->tme_bus_cycle_size; ! 477: ! 478: /* recover the TLB entry for this cycle: */ ! 479: tlb = sun4->tme_sun4_memtest_tlb; ! 480: assert (tlb != NULL); ! 481: ! 482: /* busy the TLB entry that triggered this cycle: */ ! 483: tme_bus_tlb_busy(tlb); ! 484: ! 485: /* if the TLB entry is invalid, return now: */ ! 486: if (tme_bus_tlb_is_invalid(tlb)) { ! 487: ! 488: /* unbusy the TLB entry and return now: */ ! 489: tme_bus_tlb_unbusy(tlb); ! 490: return (EBADF); ! 491: } ! 492: ! 493: /* get the PTE for this address and context from the MMU: */ ! 494: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, ! 495: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init), ! 496: address, ! 497: &pte_mmu); ! 498: assert (rc == TME_OK); ! 499: ! 500: /* if this cycle is a read: */ ! 501: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) { ! 502: ! 503: /* get a pointer to the data to read: */ ! 504: memory_data_read ! 505: = (sun4->tme_sun4_memerr_tlb_emulator_off_read ! 506: + address); ! 507: ! 508: /* dispatch on the cycle size, to transfer the data from memory ! 509: into the memory buffer: */ ! 510: switch (cycle_size) { ! 511: default: ! 512: assert (FALSE); ! 513: /* FALLTHROUGH */ ! 514: case sizeof(tme_uint8_t): ! 515: tme_memory_write8(&memory_buffer[0], ! 516: tme_memory_bus_read8(memory_data_read, ! 517: tlb->tme_bus_tlb_rwlock, ! 518: sizeof(tme_uint8_t), ! 519: sizeof(tme_uint32_t)), ! 520: sizeof(tme_uint32_t)); ! 521: break; ! 522: case sizeof(tme_uint16_t): ! 523: tme_memory_write16((tme_uint16_t *) &memory_buffer[0], ! 524: tme_memory_bus_read16((const tme_shared tme_uint16_t *) memory_data_read, ! 525: tlb->tme_bus_tlb_rwlock, ! 526: sizeof(tme_uint16_t), ! 527: sizeof(tme_uint32_t)), ! 528: sizeof(tme_uint32_t)); ! 529: break; ! 530: case sizeof(tme_uint32_t): ! 531: tme_memory_write32((tme_uint32_t *) &memory_buffer[0], ! 532: tme_memory_bus_read32((const tme_shared tme_uint32_t *) memory_data_read, ! 533: tlb->tme_bus_tlb_rwlock, ! 534: sizeof(tme_uint32_t), ! 535: sizeof(tme_uint32_t)), ! 536: sizeof(tme_uint32_t)); ! 537: break; ! 538: } ! 539: ! 540: /* run the bus cycle against the memory buffer: */ ! 541: tme_bus_cycle_xfer_memory(cycle_init, ! 542: &memory_buffer[0] - address, ! 543: address + cycle_size - 1); ! 544: assert (cycle_init->tme_bus_cycle_size == cycle_size); ! 545: ! 546: /* check for memory errors on this cache line fill: */ ! 547: rc = (_tme_sun44c_memerr_check(conn_bus_init, ! 548: address, ! 549: pte_mmu.tme_sun_mmu_pte_raw, ! 550: memory_data_read, ! 551: cycle_size) ! 552: ? EIO ! 553: : TME_OK); ! 554: } ! 555: ! 556: /* otherwise, this cycle must be a write: */ ! 557: else { ! 558: assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); ! 559: ! 560: /* run the bus cycle against the memory buffer: */ ! 561: tme_bus_cycle_xfer_memory(cycle_init, ! 562: &memory_buffer[0] - address, ! 563: address + cycle_size - 1); ! 564: assert (cycle_init->tme_bus_cycle_size == cycle_size); ! 565: ! 566: /* get a pointer to the data to write: */ ! 567: memory_data_write ! 568: = (sun4->tme_sun4_memerr_tlb_emulator_off_write ! 569: + address); ! 570: ! 571: /* dispatch on the cycle size, to transfer the data from the ! 572: memory buffer to memory: */ ! 573: switch (cycle_size) { ! 574: default: ! 575: assert (FALSE); ! 576: /* FALLTHROUGH */ ! 577: case sizeof(tme_uint8_t): ! 578: tme_memory_bus_write8(memory_data_write, ! 579: tme_memory_read8(&memory_buffer[0], ! 580: sizeof(tme_uint8_t)), ! 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, ! 587: tme_memory_read16((tme_uint16_t *) &memory_buffer[0], ! 588: sizeof(tme_uint16_t)), ! 589: tlb->tme_bus_tlb_rwlock, ! 590: sizeof(tme_uint16_t), ! 591: sizeof(tme_uint32_t)); ! 592: break; ! 593: case sizeof(tme_uint32_t): ! 594: tme_memory_bus_write32((tme_shared tme_uint32_t *) memory_data_write, ! 595: tme_memory_read32((tme_uint32_t *) &memory_buffer[0], ! 596: sizeof(tme_uint32_t)), ! 597: tlb->tme_bus_tlb_rwlock, ! 598: sizeof(tme_uint32_t), ! 599: sizeof(tme_uint32_t)); ! 600: break; ! 601: } ! 602: ! 603: /* add any memory errors caused by this write: */ ! 604: _tme_sun44c_memerr_update(sun4, ! 605: pte_mmu.tme_sun_mmu_pte_raw, ! 606: memory_data_write, ! 607: cycle_size); ! 608: rc = TME_OK; ! 609: } ! 610: ! 611: /* unbusy the TLB entry and invalidate it. this hurts performance, ! 612: since it keeps TLB entries valid only for one cycle at a time, ! 613: but it's simple and handles the problem of memory error testing ! 614: in the presence of virtual address aliases (addresses that have ! 615: never been written to can suddenly have read errors): */ ! 616: tme_bus_tlb_unbusy(tlb); ! 617: tme_bus_tlb_invalidate(tlb); ! 618: sun4->tme_sun4_memtest_tlb = NULL; ! 619: ! 620: return (rc); ! 621: } ! 622: ! 623: /* this fills TLBs when memory error testing is visible: */ ! 624: int ! 625: _tme_sun44c_tlb_fill_memerr(const struct tme_bus_connection *conn_bus_init, ! 626: struct tme_bus_tlb *tlb, ! 627: tme_uint32_t *_asi_mask, ! 628: tme_uint32_t address, ! 629: unsigned int cycle_type) ! 630: { ! 631: struct tme_sun4 *sun4; ! 632: tme_uint32_t asi_mask; ! 633: struct tme_sun_mmu_pte pte_mmu; ! 634: int rc; ! 635: ! 636: /* recover our sun4: */ ! 637: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private; ! 638: ! 639: /* recover the ASI mask: */ ! 640: asi_mask = *_asi_mask; ! 641: ! 642: /* this ASI mask must be a single ASI, for user or supervisor ! 643: instruction or data: */ ! 644: assert (asi_mask == TME_SPARC32_ASI_MASK_UD ! 645: || asi_mask == TME_SPARC32_ASI_MASK_UI ! 646: || asi_mask == TME_SPARC32_ASI_MASK_SD ! 647: || asi_mask == TME_SPARC32_ASI_MASK_SI); ! 648: ! 649: /* invalidate any other memory test TLB entry: */ ! 650: if (sun4->tme_sun4_memtest_tlb != NULL ! 651: && sun4->tme_sun4_memtest_tlb != tlb) { ! 652: tme_bus_tlb_invalidate(sun4->tme_sun4_memtest_tlb); ! 653: } ! 654: sun4->tme_sun4_memtest_tlb = NULL; ! 655: #ifndef NDEBUG ! 656: sun4->tme_sun4_memerr_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; ! 657: sun4->tme_sun4_memerr_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; ! 658: #endif /* !NDEBUG */ ! 659: ! 660: /* memory error testing must be active: */ ! 661: assert (TME_SUN44C_MEMERR_VISIBLE(sun4)); ! 662: ! 663: /* fill this TLB entry from the MMU: */ ! 664: rc = _tme_sun44c_tlb_fill_mmu(conn_bus_init, ! 665: tlb, ! 666: _asi_mask, ! 667: address, ! 668: cycle_type); ! 669: assert (rc == TME_OK); ! 670: ! 671: /* get the PTE for this address and context from the MMU: */ ! 672: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, ! 673: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init), ! 674: address, ! 675: &pte_mmu); ! 676: assert (rc == TME_OK); ! 677: ! 678: /* if this PTE is valid and for onboard memory: */ ! 679: if ((pte_mmu.tme_sun_mmu_pte_raw ! 680: & (TME_SUN44C_PTE_VALID ! 681: | TME_SUN44C_PTE_PGTYPE)) ! 682: == (TME_SUN44C_PTE_VALID ! 683: | 0 /* TME_SUN44C_PGTYPE_OBMEM */)) { ! 684: ! 685: /* this TLB entry should have no shift: */ ! 686: if (tlb->tme_bus_tlb_addr_shift != 0) { ! 687: abort(); ! 688: } ! 689: ! 690: /* if this is a read: */ ! 691: if (cycle_type == TME_BUS_CYCLE_READ) { ! 692: ! 693: /* invalidate this TLB entry for writes: */ ! 694: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; ! 695: ! 696: /* if this TLB entry allows fast reading, and there are bad ! 697: memory addresses: */ ! 698: if (tlb->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF ! 699: && sun4->tme_sun4_memerr_bad_memory_count > 0) { ! 700: ! 701: /* we will handle this read: */ ! 702: sun4->tme_sun4_memerr_tlb_emulator_off_read = tlb->tme_bus_tlb_emulator_off_read; ! 703: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; ! 704: tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init; ! 705: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus; ! 706: } ! 707: } ! 708: ! 709: /* otherwise, this must be a write: */ ! 710: else { ! 711: if (cycle_type != TME_BUS_CYCLE_WRITE) { ! 712: abort(); ! 713: } ! 714: ! 715: /* invalidate this TLB entry for reads: */ ! 716: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; ! 717: ! 718: /* if this TLB entry allows fast writing: */ ! 719: if (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) { ! 720: ! 721: /* we will handle this write: */ ! 722: sun4->tme_sun4_memerr_tlb_emulator_off_write = tlb->tme_bus_tlb_emulator_off_write; ! 723: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; ! 724: tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init; ! 725: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus; ! 726: } ! 727: } ! 728: ! 729: /* finish invalidating this TLB entry for the other cycle type: */ ! 730: assert (tlb->tme_bus_tlb_cycles_ok & cycle_type); ! 731: tlb->tme_bus_tlb_cycles_ok = cycle_type; ! 732: tlb->tme_bus_tlb_addr_offset = 0; ! 733: } ! 734: ! 735: /* remember this TLB entry: */ ! 736: sun4->tme_sun4_memtest_tlb = tlb; ! 737: ! 738: /* return success: */ ! 739: return (TME_OK); ! 740: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.