Annotation of tme/generic/bus.c, revision 1.1.1.2

1.1.1.2 ! root        1: /* $Id: bus.c,v 1.5 2003/10/16 02:48:18 fredette Exp $ */
1.1       root        2: 
                      3: /* generic/gen-bus.c - generic bus support: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2003 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: bus.c,v 1.5 2003/10/16 02:48:18 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
                     40: #include <tme/generic/bus.h>
                     41: #include <stdlib.h>
                     42: #include <string.h>
                     43: 
                     44: /* this does a binary search of the addressable connections: */
                     45: int
                     46: tme_bus_address_search(struct tme_bus *bus, tme_bus_addr_t address)
                     47: {
                     48:   int left, right, pivot;
                     49:   struct tme_bus_connection_int *conn_int;
1.1.1.2 ! root       50:   const struct tme_bus_subregion *subregion;
1.1       root       51: 
                     52:   /* initialize for the search: */
                     53:   left = 0;
                     54:   right = bus->tme_bus_addressables_count - 1;
                     55:   
                     56:   /* do the search: */
                     57:   pivot = 0;
                     58:   for (; left <= right; ) {
                     59: 
                     60:     /* get the pivot: */
                     61:     pivot = (left + right) / 2;
1.1.1.2 ! root       62:     conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection;
        !            63:     subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion;
1.1       root       64: 
                     65:     /* if we have to move left: */
1.1.1.2 ! root       66:     if (address
        !            67:        < (conn_int->tme_bus_connection_int_address
        !            68:           + subregion->tme_bus_subregion_address_first)) {
1.1       root       69:       /* if we're done searching, pivot is already the index of the
                     70:         first element we need to shift to the right in order to
                     71:         insert a new element: */
                     72:       right = pivot - 1;
                     73:     }
                     74: 
                     75:     /* if we have to move right: */
1.1.1.2 ! root       76:     else if (address
        !            77:             > (conn_int->tme_bus_connection_int_address
        !            78:                + subregion->tme_bus_subregion_address_last)) {
1.1       root       79:       /* if we're done searching, pivot + 1 is the index of the
                     80:         first element we need to shift to the right in order to
                     81:         insert a new element: */
                     82:       left = ++pivot;
                     83:     }
                     84: 
                     85:     /* we found the addressable: */
                     86:     else {
                     87:       return (pivot);
                     88:     }
                     89:   }
                     90: 
                     91:   /* we failed to find an addressable that covers the address: */
                     92:   return (-1 - pivot);
                     93: }
                     94: 
                     95: /* this fills a TLB entry: */
                     96: int
                     97: tme_bus_tlb_fill(struct tme_bus *bus,
                     98:                 struct tme_bus_connection_int *conn_int_asker,
                     99:                 struct tme_bus_tlb *tlb,
                    100:                 tme_bus_addr_t address, 
                    101:                 unsigned int cycles)
                    102: {
                    103:   int pivot;
                    104:   struct tme_bus_connection_int *conn_int;
1.1.1.2 ! root      105:   const struct tme_bus_subregion *subregion;
1.1       root      106:   struct tme_bus_connection *conn_bus_other;
                    107:   tme_bus_addr_t sourced_address_mask, conn_address;
                    108:   tme_bus_addr_t hole_first, hole_last;
                    109:   struct tme_bus_tlb tlb_bus;
                    110:   void *cycle_fault_private;
                    111:   tme_bus_cycle_handler cycle_fault;
                    112:   int rc;
                    113: 
                    114:   /* get the sourced address mask: */
                    115:   sourced_address_mask = conn_int_asker->tme_bus_connection_int_sourced;
                    116: 
                    117:   /* search for this address on the bus: */
                    118:   pivot = tme_bus_address_search(bus, sourced_address_mask | address);
                    119: 
                    120:   /* if this address doesn't exist: */
                    121:   if (pivot < 0) {
                    122: 
                    123:     /* save the bus' fault cycle handler: */
                    124:     cycle_fault_private = tlb->tme_bus_tlb_cycle_private;
                    125:     cycle_fault = tlb->tme_bus_tlb_cycle;
                    126: 
                    127:     /* initialize the TLB entry: */
                    128:     tme_bus_tlb_initialize(tlb);
                    129: 
                    130:     /* this TLB entry can cover the entire hole in the address space,
                    131:        limited by the sourced address mask of this device: */
                    132:     pivot = -1 - pivot;
                    133:     hole_first = (pivot == 0
                    134:                  ? 0
1.1.1.2 ! root      135:                  : ((bus->tme_bus_addressables[pivot - 1]
        !           136:                      .tme_bus_addressable_connection->tme_bus_connection_int_address)
        !           137:                     + (bus->tme_bus_addressables[pivot - 1]
        !           138:                        .tme_bus_addressable_subregion->tme_bus_subregion_address_last)
1.1       root      139:                     + 1));
                    140:     hole_first = TME_MAX(hole_first, sourced_address_mask);
                    141:     hole_last = (pivot == bus->tme_bus_addressables_count
                    142:                 ? bus->tme_bus_address_mask
1.1.1.2 ! root      143:                 : ((bus->tme_bus_addressables[pivot]
        !           144:                     .tme_bus_addressable_connection->tme_bus_connection_int_address)
        !           145:                    - 1));
1.1       root      146:     hole_last = TME_MIN(hole_last,
                    147:                        sourced_address_mask
                    148:                        + conn_int_asker->tme_bus_connection_int_address_last);
                    149:     TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, hole_first);
                    150:     TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, hole_last);
                    151: 
                    152:     /* reads and writes are allowed: */
                    153:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    154: 
                    155:     /* reads and writes in this region always fault: */
                    156:     tlb->tme_bus_tlb_cycle_private = cycle_fault_private;
                    157:     tlb->tme_bus_tlb_cycle = cycle_fault;
                    158:     rc = TME_OK;
                    159:   }
                    160: 
                    161:   /* otherwise, this address does exist: */
                    162:   else {
1.1.1.2 ! root      163:     conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection;
        !           164:     subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion;
1.1       root      165:     conn_bus_other = 
                    166:       (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other;
                    167: 
                    168:     /* call the TLB fill function for the connection: */
                    169:     conn_address = (sourced_address_mask | address) - conn_int->tme_bus_connection_int_address;
                    170:     rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb,
                    171:                                             conn_address, cycles);
                    172: 
                    173:     /* if that succeeded: */
                    174:     if (rc == TME_OK) {
                    175:       
                    176:       /* create the mapping TLB entry: */
                    177:       TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_bus.tme_bus_tlb_addr_first, 
                    178:                       (conn_int->tme_bus_connection_int_address
1.1.1.2 ! root      179:                        + subregion->tme_bus_subregion_address_first
1.1       root      180:                        - sourced_address_mask));
                    181:       TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_bus.tme_bus_tlb_addr_last, 
                    182:                       (conn_int->tme_bus_connection_int_address
1.1.1.2 ! root      183:                        + subregion->tme_bus_subregion_address_last
1.1       root      184:                        - sourced_address_mask));
                    185:       tlb_bus.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    186:   
                    187:       /* map the filled TLB entry: */
                    188:       tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address);
                    189:     }
                    190:   }
                    191: 
                    192:   /* done: */
                    193:   return (rc);
                    194: }
                    195: 
                    196: /* this allocates a new TLB set: */
                    197: int
                    198: tme_bus_tlb_set_allocate(struct tme_bus *bus,
                    199:                         struct tme_bus_connection_int *conn_int_asker,
                    200:                         unsigned int count, unsigned int sizeof_one, 
                    201:                         TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs)
                    202: {
                    203:   struct tme_bus_connection *conn_bus_other, *conn_bus_dma;
                    204:   int conn_int_i;
                    205:   int rc;
                    206:   struct tme_bus_tlb *tlbs, *tlb;
                    207:   unsigned int tlb_i;
                    208: 
                    209:   /* at most one of our addressable connections may provide a TLB set
                    210:      allocator.  generally, this means that connection is
                    211:      DMA-controller-like connection to the bus, where it may need to
                    212:      invalidate at any later time the TLBs it fills out, due to sudden
                    213:      changes in how the DMA region on the bus is mapped: */
                    214:   conn_bus_dma = NULL;
                    215:   for (conn_int_i = 0;
                    216:        conn_int_i < bus->tme_bus_addressables_count;
                    217:        conn_int_i++) {
                    218:     conn_bus_other = 
1.1.1.2 ! root      219:       ((struct tme_bus_connection *)
        !           220:        bus->tme_bus_addressables[conn_int_i].tme_bus_addressable_connection
        !           221:        ->tme_bus_connection_int.tme_bus_connection.tme_connection_other);
1.1       root      222: 
                    223:     /* if this bus connection offers a TLB set allocator, it is
                    224:        a DMA-controller-like connection to the bus: */
                    225:     if (conn_bus_other->tme_bus_tlb_set_allocate != NULL) {
                    226: 
                    227:       /* if there is more than one of these, it is likely a
                    228:         configuration error.  if we had some way of specifying which
                    229:         of several DMA regions a given connection will always use, we
                    230:         could avoid this: */
                    231:       if (conn_bus_dma != NULL) {
                    232:        abort();
                    233:       }
                    234: 
                    235:       conn_bus_dma = conn_bus_other;
                    236:     }
                    237:   }
                    238: 
                    239:   /* if there is a DMA-controller-like connection to the bus, 
                    240:      let it allocate the TLB set: */
                    241:   if (conn_bus_dma != NULL) {
                    242:     rc = (*conn_bus_dma->tme_bus_tlb_set_allocate)
                    243:       (conn_bus_dma, count, sizeof_one, _tlbs);
                    244:   }
                    245: 
                    246:   /* otherwise, allocate and initialize a singleton set ourselves: */
                    247:   else {
                    248:     tlbs = (struct tme_bus_tlb *) tme_malloc(count * sizeof_one);
                    249:     tlb = tlbs;
                    250:     for (tlb_i = 0; tlb_i < count; tlb_i++) {
                    251:       tme_bus_tlb_invalidate(tlb);
                    252:       tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one);
                    253:     }
                    254:     TME_ATOMIC_WRITE(struct tme_bus_tlb *, *_tlbs, tlbs);
                    255:     rc = TME_OK;
                    256:   }
                    257:       
                    258:   /* done: */
                    259:   return (rc);
                    260: }
                    261: 
                    262: /* this returns nonzero if the connection's address space is available: */
                    263: int
                    264: tme_bus_connection_ok(struct tme_bus *bus,
                    265:                      struct tme_bus_connection_int *conn_int)
                    266: {
1.1.1.2 ! root      267:   const struct tme_bus_subregion *subregion;
        !           268:   const struct tme_bus_connection *conn_bus_other;
1.1       root      269:   int pivot_start, pivot_end;
                    270: 
                    271:   /* if this connection isn't addressable, it's always OK: */
                    272:   if (!conn_int->tme_bus_connection_int_addressable) {
                    273:     return (TRUE);
                    274:   }
                    275: 
1.1.1.2 ! root      276:   /* all subregions of this connection must fit on the bus,
        !           277:      and they must not overlap with any other subregion on 
        !           278:      any other existing connection: */
        !           279:   /* XXX we should also check that the connection's subregions don't
        !           280:      overlap with each other: */
        !           281:   conn_bus_other
        !           282:     = ((struct tme_bus_connection *)
        !           283:        conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other);
        !           284:   for (subregion = &conn_bus_other->tme_bus_subregions;
        !           285:        subregion != NULL;
        !           286:        subregion = subregion->tme_bus_subregion_next) {
        !           287: 
        !           288:     /* the subregion's last address cannot be less than
        !           289:        the first address: */
        !           290:     if (subregion->tme_bus_subregion_address_last
        !           291:        < subregion->tme_bus_subregion_address_first) {
        !           292:       return (FALSE);
        !           293:     }
        !           294:     
        !           295:     /* this subregion must fit on the bus: */
        !           296:     if (subregion->tme_bus_subregion_address_last >
        !           297:        (bus->tme_bus_address_mask
        !           298:         - conn_int->tme_bus_connection_int_address)) {
        !           299:       return (FALSE);
        !           300:     }
        !           301: 
        !           302:     /* search for anything covering the start or end of the new
        !           303:        addressable subregion: */
        !           304:     pivot_start = 
        !           305:       tme_bus_address_search(bus, 
        !           306:                             (conn_int->tme_bus_connection_int_address
        !           307:                              + subregion->tme_bus_subregion_address_first));
        !           308:     pivot_end =
        !           309:       tme_bus_address_search(bus,
        !           310:                             (conn_int->tme_bus_connection_int_address
        !           311:                              + subregion->tme_bus_subregion_address_last));
        !           312: 
        !           313:     /* both searches must have failed, and they must have stopped at the
        !           314:        same point in the sorted addressables, further indicating that no
        !           315:        addressable exists anywhere *between* the start and end of the
        !           316:        new addressable, either.  otherwise, this connection fails: */
        !           317:     if (pivot_start >= 0
        !           318:        || pivot_end >= 0
        !           319:        || pivot_start != pivot_end) {
        !           320:       return (FALSE);
        !           321:     }
1.1       root      322:   }
                    323: 
                    324:   /* this connection's address space is available: */
                    325:   return (TRUE);
                    326: }
                    327: 
                    328: /* this makes a new connection: */
                    329: int
                    330: tme_bus_connection_make(struct tme_bus *bus,
                    331:                        struct tme_bus_connection_int *conn_int,
                    332:                        unsigned int state)
                    333: {
1.1.1.2 ! root      334:   const struct tme_bus_connection *conn_bus_other;
        !           335:   const struct tme_bus_subregion *subregion;
1.1       root      336:   int pivot;
                    337: 
                    338:   /* if this connection is not full, return now: */
                    339:   if (state == TME_CONNECTION_HALF) {
                    340:     return (TME_OK);
                    341:   }
                    342: 
                    343:   /* add this connection to our list: */
                    344:   conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_next
                    345:     = (struct tme_connection *) bus->tme_bus_connections;
                    346:   bus->tme_bus_connections = conn_int;
                    347: 
                    348:   /* if this connection is addressable, and this is connection is now
                    349:      fully made, add it to our list of addressables: */
                    350:   if (conn_int->tme_bus_connection_int_addressable
                    351:       && state == TME_CONNECTION_FULL) {
                    352:     
1.1.1.2 ! root      353:     /* add all subregions of this connection as addressables: */
        !           354:     conn_int->tme_bus_connection_int_address_last = 0;
        !           355:     conn_bus_other
        !           356:       = ((struct tme_bus_connection *)
        !           357:         conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other);
        !           358:     for (subregion = &conn_bus_other->tme_bus_subregions;
        !           359:         subregion != NULL;
        !           360:         subregion = subregion->tme_bus_subregion_next) {
        !           361: 
        !           362:       /* search for the place to insert this new addressable: */
        !           363:       pivot = tme_bus_address_search(bus, 
        !           364:                                     (conn_int->tme_bus_connection_int_address
        !           365:                                      + subregion->tme_bus_subregion_address_first));
        !           366:       assert(pivot < 0);
        !           367:       pivot = -1 - pivot;
1.1       root      368:     
1.1.1.2 ! root      369:       /* if we have to, grow the addressable array: */
        !           370:       if (bus->tme_bus_addressables_count
        !           371:          == bus->tme_bus_addressables_size) {
        !           372:        bus->tme_bus_addressables_size += (bus->tme_bus_addressables_size >> 1) + 1;
        !           373:        bus->tme_bus_addressables = tme_renew(struct tme_bus_addressable,
        !           374:                                              bus->tme_bus_addressables,
        !           375:                                              bus->tme_bus_addressables_size);
        !           376:       }
        !           377: 
        !           378:       /* move all of the later addressables down: */
        !           379:       memmove(&bus->tme_bus_addressables[pivot + 1],
        !           380:              &bus->tme_bus_addressables[pivot],
        !           381:              sizeof(bus->tme_bus_addressables[pivot])
        !           382:              * (bus->tme_bus_addressables_count
        !           383:                 - pivot));
        !           384: 
        !           385:       /* insert this new addressable: */
        !           386:       bus->tme_bus_addressables[pivot].tme_bus_addressable_connection = conn_int;
        !           387:       bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion = subregion;
        !           388:       bus->tme_bus_addressables_count++;
        !           389: 
        !           390:       /* update the last address on this connection.  NB that the
        !           391:         subregion information should be used almost always.
        !           392:         currently this value is only used as the width of the
        !           393:         connection for the purposes of determining TLB entry limits
        !           394:         when the connection itself asks to fill a TLB entry: */
        !           395:       conn_int->tme_bus_connection_int_address_last
        !           396:        = TME_MAX(conn_int->tme_bus_connection_int_address_last,
        !           397:                  subregion->tme_bus_subregion_address_last);
        !           398:     }
1.1       root      399:   }
                    400: 
                    401:   return (TME_OK);
                    402: }
                    403: 
                    404: /* this breaks a connection: */
                    405: int
                    406: tme_bus_connection_break(struct tme_bus *bus,
                    407:                         struct tme_bus_connection_int *conn_int,
                    408:                         unsigned int state)
                    409: {
                    410:   abort();
                    411: }
                    412: 
                    413: /* this map the first bus TLB entry to be valid on another bus, according to
                    414:    the information in the second bus TLB entry: */
                    415: void
                    416: tme_bus_tlb_map(struct tme_bus_tlb *tlb0, tme_bus_addr_t addr0, 
                    417:                const struct tme_bus_tlb *tlb1, tme_bus_addr_t addr1)
                    418: {
                    419:   tme_bus_addr_t extra_before0, extra_after0;
                    420:   tme_bus_addr_t extra_before1, extra_after1;
                    421:   tme_bus_addr_t addr_offset;
                    422:   unsigned int cycles_ok;
                    423: 
                    424:   /* get the address offset: */
                    425:   addr_offset = addr1 - addr0;
                    426: 
                    427:   /* intersect the amount of bus address space covered: */
                    428:   extra_before0 = addr0 - TME_ATOMIC_READ(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_first);
                    429:   extra_after0 = TME_ATOMIC_READ(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_last) - addr0;
                    430:   extra_before1 = addr1 - TME_ATOMIC_READ(tme_bus_addr_t, tlb1->tme_bus_tlb_addr_first);
                    431:   extra_after1 = TME_ATOMIC_READ(tme_bus_addr_t, tlb1->tme_bus_tlb_addr_last) - addr1;
                    432:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_first, 
                    433:                   addr1 - TME_MIN(extra_before0, extra_before1));
                    434:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_last, 
                    435:                   addr1 + TME_MIN(extra_after0, extra_after1));
                    436: 
                    437:   /* intersect the kinds of bus cycles allowed: */
                    438:   cycles_ok = (tlb0->tme_bus_tlb_cycles_ok &= tlb1->tme_bus_tlb_cycles_ok);
                    439:   if (!(cycles_ok & TME_BUS_CYCLE_READ)) {
                    440:     tlb0->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
                    441:   }
                    442:   else if (tlb0->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF) {
                    443:     tlb0->tme_bus_tlb_emulator_off_read -= addr_offset;
                    444:   }
                    445:   if (!(cycles_ok & TME_BUS_CYCLE_WRITE)) {
                    446:     tlb0->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
                    447:   }
                    448:   else if (tlb0->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
                    449:     tlb0->tme_bus_tlb_emulator_off_write -= addr_offset;
                    450:   }
                    451: 
                    452:   /* update the address shift for the cycle handler: */
                    453:   tlb0->tme_bus_tlb_addr_offset -= addr_offset;
                    454: }
                    455: 
                    456: /* this invalidates a bus TLB entry: */
                    457: void
                    458: tme_bus_tlb_invalidate(struct tme_bus_tlb *tlb)
                    459: {
                    460:   
                    461:   /* make the first address covered all-bits-one.  the only bus TLB
                    462:      entries this will not invalidate are those that have a last
                    463:      address covered of all-bits one: */
                    464:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, -1);
                    465:   
                    466:   /* make the last address covered all-bits-zero.  this will
                    467:      invalidate the TLB entries we didn't catch above: */
                    468:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, 0);
                    469: }
                    470: 
                    471: /* this initializes a bus TLB entry: */
                    472: void
                    473: tme_bus_tlb_initialize(struct tme_bus_tlb *tlb)
                    474: {
                    475:   
                    476:   /* make the first address covered all-bits-one: */
                    477:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, -1);
                    478:   
                    479:   /* make the last address covered all-bits-zero: */
                    480:   TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, 0);
                    481: 
                    482:   /* no fast (memory) transfers allowed: */
                    483:   tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
                    484:   tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
                    485:   tlb->tme_bus_tlb_rwlock = NULL;
                    486: 
                    487:   /* no bus cycles allowed: */
                    488:   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_UNDEF;
                    489: 
                    490:   /* no address offset or shift: */
                    491:   tlb->tme_bus_tlb_addr_offset = 0;
                    492:   tlb->tme_bus_tlb_addr_shift = 0;
                    493: 
                    494:   /* no bus cycle handler: */
                    495:   tlb->tme_bus_tlb_cycle_private = NULL;
                    496:   tlb->tme_bus_tlb_cycle = NULL;
                    497: 
                    498:   /* no bus fault handlers: */
                    499:   tlb->tme_bus_tlb_fault_handler_count = 0;
                    500: }
                    501: 
                    502: /* this calls a TLB entry's fault handlers: */
                    503: int
                    504: tme_bus_tlb_fault(struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    505: {
                    506:   unsigned int i;
                    507: 
                    508:   /* call all of the fault handlers: */
                    509:   for (i = 0; i < tlb->tme_bus_tlb_fault_handler_count; i++) {
                    510:     rc = ((*tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler)
                    511:          (tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler_private,
                    512:           tlb, cycle, rc));
                    513:   }
                    514: 
                    515:   return (rc);
                    516: }
                    517: 
                    518: /* this parses any bus address: */
                    519: tme_bus_addr_t
                    520: tme_bus_addr_parse_any(const char *address_string, int *_failed)
                    521: {
                    522:   unsigned long address;
                    523:   char *units;
                    524: 
                    525:   /* catch a NULL string: */
                    526:   if (address_string == NULL) {
                    527:     *_failed = TRUE;
                    528:     return (0);
                    529:   }
                    530: 
                    531:   /* assume we will succeed: */
                    532:   *_failed = FALSE;
                    533: 
                    534:   /* convert the string: */
                    535:   address = strtoul(address_string, &units, 0);
                    536:   if (units == address_string) {
                    537:     *_failed = TRUE;
                    538:     return (0);
                    539:   }
                    540: 
                    541:   /* handle any units: */
                    542:   if (!strcmp(units, "GB")
                    543:       || !strcasecmp(units, "G")) {
                    544:     return (((tme_bus_addr_t) address) * 1024 * 1024 * 1024);
                    545:   }
                    546:   else if (!strcmp(units, "MB")
                    547:       || !strcasecmp(units, "M")) {
                    548:     return (((tme_bus_addr_t) address) * 1024 * 1024);
                    549:   }
                    550:   else if (!strcmp(units, "KB")
                    551:           || !strcasecmp(units, "k")) {
                    552:     return (((tme_bus_addr_t) address) * 1024);
                    553:   }
                    554:   else if (*units == '\0') {
                    555:     return ((tme_bus_addr_t) address);
                    556:   }
                    557:   *_failed = TRUE;
                    558:   return (0);
                    559: }
                    560: 
                    561: /* this parses a bus address that has a restricted range: */
                    562: tme_bus_addr_t
                    563: tme_bus_addr_parse(const char *address_string, tme_bus_addr_t failure_value)
                    564: {
                    565:   int failed;
                    566:   tme_bus_addr_t address;
                    567:   address = tme_bus_addr_parse_any(address_string, &failed);
                    568:   return (failed ? failure_value : address);
                    569: }
                    570: 
                    571: /* this transfers bytes between the two participants in a bus cycle: */
                    572: void
                    573: tme_bus_cycle_xfer(struct tme_bus_cycle *cycle_init, struct tme_bus_cycle *cycle_resp)
                    574: {
                    575:   struct tme_bus_cycle *cycle_reader, *cycle_writer;
                    576:   int buffer_increment_mask_reader, buffer_increment_mask_writer;
                    577:   int port_size_reader, port_size_writer;
                    578:   int port_overlap_lane_least, port_overlap_size, port_overlap_size_lg2;
                    579:   int lane, lane_end;
                    580:   int lane_reader, lane_writer;
                    581:   int lane_in_reader, lane_in_writer;
                    582:   int lane_routing_offset_reader, lane_routing_offset_writer;
                    583:   tme_bus_lane_t lane_routing_reader, lane_routing_writer;
                    584:   tme_uint8_t lane_value;
                    585:   int warn_on_lane;
                    586:   unsigned int cycle_size_reader, cycle_size_writer;
                    587: 
                    588:   /* sort the initiator and responder into bus reader and bus writer: */
                    589:   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
                    590:     assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
                    591:     cycle_reader = cycle_init;
                    592:     cycle_writer = cycle_resp;
                    593:   }
                    594:   else {
                    595:     assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
                    596:     assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
                    597:     cycle_reader = cycle_resp;
                    598:     cycle_writer = cycle_init;
                    599:   }
                    600: 
                    601:   /* get the increment masks for the reader and writer.  since
                    602:      tme_bus_cycle_buffer_increment is always 1 or -1, this mask is
                    603:      used to negate values without multiplication: */
                    604:   if (cycle_reader->tme_bus_cycle_buffer_increment == -1) {
                    605:     buffer_increment_mask_reader = -1;
                    606:   }
                    607:   else {
                    608:     assert(cycle_reader->tme_bus_cycle_buffer_increment == 1);
                    609:     buffer_increment_mask_reader = 0;
                    610:   }
                    611:   if (cycle_writer->tme_bus_cycle_buffer_increment == -1) {
                    612:     buffer_increment_mask_writer = -1;
                    613:   }
                    614:   else {
                    615:     assert(cycle_writer->tme_bus_cycle_buffer_increment == 1);
                    616:     buffer_increment_mask_writer = 0;
                    617:   }
                    618: #define _TME_BUS_CYCLE_BUFFER_MULTIPLY(value, mask) \
                    619:   (((value) ^ (mask)) + ((mask) & 1))
                    620: 
                    621:   /* get the sizes, in bytes, of the reader and writer ports: */
                    622:   port_size_reader = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port));
                    623:   port_size_writer = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port));
                    624: 
                    625:   /* determine how the writer's port and the reader's port overlap: */
                    626:   port_overlap_size = port_size_writer;
                    627:   port_overlap_lane_least = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port);
                    628:   lane = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port);
                    629:   if (port_overlap_lane_least < lane) {
                    630:     port_overlap_size -= (lane - port_overlap_lane_least);
                    631:     port_overlap_lane_least = lane;
                    632:   }
                    633:   lane += port_size_reader;
                    634:   if ((port_overlap_lane_least + port_overlap_size) > lane) {
                    635:     port_overlap_size -= (lane - (port_overlap_lane_least + port_overlap_size));
                    636:   }
                    637:   assert(port_overlap_size > 0);
                    638:   for (port_overlap_size_lg2 = 0;
                    639:        (port_overlap_size >>= 1) != 0;
                    640:        port_overlap_size_lg2++);
                    641: 
                    642:   /* select the reader's lane routing: */
                    643:   lane_routing_offset_reader =
                    644:     TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port),
                    645:                         port_overlap_size_lg2,
                    646:                         port_overlap_lane_least
                    647:                         - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port));
                    648: 
                    649:   /* select the writer's lane routing: */
                    650:   lane_routing_offset_writer =
                    651:     TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port),
                    652:                         port_overlap_size_lg2,
                    653:                         port_overlap_lane_least
                    654:                         - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port));
                    655: 
                    656:   /* loop over all byte lanes in one or both ports: */
                    657:   lane = TME_MIN(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port),
                    658:                 TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port));
                    659:   lane_end = TME_MAX(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port) + port_size_reader,
                    660:                     TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port) + port_size_writer);
                    661:   cycle_size_reader = cycle_size_writer = 0;
                    662:   for (; lane < lane_end; lane++) {
                    663: 
                    664:     /* assume that we won't have to warn on this lane: */
                    665:     warn_on_lane = FALSE;
                    666: 
                    667:     /* see if this lane falls in the reader or writer's port: */
                    668:     lane_reader = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port);
                    669:     lane_writer = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port);
                    670:     lane_in_reader = (lane_reader >= 0 && lane_reader < port_size_reader);
                    671:     lane_in_writer = (lane_writer >= 0 && lane_writer < port_size_writer);
                    672: 
                    673:     /* get the value being written to this byte lane.  assume a
                    674:        garbage value: */
                    675:     lane_value = 0xd2;
                    676: 
                    677:     /* if this lane is in the writer's port, it may supply a real
                    678:        lane value: */
                    679:     if (lane_in_writer) {
                    680: 
                    681:       /* get the routing for the writer: */
                    682:       lane_routing_writer = 
                    683:        cycle_writer->tme_bus_cycle_lane_routing[lane_routing_offset_writer + lane_writer];
                    684: 
                    685:       /* if the writer doesn't expect this lane to be connected to the
                    686:         reader, we will issue a warning on this lane: */
                    687:       if ((lane_routing_writer & TME_BUS_LANE_WARN)
                    688:          && lane_in_reader) {
                    689:        warn_on_lane = TRUE;
                    690:       }
                    691:       lane_routing_writer &= ~TME_BUS_LANE_WARN;
                    692: 
                    693:       /* dispatch on the routing to get the lane value: */
                    694:       if (lane_routing_writer == TME_BUS_LANE_ABORT) {
                    695:        abort();
                    696:       }
                    697:       else if (lane_routing_writer != TME_BUS_LANE_UNDEF) {
                    698:        if (!(lane_routing_writer & TME_BUS_LANE_ROUTE_WRITE_IGNORE)
                    699:            && lane_routing_writer >= cycle_size_writer) {
                    700:          cycle_size_writer = lane_routing_writer + 1;
                    701:        }
                    702:        lane_routing_writer &= ~TME_BUS_LANE_ROUTE_WRITE_IGNORE;
                    703: 
                    704:        /* if the writer is the responder, make sure that only bytes
                    705:           in the given register are ever referenced.  given the
                    706:           writer's port size, we could warp the reference index as
                    707:           needed, but hopefully we'll never have to: */
                    708:        assert(!(cycle_writer == cycle_resp
                    709:                 && (((cycle_writer->tme_bus_cycle_address + lane_routing_writer)
                    710:                      ^  cycle_writer->tme_bus_cycle_address)
                    711:                     & ~(port_size_writer - 1)) != 0));
                    712: 
                    713:        lane_value =
                    714:          *(cycle_writer->tme_bus_cycle_buffer
                    715:            + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_writer,
                    716:                                             buffer_increment_mask_writer));
                    717:       }
                    718:     }
                    719: 
                    720:     /* if this lane is in the reader's port, it may take the lane
                    721:        value: */
                    722:     if (lane_in_reader) {
                    723: 
                    724:       /* get the routing for the reader: */
                    725:       lane_routing_reader =
                    726:        cycle_reader->tme_bus_cycle_lane_routing[lane_routing_offset_reader + lane_reader];
                    727: 
                    728:       /* if the reader doesn't expect this lane to be connected to the
                    729:         writer, we will issue a warning on this lane: */
                    730:       if ((lane_routing_reader & TME_BUS_LANE_WARN)
                    731:          && lane_in_writer) {
                    732:        warn_on_lane = TRUE;
                    733:       }
                    734:       lane_routing_reader &= ~TME_BUS_LANE_WARN;
                    735: 
                    736:       /* dispatch on the routing to take the lane value: */
                    737:       if (lane_routing_reader == TME_BUS_LANE_ABORT) {
                    738:        abort();
                    739:       }
                    740:       else if (lane_routing_reader != TME_BUS_LANE_UNDEF
                    741:               && !(lane_routing_reader & TME_BUS_LANE_ROUTE_WRITE_IGNORE)) {
                    742:        if (lane_routing_reader >= cycle_size_reader) {
                    743:          cycle_size_reader = lane_routing_reader + 1;
                    744:        }
                    745: 
                    746:        /* if the reader is the responder, make sure that only bytes
                    747:           in the given register are ever referenced.  given the
                    748:           reader's port size, we could warp the reference index as
                    749:           needed, but hopefully we'll never have to: */
                    750:        assert(!(cycle_reader == cycle_resp
                    751:                 && (((cycle_reader->tme_bus_cycle_address + lane_routing_reader)
                    752:                      ^  cycle_reader->tme_bus_cycle_address)
                    753:                     & ~(port_size_reader - 1)) != 0));
                    754: 
                    755:        *(cycle_reader->tme_bus_cycle_buffer
                    756:          + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_reader,
                    757:                                           buffer_increment_mask_reader)) =
                    758:          lane_value;
                    759:       }
                    760:     }
                    761: 
                    762:     /* if we need to issue a warning on this lane: */
                    763:     if (warn_on_lane) {
                    764:       /* XXX TBD: */
                    765:       abort();
                    766:     }
                    767:   }
                    768: 
                    769:   /* give the reader feedback: */
                    770:   cycle_reader->tme_bus_cycle_size = cycle_size_reader;
                    771:   cycle_reader->tme_bus_cycle_address += cycle_size_reader;
                    772:   cycle_reader->tme_bus_cycle_buffer += 
                    773:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_reader,
                    774:                                   buffer_increment_mask_reader);
                    775:   cycle_reader->tme_bus_cycle_lane_routing += lane_routing_offset_reader;
                    776:   cycle_reader->tme_bus_cycle_port = 
                    777:     TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2);
                    778:   
                    779:   /* give the writer feedback: */
                    780:   cycle_writer->tme_bus_cycle_size = cycle_size_writer;
                    781:   cycle_writer->tme_bus_cycle_address += cycle_size_writer;
                    782:   cycle_writer->tme_bus_cycle_buffer += 
                    783:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_writer,
                    784:                                   buffer_increment_mask_writer);
                    785:   cycle_writer->tme_bus_cycle_lane_routing += lane_routing_offset_writer;
                    786:   cycle_writer->tme_bus_cycle_port = 
                    787:     TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2);
                    788: }
                    789: 
                    790: /* this handles a bus cycle for a memory-like device: */
                    791: void
                    792: tme_bus_cycle_xfer_memory(struct tme_bus_cycle *cycle_init, tme_uint8_t *memory, tme_bus_addr_t address_last)
                    793: {
                    794:   tme_uint8_t memory_junk[sizeof(tme_bus_addr_t)];
                    795:   struct tme_bus_cycle cycle_resp;
                    796: 
                    797:   /* check the starting address: */
                    798:   assert(cycle_init->tme_bus_cycle_address <= address_last);
                    799: 
                    800:   /* get the start of the buffer for this starting address: */
                    801:   if (memory != NULL) {
                    802:     memory += cycle_init->tme_bus_cycle_address;
                    803:   }
                    804:   else {
                    805:     assert(sizeof(memory_junk)
1.1.1.2 ! root      806:           >= ((unsigned int) 1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port)));
1.1       root      807:     memory = memory_junk;
                    808:   }
                    809: 
                    810:   /* create the responder cycle: */
                    811:   cycle_resp.tme_bus_cycle_buffer = memory;
                    812:   cycle_resp.tme_bus_cycle_buffer_increment = 1;
                    813:   cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing;
                    814:   cycle_resp.tme_bus_cycle_address = cycle_init->tme_bus_cycle_address;
                    815:   cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type
                    816:                                   ^ (TME_BUS_CYCLE_WRITE
                    817:                                      | TME_BUS_CYCLE_READ));
                    818:   cycle_resp.tme_bus_cycle_port = cycle_init->tme_bus_cycle_port;
                    819: 
                    820:   /* run the cycle: */
                    821:   tme_bus_cycle_xfer(cycle_init, &cycle_resp);
                    822: 
                    823:   /* check the finishing address: */
                    824:   assert((cycle_init->tme_bus_cycle_address - 1) <= address_last);
                    825: }
                    826:   

unix.superglobalmegacorp.com

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