Annotation of tme/machine/sun4/sun44c-memerr.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.