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

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

unix.superglobalmegacorp.com

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