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

1.1.1.4 ! root        1: /* $Id: bus.c,v 1.13 2007/02/12 23:36: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.4 ! root       37: _TME_RCSID("$Id: bus.c,v 1.13 2007/02/12 23:36:18 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
                     40: #include <tme/generic/bus.h>
1.1.1.3   root       41: #include <tme/misc.h>
1.1       root       42: #include <stdlib.h>
                     43: #include <string.h>
                     44: 
                     45: /* this does a binary search of the addressable connections: */
                     46: int
                     47: tme_bus_address_search(struct tme_bus *bus, tme_bus_addr_t address)
                     48: {
                     49:   int left, right, pivot;
                     50:   struct tme_bus_connection_int *conn_int;
1.1.1.2   root       51:   const struct tme_bus_subregion *subregion;
1.1       root       52: 
                     53:   /* initialize for the search: */
                     54:   left = 0;
                     55:   right = bus->tme_bus_addressables_count - 1;
                     56:   
                     57:   /* do the search: */
                     58:   pivot = 0;
                     59:   for (; left <= right; ) {
                     60: 
                     61:     /* get the pivot: */
                     62:     pivot = (left + right) / 2;
1.1.1.2   root       63:     conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection;
                     64:     subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion;
1.1       root       65: 
                     66:     /* if we have to move left: */
1.1.1.2   root       67:     if (address
                     68:        < (conn_int->tme_bus_connection_int_address
                     69:           + subregion->tme_bus_subregion_address_first)) {
1.1       root       70:       /* if we're done searching, pivot is already the index of the
                     71:         first element we need to shift to the right in order to
                     72:         insert a new element: */
                     73:       right = pivot - 1;
                     74:     }
                     75: 
                     76:     /* if we have to move right: */
1.1.1.2   root       77:     else if (address
                     78:             > (conn_int->tme_bus_connection_int_address
                     79:                + subregion->tme_bus_subregion_address_last)) {
1.1       root       80:       /* if we're done searching, pivot + 1 is the index of the
                     81:         first element we need to shift to the right in order to
                     82:         insert a new element: */
                     83:       left = ++pivot;
                     84:     }
                     85: 
                     86:     /* we found the addressable: */
                     87:     else {
                     88:       return (pivot);
                     89:     }
                     90:   }
                     91: 
                     92:   /* we failed to find an addressable that covers the address: */
                     93:   return (-1 - pivot);
                     94: }
                     95: 
                     96: /* this fills a TLB entry: */
                     97: int
                     98: tme_bus_tlb_fill(struct tme_bus *bus,
                     99:                 struct tme_bus_connection_int *conn_int_asker,
                    100:                 struct tme_bus_tlb *tlb,
                    101:                 tme_bus_addr_t address, 
                    102:                 unsigned int cycles)
                    103: {
                    104:   int pivot;
                    105:   struct tme_bus_connection_int *conn_int;
1.1.1.2   root      106:   const struct tme_bus_subregion *subregion;
1.1       root      107:   struct tme_bus_connection *conn_bus_other;
                    108:   tme_bus_addr_t sourced_address_mask, conn_address;
                    109:   tme_bus_addr_t hole_first, hole_last;
                    110:   struct tme_bus_tlb tlb_bus;
                    111:   void *cycle_fault_private;
                    112:   tme_bus_cycle_handler cycle_fault;
                    113:   int rc;
                    114: 
                    115:   /* get the sourced address mask: */
                    116:   sourced_address_mask = conn_int_asker->tme_bus_connection_int_sourced;
                    117: 
1.1.1.4 ! root      118:   /* get the asked address on the bus: */
        !           119:   conn_address = (sourced_address_mask | address);
        !           120: 
        !           121:   /* start the mapping TLB entry: */
        !           122:   tlb_bus.tme_bus_tlb_addr_first = 0;
        !           123:   tlb_bus.tme_bus_tlb_addr_last = TME_MIN(((sourced_address_mask
        !           124:                                            | (sourced_address_mask - 1))
        !           125:                                           ^ sourced_address_mask),
        !           126:                                          bus->tme_bus_address_mask);
        !           127:   tlb_bus.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
        !           128: 
        !           129:   /* if this bus has a controller, and this request isn't coming from
        !           130:      the controller: */
        !           131:   conn_int = bus->tme_bus_controller;
        !           132:   if (conn_int != NULL
        !           133:       && conn_int != conn_int_asker) {
        !           134: 
        !           135:     /* get the controller's connection: */
        !           136:     conn_bus_other = 
        !           137:       (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other;
        !           138: 
        !           139:     /* unlock the bus: */
        !           140:     tme_rwlock_unlock(&bus->tme_bus_rwlock);
        !           141: 
        !           142:     /* call the controller's TLB fill function: */
        !           143:     rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb,
        !           144:                                             conn_address, cycles);
        !           145: 
        !           146:     /* relock the bus: */
        !           147:     /* XXX FIXME - we assume that this succeeds: */
        !           148:     (void) tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
        !           149: 
        !           150:     /* if the TLB fill succeeded: */
        !           151:     if (rc == TME_OK) {
        !           152: 
        !           153:       /* map the filled TLB entry: */
        !           154:       tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address);
        !           155:     }
        !           156: 
        !           157:     return (rc);
        !           158:   }
        !           159: 
1.1       root      160:   /* search for this address on the bus: */
1.1.1.4 ! root      161:   pivot = tme_bus_address_search(bus, conn_address);
1.1       root      162: 
                    163:   /* if this address doesn't exist: */
                    164:   if (pivot < 0) {
                    165: 
                    166:     /* save the bus' fault cycle handler: */
                    167:     cycle_fault_private = tlb->tme_bus_tlb_cycle_private;
                    168:     cycle_fault = tlb->tme_bus_tlb_cycle;
                    169: 
                    170:     /* initialize the TLB entry: */
                    171:     tme_bus_tlb_initialize(tlb);
                    172: 
1.1.1.4 ! root      173:     /* this TLB entry can cover the entire hole in the address space: */
1.1       root      174:     pivot = -1 - pivot;
                    175:     hole_first = (pivot == 0
                    176:                  ? 0
1.1.1.2   root      177:                  : ((bus->tme_bus_addressables[pivot - 1]
                    178:                      .tme_bus_addressable_connection->tme_bus_connection_int_address)
                    179:                     + (bus->tme_bus_addressables[pivot - 1]
                    180:                        .tme_bus_addressable_subregion->tme_bus_subregion_address_last)
1.1       root      181:                     + 1));
                    182:     hole_last = (pivot == bus->tme_bus_addressables_count
                    183:                 ? bus->tme_bus_address_mask
1.1.1.2   root      184:                 : ((bus->tme_bus_addressables[pivot]
                    185:                     .tme_bus_addressable_connection->tme_bus_connection_int_address)
                    186:                    - 1));
1.1.1.4 ! root      187:     tlb->tme_bus_tlb_addr_first = hole_first;
        !           188:     tlb->tme_bus_tlb_addr_last = hole_last;
1.1       root      189: 
                    190:     /* reads and writes are allowed: */
                    191:     tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
                    192: 
                    193:     /* reads and writes in this region always fault: */
                    194:     tlb->tme_bus_tlb_cycle_private = cycle_fault_private;
                    195:     tlb->tme_bus_tlb_cycle = cycle_fault;
                    196:     rc = TME_OK;
                    197:   }
                    198: 
                    199:   /* otherwise, this address does exist: */
                    200:   else {
1.1.1.2   root      201:     conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection;
                    202:     subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion;
1.1       root      203:     conn_bus_other = 
                    204:       (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other;
                    205: 
                    206:     /* call the TLB fill function for the connection: */
1.1.1.4 ! root      207:     conn_address -= conn_int->tme_bus_connection_int_address;
1.1       root      208:     rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb,
                    209:                                             conn_address, cycles);
                    210: 
                    211:     /* if that succeeded: */
                    212:     if (rc == TME_OK) {
                    213:       
                    214:       /* create the mapping TLB entry: */
1.1.1.4 ! root      215:       tlb_bus.tme_bus_tlb_addr_first =
        !           216:        (TME_MAX((conn_int->tme_bus_connection_int_address
        !           217:                  + subregion->tme_bus_subregion_address_first),
        !           218:                 (sourced_address_mask
        !           219:                  | tlb_bus.tme_bus_tlb_addr_first))
        !           220:         - sourced_address_mask);
        !           221:       tlb_bus.tme_bus_tlb_addr_last = 
        !           222:        (TME_MIN((conn_int->tme_bus_connection_int_address
        !           223:                  + subregion->tme_bus_subregion_address_last),
        !           224:                 (sourced_address_mask
        !           225:                  | tlb_bus.tme_bus_tlb_addr_last))
        !           226:         - sourced_address_mask);
1.1       root      227:     }
                    228:   }
                    229: 
1.1.1.4 ! root      230:   /* if the TLB fill succeeded: */
        !           231:   if (rc == TME_OK) {
        !           232: 
        !           233:     /* map the filled TLB entry: */
        !           234:     tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address);
        !           235:   }
        !           236: 
1.1       root      237:   /* done: */
                    238:   return (rc);
                    239: }
                    240: 
                    241: /* this allocates a new TLB set: */
                    242: int
                    243: tme_bus_tlb_set_allocate(struct tme_bus *bus,
                    244:                         struct tme_bus_connection_int *conn_int_asker,
                    245:                         unsigned int count, unsigned int sizeof_one, 
1.1.1.4 ! root      246:                         struct tme_bus_tlb * tme_shared *_tlbs,
        !           247:                         tme_rwlock_t *_tlbs_rwlock)
1.1       root      248: {
                    249:   struct tme_bus_connection *conn_bus_other, *conn_bus_dma;
                    250:   int conn_int_i;
                    251:   int rc;
                    252:   struct tme_bus_tlb *tlbs, *tlb;
                    253:   unsigned int tlb_i;
                    254: 
                    255:   /* at most one of our addressable connections may provide a TLB set
                    256:      allocator.  generally, this means that connection is
                    257:      DMA-controller-like connection to the bus, where it may need to
                    258:      invalidate at any later time the TLBs it fills out, due to sudden
                    259:      changes in how the DMA region on the bus is mapped: */
                    260:   conn_bus_dma = NULL;
                    261:   for (conn_int_i = 0;
                    262:        conn_int_i < bus->tme_bus_addressables_count;
                    263:        conn_int_i++) {
                    264:     conn_bus_other = 
1.1.1.2   root      265:       ((struct tme_bus_connection *)
                    266:        bus->tme_bus_addressables[conn_int_i].tme_bus_addressable_connection
                    267:        ->tme_bus_connection_int.tme_bus_connection.tme_connection_other);
1.1       root      268: 
                    269:     /* if this bus connection offers a TLB set allocator, it is
                    270:        a DMA-controller-like connection to the bus: */
                    271:     if (conn_bus_other->tme_bus_tlb_set_allocate != NULL) {
                    272: 
                    273:       /* if there is more than one of these, it is likely a
                    274:         configuration error.  if we had some way of specifying which
                    275:         of several DMA regions a given connection will always use, we
                    276:         could avoid this: */
                    277:       if (conn_bus_dma != NULL) {
                    278:        abort();
                    279:       }
                    280: 
                    281:       conn_bus_dma = conn_bus_other;
                    282:     }
                    283:   }
                    284: 
                    285:   /* if there is a DMA-controller-like connection to the bus, 
                    286:      let it allocate the TLB set: */
                    287:   if (conn_bus_dma != NULL) {
                    288:     rc = (*conn_bus_dma->tme_bus_tlb_set_allocate)
1.1.1.4 ! root      289:       (conn_bus_dma, count, sizeof_one, _tlbs, _tlbs_rwlock);
1.1       root      290:   }
                    291: 
                    292:   /* otherwise, allocate and initialize a singleton set ourselves: */
                    293:   else {
                    294:     tlbs = (struct tme_bus_tlb *) tme_malloc(count * sizeof_one);
                    295:     tlb = tlbs;
                    296:     for (tlb_i = 0; tlb_i < count; tlb_i++) {
1.1.1.4 ! root      297:       tme_bus_tlb_construct(tlb);
1.1       root      298:       tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one);
                    299:     }
1.1.1.4 ! root      300:     tme_memory_atomic_pointer_write(struct tme_bus_tlb *, *_tlbs, tlbs, _tlbs_rwlock);
1.1       root      301:     rc = TME_OK;
                    302:   }
                    303:       
                    304:   /* done: */
                    305:   return (rc);
                    306: }
                    307: 
                    308: /* this returns nonzero if the connection's address space is available: */
                    309: int
                    310: tme_bus_connection_ok(struct tme_bus *bus,
                    311:                      struct tme_bus_connection_int *conn_int)
                    312: {
1.1.1.2   root      313:   const struct tme_bus_subregion *subregion;
                    314:   const struct tme_bus_connection *conn_bus_other;
1.1       root      315:   int pivot_start, pivot_end;
                    316: 
                    317:   /* if this connection isn't addressable, it's always OK: */
1.1.1.4 ! root      318:   if (!(conn_int->tme_bus_connection_int_flags
        !           319:        & TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE)) {
1.1       root      320:     return (TRUE);
                    321:   }
                    322: 
1.1.1.2   root      323:   /* all subregions of this connection must fit on the bus,
                    324:      and they must not overlap with any other subregion on 
                    325:      any other existing connection: */
                    326:   /* XXX we should also check that the connection's subregions don't
                    327:      overlap with each other: */
                    328:   conn_bus_other
                    329:     = ((struct tme_bus_connection *)
                    330:        conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other);
                    331:   for (subregion = &conn_bus_other->tme_bus_subregions;
                    332:        subregion != NULL;
                    333:        subregion = subregion->tme_bus_subregion_next) {
                    334: 
                    335:     /* the subregion's last address cannot be less than
                    336:        the first address: */
                    337:     if (subregion->tme_bus_subregion_address_last
                    338:        < subregion->tme_bus_subregion_address_first) {
                    339:       return (FALSE);
                    340:     }
                    341:     
                    342:     /* this subregion must fit on the bus: */
                    343:     if (subregion->tme_bus_subregion_address_last >
                    344:        (bus->tme_bus_address_mask
                    345:         - conn_int->tme_bus_connection_int_address)) {
                    346:       return (FALSE);
                    347:     }
                    348: 
                    349:     /* search for anything covering the start or end of the new
                    350:        addressable subregion: */
                    351:     pivot_start = 
                    352:       tme_bus_address_search(bus, 
                    353:                             (conn_int->tme_bus_connection_int_address
                    354:                              + subregion->tme_bus_subregion_address_first));
                    355:     pivot_end =
                    356:       tme_bus_address_search(bus,
                    357:                             (conn_int->tme_bus_connection_int_address
                    358:                              + subregion->tme_bus_subregion_address_last));
                    359: 
                    360:     /* both searches must have failed, and they must have stopped at the
                    361:        same point in the sorted addressables, further indicating that no
                    362:        addressable exists anywhere *between* the start and end of the
                    363:        new addressable, either.  otherwise, this connection fails: */
                    364:     if (pivot_start >= 0
                    365:        || pivot_end >= 0
                    366:        || pivot_start != pivot_end) {
                    367:       return (FALSE);
                    368:     }
1.1       root      369:   }
                    370: 
                    371:   /* this connection's address space is available: */
                    372:   return (TRUE);
                    373: }
                    374: 
                    375: /* this makes a new connection: */
                    376: int
                    377: tme_bus_connection_make(struct tme_bus *bus,
                    378:                        struct tme_bus_connection_int *conn_int,
                    379:                        unsigned int state)
                    380: {
1.1.1.2   root      381:   const struct tme_bus_connection *conn_bus_other;
                    382:   const struct tme_bus_subregion *subregion;
1.1       root      383:   int pivot;
                    384: 
                    385:   /* if this connection is not full, return now: */
                    386:   if (state == TME_CONNECTION_HALF) {
                    387:     return (TME_OK);
                    388:   }
                    389: 
1.1.1.4 ! root      390:   /* if this connection is to a bus controller: */
        !           391:   if (conn_int->tme_bus_connection_int_flags
        !           392:       & TME_BUS_CONNECTION_INT_FLAG_CONTROLLER) {
        !           393: 
        !           394:     /* if this bus already has a controller: */
        !           395:     if (bus->tme_bus_controller != NULL) {
        !           396: 
        !           397:       /* we can't make this connection: */
        !           398:       return (EEXIST);
        !           399:     }
        !           400: 
        !           401:     /* this connection is to the bus controller: */
        !           402:     bus->tme_bus_controller = conn_int;
        !           403:   }
        !           404: 
1.1       root      405:   /* add this connection to our list: */
                    406:   conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_next
                    407:     = (struct tme_connection *) bus->tme_bus_connections;
                    408:   bus->tme_bus_connections = conn_int;
                    409: 
                    410:   /* if this connection is addressable, and this is connection is now
                    411:      fully made, add it to our list of addressables: */
1.1.1.4 ! root      412:   if ((conn_int->tme_bus_connection_int_flags
        !           413:        & TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE)
1.1       root      414:       && state == TME_CONNECTION_FULL) {
                    415:     
1.1.1.2   root      416:     /* add all subregions of this connection as addressables: */
                    417:     conn_int->tme_bus_connection_int_address_last = 0;
                    418:     conn_bus_other
                    419:       = ((struct tme_bus_connection *)
                    420:         conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other);
                    421:     for (subregion = &conn_bus_other->tme_bus_subregions;
                    422:         subregion != NULL;
                    423:         subregion = subregion->tme_bus_subregion_next) {
                    424: 
                    425:       /* search for the place to insert this new addressable: */
                    426:       pivot = tme_bus_address_search(bus, 
                    427:                                     (conn_int->tme_bus_connection_int_address
                    428:                                      + subregion->tme_bus_subregion_address_first));
                    429:       assert(pivot < 0);
                    430:       pivot = -1 - pivot;
1.1       root      431:     
1.1.1.2   root      432:       /* if we have to, grow the addressable array: */
                    433:       if (bus->tme_bus_addressables_count
                    434:          == bus->tme_bus_addressables_size) {
                    435:        bus->tme_bus_addressables_size += (bus->tme_bus_addressables_size >> 1) + 1;
                    436:        bus->tme_bus_addressables = tme_renew(struct tme_bus_addressable,
                    437:                                              bus->tme_bus_addressables,
                    438:                                              bus->tme_bus_addressables_size);
                    439:       }
                    440: 
                    441:       /* move all of the later addressables down: */
                    442:       memmove(&bus->tme_bus_addressables[pivot + 1],
                    443:              &bus->tme_bus_addressables[pivot],
                    444:              sizeof(bus->tme_bus_addressables[pivot])
                    445:              * (bus->tme_bus_addressables_count
                    446:                 - pivot));
                    447: 
                    448:       /* insert this new addressable: */
                    449:       bus->tme_bus_addressables[pivot].tme_bus_addressable_connection = conn_int;
                    450:       bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion = subregion;
                    451:       bus->tme_bus_addressables_count++;
                    452: 
                    453:       /* update the last address on this connection.  NB that the
                    454:         subregion information should be used almost always.
                    455:         currently this value is only used as the width of the
                    456:         connection for the purposes of determining TLB entry limits
                    457:         when the connection itself asks to fill a TLB entry: */
                    458:       conn_int->tme_bus_connection_int_address_last
                    459:        = TME_MAX(conn_int->tme_bus_connection_int_address_last,
                    460:                  subregion->tme_bus_subregion_address_last);
                    461:     }
1.1       root      462:   }
                    463: 
                    464:   return (TME_OK);
                    465: }
                    466: 
                    467: /* this breaks a connection: */
                    468: int
                    469: tme_bus_connection_break(struct tme_bus *bus,
                    470:                         struct tme_bus_connection_int *conn_int,
                    471:                         unsigned int state)
                    472: {
                    473:   abort();
                    474: }
                    475: 
                    476: /* this map the first bus TLB entry to be valid on another bus, according to
                    477:    the information in the second bus TLB entry: */
                    478: void
                    479: tme_bus_tlb_map(struct tme_bus_tlb *tlb0, tme_bus_addr_t addr0, 
                    480:                const struct tme_bus_tlb *tlb1, tme_bus_addr_t addr1)
                    481: {
                    482:   tme_bus_addr_t extra_before0, extra_after0;
                    483:   tme_bus_addr_t extra_before1, extra_after1;
1.1.1.4 ! root      484:   long addr_offset;
1.1       root      485:   unsigned int cycles_ok;
                    486: 
                    487:   /* get the address offset: */
1.1.1.4 ! root      488:   addr_offset = addr1;
        !           489:   addr_offset -= addr0;
1.1       root      490: 
                    491:   /* intersect the amount of bus address space covered: */
1.1.1.4 ! root      492:   extra_before0 = addr0 - tlb0->tme_bus_tlb_addr_first;
        !           493:   extra_after0 = tlb0->tme_bus_tlb_addr_last - addr0;
        !           494:   extra_before1 = addr1 - tlb1->tme_bus_tlb_addr_first;
        !           495:   extra_after1 = tlb1->tme_bus_tlb_addr_last - addr1;
        !           496:   tlb0->tme_bus_tlb_addr_first = addr1 - TME_MIN(extra_before0, extra_before1);
        !           497:   tlb0->tme_bus_tlb_addr_last = addr1 + TME_MIN(extra_after0, extra_after1);
1.1       root      498: 
                    499:   /* intersect the kinds of bus cycles allowed: */
                    500:   cycles_ok = (tlb0->tme_bus_tlb_cycles_ok &= tlb1->tme_bus_tlb_cycles_ok);
                    501:   if (!(cycles_ok & TME_BUS_CYCLE_READ)) {
                    502:     tlb0->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
                    503:   }
                    504:   else if (tlb0->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF) {
                    505:     tlb0->tme_bus_tlb_emulator_off_read -= addr_offset;
                    506:   }
                    507:   if (!(cycles_ok & TME_BUS_CYCLE_WRITE)) {
                    508:     tlb0->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
                    509:   }
                    510:   else if (tlb0->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
                    511:     tlb0->tme_bus_tlb_emulator_off_write -= addr_offset;
                    512:   }
                    513: 
                    514:   /* update the address shift for the cycle handler: */
                    515:   tlb0->tme_bus_tlb_addr_offset -= addr_offset;
                    516: }
                    517: 
1.1.1.4 ! root      518: /* this constructs a new global TLB entry: */
1.1.1.3   root      519: void
1.1.1.4 ! root      520: tme_bus_tlb_construct(struct tme_bus_tlb *tlb)
1.1.1.3   root      521: {
1.1.1.4 ! root      522:   /* a new global TLB entry is invalid and not busy: */
        !           523:   tlb->tme_bus_tlb_invalid = TRUE;
        !           524:   tme_rwlock_init(&tlb->tme_bus_tlb_invalid_rwlock);
        !           525:   tlb->tme_bus_tlb_busy = FALSE;
        !           526:   tme_rwlock_init(&tlb->tme_bus_tlb_busy_rwlock);
        !           527:   tlb->tme_bus_tlb_global = tlb;
1.1.1.3   root      528: }
                    529: 
1.1.1.4 ! root      530: /* this saves a bus TLB entry in automatic storage into a backing
        !           531:    global bus TLB entry: */
1.1.1.3   root      532: void
                    533: tme_bus_tlb_back(const struct tme_bus_tlb *tlb_local)
                    534: {
                    535:   struct tme_bus_tlb *tlb_backing;
                    536: 
                    537:   /* get the backing TLB entry: */
1.1.1.4 ! root      538:   tlb_backing = tlb_local->tme_bus_tlb_global;
1.1.1.3   root      539: 
                    540: #define TLB_BACK(f) tlb_backing->f = tlb_local->f
                    541: 
                    542:   /* the first address covered: */
1.1.1.4 ! root      543:   TLB_BACK(tme_bus_tlb_addr_first);
1.1.1.3   root      544: 
                    545:   /* the last address covered: */
1.1.1.4 ! root      546:   TLB_BACK(tme_bus_tlb_addr_last);
1.1.1.3   root      547: 
                    548:   /* the fast (memory) transfers: */
                    549:   TLB_BACK(tme_bus_tlb_emulator_off_read);
                    550:   TLB_BACK(tme_bus_tlb_emulator_off_write);
                    551: 
                    552:   /* fast (memory) reads and writes are protected by this rwlock: */
                    553:   TLB_BACK(tme_bus_tlb_rwlock);
                    554: 
                    555:   /* when one or both of TLB_BUS_CYCLE_READ and TLB_BUS_CYCLE_WRITE
                    556:      are set in this value, this TLB entry allows slow (function call)
                    557:      reads of and/or writes to the bus region: */
                    558:   TLB_BACK(tme_bus_tlb_cycles_ok);
                    559: 
                    560:   /* adding an address in the bus region to this offset, and then
                    561:      shifting that result to the right (shift > 0) or to the left
                    562:      (shift < 0) yields an address for the bus cycle handler: */
                    563:   TLB_BACK(tme_bus_tlb_addr_offset);
                    564:   TLB_BACK(tme_bus_tlb_addr_shift);
                    565: 
                    566:   /* the bus cycle handler: */
                    567:   TLB_BACK(tme_bus_tlb_cycle_private);
                    568:   TLB_BACK(tme_bus_tlb_cycle);
                    569: 
                    570:   /* the bus fault handlers: */
                    571:   TLB_BACK(tme_bus_tlb_fault_handler_count);
                    572:   memcpy (&tlb_backing->tme_bus_tlb_fault_handlers[0],
                    573:          &tlb_local->tme_bus_tlb_fault_handlers[0],
                    574:          sizeof (tlb_local->tme_bus_tlb_fault_handlers[0])
                    575:          * tlb_local->tme_bus_tlb_fault_handler_count);
                    576: 
                    577: #undef TLB_BACK
                    578: }
                    579: 
1.1       root      580: /* this invalidates a bus TLB entry: */
                    581: void
                    582: tme_bus_tlb_invalidate(struct tme_bus_tlb *tlb)
                    583: {
1.1.1.3   root      584: 
1.1.1.4 ! root      585:   /* lock this TLB entry for invalidation: */
        !           586:   tme_rwlock_wrlock(&tlb->tme_bus_tlb_invalid_rwlock);
1.1.1.3   root      587: 
1.1.1.4 ! root      588:   /* invalidate this TLB entry: */
        !           589:   tlb->tme_bus_tlb_invalid = TRUE;
        !           590: 
        !           591: #if TME_THREADS_COOPERATIVE
        !           592: #ifndef TME_NO_DEBUG_LOCKS
        !           593:   assert(!tme_memory_atomic_read_flag(&tlb->tme_bus_tlb_busy,
        !           594:                                      &tlb->tme_bus_tlb_busy_rwlock));
        !           595: #endif /* !TME_NO_DEBUG_LOCKS */
        !           596: #else  /* !TME_THREADS_COOPERATIVE */
        !           597:   /* spin while the TLB entry is busy: */
        !           598:   do { } while(tme_memory_atomic_read_flag(&tlb->tme_bus_tlb_busy,
        !           599:                                           &tlb->tme_bus_tlb_busy_rwlock));
        !           600: #endif /* !TME_THREADS_COOPERATIVE */
1.1.1.3   root      601: 
1.1.1.4 ! root      602:   /* unlock this TLB entry for invalidation: */
        !           603:   tme_rwlock_unlock(&tlb->tme_bus_tlb_invalid_rwlock);
1.1       root      604: }
                    605: 
                    606: /* this initializes a bus TLB entry: */
                    607: void
                    608: tme_bus_tlb_initialize(struct tme_bus_tlb *tlb)
                    609: {
                    610:   
                    611:   /* make the first address covered all-bits-one: */
1.1.1.4 ! root      612:   tlb->tme_bus_tlb_addr_first = (((tme_bus_addr_t) 0) - 1);
1.1       root      613:   
                    614:   /* make the last address covered all-bits-zero: */
1.1.1.4 ! root      615:   tlb->tme_bus_tlb_addr_last = 0;
1.1       root      616: 
                    617:   /* no fast (memory) transfers allowed: */
                    618:   tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
                    619:   tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
                    620:   tlb->tme_bus_tlb_rwlock = NULL;
                    621: 
                    622:   /* no bus cycles allowed: */
                    623:   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_UNDEF;
                    624: 
                    625:   /* no address offset or shift: */
                    626:   tlb->tme_bus_tlb_addr_offset = 0;
                    627:   tlb->tme_bus_tlb_addr_shift = 0;
                    628: 
                    629:   /* no bus cycle handler: */
                    630:   tlb->tme_bus_tlb_cycle_private = NULL;
                    631:   tlb->tme_bus_tlb_cycle = NULL;
                    632: 
                    633:   /* no bus fault handlers: */
                    634:   tlb->tme_bus_tlb_fault_handler_count = 0;
                    635: }
                    636: 
                    637: /* this calls a TLB entry's fault handlers: */
                    638: int
                    639: tme_bus_tlb_fault(struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
                    640: {
                    641:   unsigned int i;
                    642: 
                    643:   /* call all of the fault handlers: */
                    644:   for (i = 0; i < tlb->tme_bus_tlb_fault_handler_count; i++) {
                    645:     rc = ((*tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler)
                    646:          (tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler_private,
                    647:           tlb, cycle, rc));
                    648:   }
                    649: 
                    650:   return (rc);
                    651: }
                    652: 
                    653: /* this parses any bus address: */
                    654: tme_bus_addr_t
                    655: tme_bus_addr_parse_any(const char *address_string, int *_failed)
                    656: {
1.1.1.3   root      657:   return (tme_misc_unumber_parse_any(address_string, _failed));
1.1       root      658: }
                    659: 
                    660: /* this parses a bus address that has a restricted range: */
                    661: tme_bus_addr_t
                    662: tme_bus_addr_parse(const char *address_string, tme_bus_addr_t failure_value)
                    663: {
                    664:   int failed;
                    665:   tme_bus_addr_t address;
                    666:   address = tme_bus_addr_parse_any(address_string, &failed);
                    667:   return (failed ? failure_value : address);
                    668: }
                    669: 
                    670: /* this transfers bytes between the two participants in a bus cycle: */
                    671: void
                    672: tme_bus_cycle_xfer(struct tme_bus_cycle *cycle_init, struct tme_bus_cycle *cycle_resp)
                    673: {
                    674:   struct tme_bus_cycle *cycle_reader, *cycle_writer;
                    675:   int buffer_increment_mask_reader, buffer_increment_mask_writer;
                    676:   int port_size_reader, port_size_writer;
                    677:   int port_overlap_lane_least, port_overlap_size, port_overlap_size_lg2;
                    678:   int lane, lane_end;
                    679:   int lane_reader, lane_writer;
                    680:   int lane_in_reader, lane_in_writer;
                    681:   int lane_routing_offset_reader, lane_routing_offset_writer;
                    682:   tme_bus_lane_t lane_routing_reader, lane_routing_writer;
                    683:   tme_uint8_t lane_value;
                    684:   int warn_on_lane;
                    685:   unsigned int cycle_size_reader, cycle_size_writer;
                    686: 
                    687:   /* sort the initiator and responder into bus reader and bus writer: */
                    688:   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
                    689:     assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
                    690:     cycle_reader = cycle_init;
                    691:     cycle_writer = cycle_resp;
                    692:   }
                    693:   else {
                    694:     assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
                    695:     assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
                    696:     cycle_reader = cycle_resp;
                    697:     cycle_writer = cycle_init;
                    698:   }
                    699: 
                    700:   /* get the increment masks for the reader and writer.  since
                    701:      tme_bus_cycle_buffer_increment is always 1 or -1, this mask is
                    702:      used to negate values without multiplication: */
                    703:   if (cycle_reader->tme_bus_cycle_buffer_increment == -1) {
                    704:     buffer_increment_mask_reader = -1;
                    705:   }
                    706:   else {
                    707:     assert(cycle_reader->tme_bus_cycle_buffer_increment == 1);
                    708:     buffer_increment_mask_reader = 0;
                    709:   }
                    710:   if (cycle_writer->tme_bus_cycle_buffer_increment == -1) {
                    711:     buffer_increment_mask_writer = -1;
                    712:   }
                    713:   else {
                    714:     assert(cycle_writer->tme_bus_cycle_buffer_increment == 1);
                    715:     buffer_increment_mask_writer = 0;
                    716:   }
                    717: #define _TME_BUS_CYCLE_BUFFER_MULTIPLY(value, mask) \
                    718:   (((value) ^ (mask)) + ((mask) & 1))
                    719: 
                    720:   /* get the sizes, in bytes, of the reader and writer ports: */
                    721:   port_size_reader = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port));
                    722:   port_size_writer = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port));
                    723: 
                    724:   /* determine how the writer's port and the reader's port overlap: */
                    725:   port_overlap_size = port_size_writer;
                    726:   port_overlap_lane_least = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port);
                    727:   lane = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port);
                    728:   if (port_overlap_lane_least < lane) {
                    729:     port_overlap_size -= (lane - port_overlap_lane_least);
                    730:     port_overlap_lane_least = lane;
                    731:   }
                    732:   lane += port_size_reader;
                    733:   if ((port_overlap_lane_least + port_overlap_size) > lane) {
                    734:     port_overlap_size -= (lane - (port_overlap_lane_least + port_overlap_size));
                    735:   }
                    736:   assert(port_overlap_size > 0);
                    737:   for (port_overlap_size_lg2 = 0;
                    738:        (port_overlap_size >>= 1) != 0;
                    739:        port_overlap_size_lg2++);
                    740: 
                    741:   /* select the reader's lane routing: */
                    742:   lane_routing_offset_reader =
                    743:     TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port),
                    744:                         port_overlap_size_lg2,
                    745:                         port_overlap_lane_least
                    746:                         - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port));
                    747: 
                    748:   /* select the writer's lane routing: */
                    749:   lane_routing_offset_writer =
                    750:     TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port),
                    751:                         port_overlap_size_lg2,
                    752:                         port_overlap_lane_least
                    753:                         - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port));
                    754: 
                    755:   /* loop over all byte lanes in one or both ports: */
                    756:   lane = TME_MIN(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port),
                    757:                 TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port));
                    758:   lane_end = TME_MAX(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port) + port_size_reader,
                    759:                     TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port) + port_size_writer);
                    760:   cycle_size_reader = cycle_size_writer = 0;
                    761:   for (; lane < lane_end; lane++) {
                    762: 
                    763:     /* assume that we won't have to warn on this lane: */
                    764:     warn_on_lane = FALSE;
                    765: 
                    766:     /* see if this lane falls in the reader or writer's port: */
                    767:     lane_reader = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port);
                    768:     lane_writer = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port);
                    769:     lane_in_reader = (lane_reader >= 0 && lane_reader < port_size_reader);
                    770:     lane_in_writer = (lane_writer >= 0 && lane_writer < port_size_writer);
                    771: 
                    772:     /* get the value being written to this byte lane.  assume a
                    773:        garbage value: */
                    774:     lane_value = 0xd2;
                    775: 
                    776:     /* if this lane is in the writer's port, it may supply a real
                    777:        lane value: */
                    778:     if (lane_in_writer) {
                    779: 
                    780:       /* get the routing for the writer: */
                    781:       lane_routing_writer = 
                    782:        cycle_writer->tme_bus_cycle_lane_routing[lane_routing_offset_writer + lane_writer];
                    783: 
                    784:       /* if the writer doesn't expect this lane to be connected to the
                    785:         reader, we will issue a warning on this lane: */
                    786:       if ((lane_routing_writer & TME_BUS_LANE_WARN)
                    787:          && lane_in_reader) {
                    788:        warn_on_lane = TRUE;
                    789:       }
                    790:       lane_routing_writer &= ~TME_BUS_LANE_WARN;
                    791: 
                    792:       /* dispatch on the routing to get the lane value: */
                    793:       if (lane_routing_writer == TME_BUS_LANE_ABORT) {
                    794:        abort();
                    795:       }
                    796:       else if (lane_routing_writer != TME_BUS_LANE_UNDEF) {
                    797:        if (!(lane_routing_writer & TME_BUS_LANE_ROUTE_WRITE_IGNORE)
                    798:            && lane_routing_writer >= cycle_size_writer) {
                    799:          cycle_size_writer = lane_routing_writer + 1;
                    800:        }
                    801:        lane_routing_writer &= ~TME_BUS_LANE_ROUTE_WRITE_IGNORE;
                    802: 
                    803:        /* if the writer is the responder, make sure that only bytes
                    804:           in the given register are ever referenced.  given the
                    805:           writer's port size, we could warp the reference index as
                    806:           needed, but hopefully we'll never have to: */
                    807:        assert(!(cycle_writer == cycle_resp
                    808:                 && (((cycle_writer->tme_bus_cycle_address + lane_routing_writer)
                    809:                      ^  cycle_writer->tme_bus_cycle_address)
                    810:                     & ~(port_size_writer - 1)) != 0));
                    811: 
                    812:        lane_value =
                    813:          *(cycle_writer->tme_bus_cycle_buffer
                    814:            + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_writer,
                    815:                                             buffer_increment_mask_writer));
                    816:       }
                    817:     }
                    818: 
                    819:     /* if this lane is in the reader's port, it may take the lane
                    820:        value: */
                    821:     if (lane_in_reader) {
                    822: 
                    823:       /* get the routing for the reader: */
                    824:       lane_routing_reader =
                    825:        cycle_reader->tme_bus_cycle_lane_routing[lane_routing_offset_reader + lane_reader];
                    826: 
                    827:       /* if the reader doesn't expect this lane to be connected to the
                    828:         writer, we will issue a warning on this lane: */
                    829:       if ((lane_routing_reader & TME_BUS_LANE_WARN)
                    830:          && lane_in_writer) {
                    831:        warn_on_lane = TRUE;
                    832:       }
                    833:       lane_routing_reader &= ~TME_BUS_LANE_WARN;
                    834: 
                    835:       /* dispatch on the routing to take the lane value: */
                    836:       if (lane_routing_reader == TME_BUS_LANE_ABORT) {
                    837:        abort();
                    838:       }
                    839:       else if (lane_routing_reader != TME_BUS_LANE_UNDEF
                    840:               && !(lane_routing_reader & TME_BUS_LANE_ROUTE_WRITE_IGNORE)) {
                    841:        if (lane_routing_reader >= cycle_size_reader) {
                    842:          cycle_size_reader = lane_routing_reader + 1;
                    843:        }
                    844: 
                    845:        /* if the reader is the responder, make sure that only bytes
                    846:           in the given register are ever referenced.  given the
                    847:           reader's port size, we could warp the reference index as
                    848:           needed, but hopefully we'll never have to: */
                    849:        assert(!(cycle_reader == cycle_resp
                    850:                 && (((cycle_reader->tme_bus_cycle_address + lane_routing_reader)
                    851:                      ^  cycle_reader->tme_bus_cycle_address)
                    852:                     & ~(port_size_reader - 1)) != 0));
                    853: 
                    854:        *(cycle_reader->tme_bus_cycle_buffer
                    855:          + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_reader,
                    856:                                           buffer_increment_mask_reader)) =
                    857:          lane_value;
                    858:       }
                    859:     }
                    860: 
                    861:     /* if we need to issue a warning on this lane: */
                    862:     if (warn_on_lane) {
                    863:       /* XXX TBD: */
                    864:       abort();
                    865:     }
                    866:   }
                    867: 
                    868:   /* give the reader feedback: */
                    869:   cycle_reader->tme_bus_cycle_size = cycle_size_reader;
                    870:   cycle_reader->tme_bus_cycle_address += cycle_size_reader;
                    871:   cycle_reader->tme_bus_cycle_buffer += 
                    872:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_reader,
                    873:                                   buffer_increment_mask_reader);
                    874:   cycle_reader->tme_bus_cycle_lane_routing += lane_routing_offset_reader;
                    875:   cycle_reader->tme_bus_cycle_port = 
                    876:     TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2);
                    877:   
                    878:   /* give the writer feedback: */
                    879:   cycle_writer->tme_bus_cycle_size = cycle_size_writer;
                    880:   cycle_writer->tme_bus_cycle_address += cycle_size_writer;
                    881:   cycle_writer->tme_bus_cycle_buffer += 
                    882:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_writer,
                    883:                                   buffer_increment_mask_writer);
                    884:   cycle_writer->tme_bus_cycle_lane_routing += lane_routing_offset_writer;
                    885:   cycle_writer->tme_bus_cycle_port = 
                    886:     TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2);
                    887: }
                    888: 
                    889: /* this handles a bus cycle for a memory-like device: */
                    890: void
                    891: tme_bus_cycle_xfer_memory(struct tme_bus_cycle *cycle_init, tme_uint8_t *memory, tme_bus_addr_t address_last)
                    892: {
                    893:   tme_uint8_t memory_junk[sizeof(tme_bus_addr_t)];
                    894:   struct tme_bus_cycle cycle_resp;
                    895: 
                    896:   /* check the starting address: */
                    897:   assert(cycle_init->tme_bus_cycle_address <= address_last);
                    898: 
                    899:   /* get the start of the buffer for this starting address: */
                    900:   if (memory != NULL) {
                    901:     memory += cycle_init->tme_bus_cycle_address;
                    902:   }
                    903:   else {
                    904:     assert(sizeof(memory_junk)
1.1.1.2   root      905:           >= ((unsigned int) 1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port)));
1.1       root      906:     memory = memory_junk;
                    907:   }
                    908: 
                    909:   /* create the responder cycle: */
                    910:   cycle_resp.tme_bus_cycle_buffer = memory;
                    911:   cycle_resp.tme_bus_cycle_buffer_increment = 1;
                    912:   cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing;
                    913:   cycle_resp.tme_bus_cycle_address = cycle_init->tme_bus_cycle_address;
                    914:   cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type
                    915:                                   ^ (TME_BUS_CYCLE_WRITE
                    916:                                      | TME_BUS_CYCLE_READ));
                    917:   cycle_resp.tme_bus_cycle_port = cycle_init->tme_bus_cycle_port;
                    918: 
                    919:   /* run the cycle: */
                    920:   tme_bus_cycle_xfer(cycle_init, &cycle_resp);
                    921: 
                    922:   /* check the finishing address: */
                    923:   assert((cycle_init->tme_bus_cycle_address - 1) <= address_last);
                    924: }
                    925:   
1.1.1.3   root      926: /* given an initiator's cycle and a responder's port size, assuming
                    927:    that the responder's port fits completely within the initiator's
                    928:    port, this internal function returns the "correct" least lane for
                    929:    the responder's port, relative to the least lane of the initiator's
                    930:    port.  this requires that the initiator's lane routing use either
                    931:    TME_BUS_LANE_ABORT or TME_BUS_LANE_WARN on routings for incorrect
                    932:    lanes: */
                    933: static unsigned int
                    934: _tme_bus_cycle_xfer_resp_least_lane(const struct tme_bus_cycle *cycle_init, 
                    935:                                    unsigned int port_size_log2_resp)
                    936: {
                    937:   unsigned int port_size_resp;
                    938:   unsigned int port_lane_least_max_resp;
                    939:   unsigned int port_lane_least_resp;
                    940:   const tme_bus_lane_t *lane_routing_init;
                    941:   unsigned int lane;
                    942:   int lane_routing;
                    943: 
                    944:   /* get the responder's port size: */
                    945:   port_size_resp = (1 << port_size_log2_resp);
                    946: 
                    947:   /* calculate the maximum possible least lane for the responder.  we
                    948:      require that the responder's port fit completely within the
                    949:      initiator's port: */
                    950:   port_lane_least_max_resp = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port));
                    951:   if (__tme_predict_false(port_size_resp > port_lane_least_max_resp)) {
                    952:     abort();
                    953:   }
                    954:   port_lane_least_max_resp -= port_size_resp;
                    955: 
                    956:   /* assume that the responder will have the same least lane as the
                    957:      initiator, and get the initiator's lane routing for that
                    958:      responder least lane: */
                    959:   port_lane_least_resp = 0;
                    960:   lane_routing_init
                    961:     = (cycle_init->tme_bus_cycle_lane_routing
                    962:        + TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port),
                    963:                              port_size_log2_resp,
                    964:                              port_lane_least_resp));
                    965: 
                    966:   /* loop over all of the possible least lanes for the responder: */
                    967:   for (;
                    968:        port_lane_least_resp <= port_lane_least_max_resp;
                    969:        port_lane_least_resp++) {
                    970: 
                    971:     /* check the routing for all of the lanes in the responder's port, starting
                    972:        from the highest numbered lane and working down: */
                    973:     lane = port_lane_least_resp + port_size_resp;
                    974:     for (;;) {
                    975:       lane = lane - 1;
                    976:       lane_routing = lane_routing_init[lane];
                    977: 
                    978:       /* if this lane gets a warning or an abort, this is not the
                    979:         correct least lane for the responder: */
                    980:       if ((lane_routing & TME_BUS_LANE_WARN) 
                    981:          || lane_routing == TME_BUS_LANE_ABORT) {
                    982:        break;
                    983:       }
                    984: 
                    985:       /* if we have now checked all of the lanes in the overlap between
                    986:         initiator and responder, we've found the correct least lane for
                    987:         the responder: */
                    988:       if (lane == port_lane_least_resp) {
                    989:        return (port_lane_least_resp);
                    990:       }
                    991:     }
                    992: 
                    993:     /* advance the offset into the initiator's lane routing: */
                    994:     lane_routing_init += (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port));
                    995:   }
                    996: 
                    997:   /* if we get here, the initiator doesn't allow responders of the
                    998:      given port size: */
                    999:   abort();
                   1000: }
                   1001:          
                   1002: /* this handles a bus cycle for a simple register device: */
                   1003: void
                   1004: tme_bus_cycle_xfer_reg(struct tme_bus_cycle *cycle_init, 
                   1005:                       void *resp_reg,
                   1006:                       unsigned int port_size_log2_resp)
                   1007: {
                   1008:   unsigned int port_lane_least_resp;
                   1009:   const tme_bus_lane_t *lane_routing_init;
                   1010:   unsigned int lane_count;
                   1011:   unsigned int lane;
                   1012:   tme_uint8_t *buffer_init;
                   1013:   tme_uint8_t *buffer_resp;
                   1014:   int lane_routing;
                   1015:   int cycle_size_init;
                   1016:   int buffer_increment_mask_init;
                   1017:   int writer_init;
                   1018: 
                   1019:   /* see if the initiator is writing: */
                   1020:   writer_init = (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
                   1021:   assert (writer_init || cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
                   1022: 
                   1023:   /* get the increment mask for the initiator.  since
                   1024:      tme_bus_cycle_buffer_increment is always 1 or -1, this mask is
                   1025:      used to negate values without multiplication: */
                   1026:   if (cycle_init->tme_bus_cycle_buffer_increment == -1) {
                   1027:     buffer_increment_mask_init = -1;
                   1028:   }
                   1029:   else {
                   1030:     assert(cycle_init->tme_bus_cycle_buffer_increment == 1);
                   1031:     buffer_increment_mask_init = 0;
                   1032:   }
                   1033: 
                   1034:   /* get the least lane for the responder's port relative to the
                   1035:      initiator port's least lane, assuming that the responder's port
                   1036:      fits completely within the initiator's port and starts at the
                   1037:      "correct" least lane: */
                   1038:   port_lane_least_resp = _tme_bus_cycle_xfer_resp_least_lane(cycle_init,
                   1039:                                                             port_size_log2_resp);
                   1040: 
                   1041:   /* get the initiator's lane routing: */
                   1042:   lane_routing_init
                   1043:     = (cycle_init->tme_bus_cycle_lane_routing
                   1044:        + TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port),
                   1045:                              port_size_log2_resp,
                   1046:                              port_lane_least_resp));
                   1047: 
                   1048:   /* return some things to the initiator: */
                   1049:   cycle_init->tme_bus_cycle_lane_routing = lane_routing_init;
                   1050:   cycle_init->tme_bus_cycle_port = 
                   1051:     TME_BUS_CYCLE_PORT((TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_init->tme_bus_cycle_port)
                   1052:                        + port_lane_least_resp),
                   1053:                       port_size_log2_resp);
                   1054: 
                   1055:   /* advance the initiator's lane routing to the first lane in the
                   1056:      responder's port: */
                   1057:   lane_routing_init += port_lane_least_resp;
                   1058: 
                   1059:   /* get the lane count: */
                   1060:   lane_count = (1 << port_size_log2_resp);
                   1061: 
                   1062:   /* get the initial pointer into the responder's register buffer.  we
                   1063:      move from lower-numbered lanes (with data of lesser significance)
                   1064:      to higher-numbered lanes (with data of more significance).  we
                   1065:      are always called with pointers to registers in host native byte
                   1066:      order, so if the host is little-endian, we start from the given
                   1067:      pointer, else we start from the other end of the register
                   1068:      buffer: */
                   1069:   buffer_resp = (((tme_uint8_t *) resp_reg)
                   1070:                 + (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG
                   1071:                    ? (lane_count - 1)
                   1072:                    : 0));
                   1073: 
                   1074:   /* loop over the lanes: */
                   1075:   lane = 0;
                   1076:   cycle_size_init = 0;
                   1077:   do {
                   1078: 
                   1079:     /* get the routing for this lane: */
                   1080:     lane_routing = *(lane_routing_init++);
                   1081: 
                   1082:     /* this cannot be a TME_BUS_LANE_WARN, or a TME_BUS_LANE_ABORT, or
                   1083:        an enabled byte lane with an undefined value: */
                   1084:     assert (!(lane_routing & TME_BUS_LANE_WARN)
                   1085:            && lane_routing != TME_BUS_LANE_ABORT
                   1086:            && lane_routing != TME_BUS_LANE_UNDEF);
                   1087: 
                   1088:     /* if this is an enabled byte lane: */
                   1089:     if (__tme_predict_true(!(lane_routing & TME_BUS_LANE_ROUTE_WRITE_IGNORE))) {
                   1090: 
                   1091:       /* get a pointer into the initiator's buffer for this lane: */
                   1092:       buffer_init
                   1093:        = (cycle_init->tme_bus_cycle_buffer
                   1094:           + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing,
                   1095:                                            buffer_increment_mask_init));
                   1096: 
                   1097:       /* transfer the byte: */
                   1098:       if (writer_init) {
                   1099:        *buffer_resp = *buffer_init;
                   1100:       }
                   1101:       else {
                   1102:        *buffer_init = *buffer_resp;
                   1103:       }
                   1104: 
                   1105:       /* update the cycle size for the initiator: */
                   1106:       if (lane_routing >= cycle_size_init) {
                   1107:        cycle_size_init = lane_routing + 1;
                   1108:       }
                   1109:     }
                   1110: 
                   1111:     /* update the pointer into the responder's buffer for the next lane: */
                   1112:     buffer_resp += (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG ? -1 : 1);
                   1113: 
                   1114:   } while (--lane_count > 0);
                   1115: 
                   1116:   /* give the initiator feedback: */
                   1117:   cycle_init->tme_bus_cycle_size = cycle_size_init;
                   1118:   cycle_init->tme_bus_cycle_address += cycle_size_init;
                   1119:   cycle_init->tme_bus_cycle_buffer += 
                   1120:     _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_init,
                   1121:                                   buffer_increment_mask_init);
                   1122: }

unix.superglobalmegacorp.com

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