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

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

unix.superglobalmegacorp.com

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