Annotation of tme/machine/sun4/sun44c-memerr.c, revision 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.