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

1.1.1.4 ! root        1: /* $Id: bus-el.c,v 1.17 2007/03/25 21:17:01 fredette Exp $ */
1.1       root        2: 
1.1.1.2   root        3: /* generic/bus-el.c - a real generic bus element: */
1.1       root        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-el.c,v 1.17 2007/03/25 21:17:01 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
1.1.1.3   root       40: #define TME_BUS_VERSION TME_X_VERSION(0, 0)
1.1       root       41: #include <tme/generic/bus.h>
                     42: #include <stdlib.h>
                     43: #include <string.h>
                     44: 
                     45: /* macros: */
                     46: 
1.1.1.3   root       47: /* globals: */
                     48: 
                     49: /* the generic bus signals: */
                     50: static const struct tme_bus_signals _tme_bus_signals_default[] = {
                     51:   TME_BUS_SIGNALS_GENERIC
                     52: };
                     53: 
                     54: /* this adds a bus signal set to the bus: */
                     55: static int
                     56: _tme_bus_signals_add(struct tme_bus_connection *conn_bus_caller,
                     57:                     struct tme_bus_signals *bus_signals)
                     58: {
                     59:   struct tme_bus *bus;
                     60:   unsigned int signal_i;
                     61:   tme_uint32_t signals_count_new;
                     62:   tme_uint32_t signals_count_old;
                     63:   struct tme_bus_connection_int *conn_bus_int;
                     64:   int rc;
                     65: 
                     66:   /* recover our bus: */
                     67:   bus = conn_bus_caller->tme_bus_connection.tme_connection_element->tme_element_private;
                     68: 
                     69:   /* lock the bus for writing: */
                     70:   rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                     71:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                     72:     return (TME_THREADS_ERRNO(rc));
                     73:   }
                     74: 
                     75:   /* search for an existing bus signals set that matches the caller's: */
                     76:   for (signal_i = 0;
                     77:        signal_i < bus->tme_bus_signals_count;
                     78:        signal_i++) {
                     79: 
                     80:     /* stop if this existing bus signals set has the right ID and the
                     81:        versions overlap: */
                     82:     if ((bus->tme_bus_signals[signal_i].tme_bus_signals_id
                     83:         == bus_signals->tme_bus_signals_id)
                     84:        && TME_X_VERSION_OK(bus->tme_bus_signals[signal_i].tme_bus_signals_version,
                     85:                            bus_signals->tme_bus_signals_version)) {
                     86:       break;
                     87:     }
                     88:   }
                     89: 
                     90:   /* assume that this call succeeds: */
                     91:   rc = TME_OK;
                     92: 
                     93:   /* if an existing bus signals set was not found: */
                     94:   if (signal_i == bus->tme_bus_signals_count) {
                     95: 
                     96:     /* get the old count of bus signals from the current last bus
                     97:        signals set in the bus signals sets array: */
                     98:     signals_count_old =
                     99:       (TME_BUS_SIGNAL_INDEX(bus->tme_bus_signals[bus->tme_bus_signals_count - 1].tme_bus_signals_first)
                    100:        + bus->tme_bus_signals[bus->tme_bus_signals_count - 1].tme_bus_signals_count);
                    101: 
                    102:     /* resize the bus signals sets array: */
                    103:     bus->tme_bus_signals
                    104:       = tme_renew(struct tme_bus_signals,
                    105:                  bus->tme_bus_signals,
                    106:                  bus->tme_bus_signals_count
                    107:                  + 1);
                    108: 
                    109:     /* add the new bus signals set: */
                    110:     signals_count_new = signals_count_old + bus_signals->tme_bus_signals_count;
                    111:     assert (signals_count_new > signals_count_old);
                    112:     bus_signals->tme_bus_signals_first = TME_BUS_SIGNAL_X(signals_count_old);
                    113:     bus->tme_bus_signals[bus->tme_bus_signals_count] = *bus_signals;
                    114:     bus->tme_bus_signals_count++;
                    115: 
                    116:     /* reallocate the bus' asserted-signals count array: */
                    117:     bus->tme_bus_signal_asserts
                    118:       = tme_renew(unsigned int,
                    119:                  bus->tme_bus_signal_asserts,
                    120:                  signals_count_new);
                    121:     memset ((char *) &bus->tme_bus_signal_asserts[signals_count_old],
                    122:            0,
                    123:            (sizeof(bus->tme_bus_signal_asserts[0])
                    124:             * (signals_count_new
                    125:                - signals_count_old)));
                    126: 
                    127:     /* if needed, reallocate each connection's asserted-signals
                    128:        bitmap: */
                    129:     if (TME_BUS_SIGNAL_BIT_BYTES(signals_count_new)
                    130:        > TME_BUS_SIGNAL_BIT_BYTES(signals_count_old)) {
                    131:       for (conn_bus_int = bus->tme_bus_connections;
                    132:           conn_bus_int != NULL;
                    133:           conn_bus_int =
                    134:             (struct tme_bus_connection_int *) 
                    135:             conn_bus_int->tme_bus_connection_int
                    136:             .tme_bus_connection
                    137:             .tme_connection_next) {
                    138:        conn_bus_int->tme_bus_connection_int_signals
                    139:          = tme_renew(tme_uint8_t,
                    140:                      conn_bus_int->tme_bus_connection_int_signals,
                    141:                      TME_BUS_SIGNAL_BIT_BYTES(signals_count_new));
                    142:        memset ((char *) &conn_bus_int->tme_bus_connection_int_signals[TME_BUS_SIGNAL_BIT_BYTES(signals_count_old)],
                    143:                0,
                    144:                (sizeof (conn_bus_int->tme_bus_connection_int_signals[0])
                    145:                 * (TME_BUS_SIGNAL_BIT_BYTES(signals_count_new)
                    146:                    - TME_BUS_SIGNAL_BIT_BYTES(signals_count_old))));
                    147:       }
                    148:     }
                    149:   }
                    150: 
                    151:   /* otherwise, we found an existing bus signals set.  however, even
                    152:      though the versions overlap, if they don't support the same least
                    153:      version, something is wrong: */
                    154:   else if ((TME_X_VERSION_CURRENT(bus->tme_bus_signals[signal_i].tme_bus_signals_version)
                    155:            - TME_X_VERSION_AGE(bus->tme_bus_signals[signal_i].tme_bus_signals_version))
                    156:           != (TME_X_VERSION_CURRENT(bus_signals->tme_bus_signals_version)
                    157:               - TME_X_VERSION_AGE(bus_signals->tme_bus_signals_version))) {
                    158:     rc = EINVAL;
                    159:   }
                    160: 
                    161:   /* otherwise, we found an existing bus signals set that fully matches
                    162:      and is compatible with the caller's: */
                    163:   else {
                    164:     
                    165:     /* update the versioning on this bus signals set: */
                    166:     if (TME_X_VERSION_CURRENT(bus_signals->tme_bus_signals_version)
                    167:        > TME_X_VERSION_CURRENT(bus->tme_bus_signals[signal_i].tme_bus_signals_version)) {
                    168:       bus->tme_bus_signals[signal_i].tme_bus_signals_version = bus_signals->tme_bus_signals_version;
                    169:     }
                    170: 
                    171:     /* return the existing bus signals set: */
                    172:     *bus_signals = bus->tme_bus_signals[signal_i];
                    173:   }
                    174:     
                    175:   /* unlock the bus and return: */
                    176:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    177:   return (rc);
                    178: }
1.1       root      179: 
                    180: /* this handles a bus connection signal edge: */
                    181: static int
                    182: _tme_bus_signal(struct tme_bus_connection *conn_bus_edger, unsigned int signal)
                    183: {
                    184:   struct tme_bus *bus;
                    185:   struct tme_bus_connection_int *conn_bus_int_edger;
                    186:   struct tme_bus_connection_int *conn_bus_int;
                    187:   unsigned int level_edge;
                    188:   struct tme_bus_connection *conn_bus;
                    189:   struct tme_bus_connection *conn_bus_other;
                    190:   int signal_asserted, need_propagate;
                    191:   unsigned int signal_index;
                    192:   tme_uint8_t signal_mask;
                    193:   int rc;
                    194:   int deadlocked;
                    195: 
                    196:   /* recover our bus: */
                    197:   bus = conn_bus_edger->tme_bus_connection.tme_connection_element->tme_element_private;
                    198:   conn_bus_int_edger = (struct tme_bus_connection_int *) conn_bus_edger;
                    199: 
                    200:   /* take out the level and edge: */
1.1.1.3   root      201:   level_edge = signal;
                    202:   signal = TME_BUS_SIGNAL_WHICH(signal);
                    203:   level_edge ^= signal;
1.1       root      204: 
                    205:   /* lock the bus for writing: */
                    206:   rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    207:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    208:     return (TME_THREADS_ERRNO(rc));
                    209:   }
                    210:   
                    211:   /* if this device doesn't know its interrupt signal, fix it: */
                    212:   if (signal == TME_BUS_SIGNAL_INT_UNSPEC) {
                    213:     signal = conn_bus_int_edger->tme_bus_connection_int_signal_int;
                    214:     if (signal == TME_BUS_SIGNAL_INT_UNSPEC) {
                    215:       /* this bus connection is misconfigured: */
                    216:       if (!conn_bus_int_edger->tme_bus_connection_int_logged_int) {
                    217:        conn_bus_int_edger->tme_bus_connection_int_logged_int = TRUE;
                    218:        /* XXX diagnostic */
                    219:        abort();
                    220:       }
                    221:       tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    222:       return (TME_OK);
                    223:     }
                    224:   }
                    225: 
                    226:   /* assume we don't need to propagate this signal across the bus: */
                    227:   need_propagate = FALSE;
                    228: 
1.1.1.3   root      229:   /* see whether the device is asserting or negating this signal.  iff
                    230:      one or more devices on a bus are asserting a signal, the signal
                    231:      appears asserted on the bus.  this gives an ORed effect: */
                    232:   signal_asserted = TRUE;
                    233:   switch (level_edge & TME_BUS_SIGNAL_LEVEL_MASK) {
                    234:   case TME_BUS_SIGNAL_LEVEL_NEGATED:
                    235:     signal_asserted = FALSE;
                    236:   case TME_BUS_SIGNAL_LEVEL_ASSERTED:
                    237:     break;
                    238:   default:
                    239:     abort();
1.1       root      240:   }
                    241: 
1.1.1.3   root      242:   /* get the index and mask of this signal in signal byte arrays: */
                    243:   signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal);
                    244:   signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal);
1.1       root      245: 
1.1.1.3   root      246:   /* if this signal is being asserted: */
                    247:   if (signal_asserted) {
                    248: 
                    249:     /* if this device wasn't already asserting this signal: */
                    250:     if (!(conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
                    251:          & signal_mask)) {
                    252: 
                    253:       /* it is now asserting this signal: */
                    254:       conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
                    255:        |= signal_mask;
                    256:       bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)]++;
                    257: 
                    258:       /* if this is the only device asserting this signal,
                    259:         propagate the change across the bus: */
                    260:       if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] == 1) {
                    261:        need_propagate = TRUE;
1.1       root      262:       }
                    263:     }
                    264: 
1.1.1.3   root      265:     /* otherwise, this device was already asserting this signal: */
1.1       root      266:     else {
1.1.1.3   root      267:       assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] > 0);
                    268:     }
                    269:   }
1.1       root      270: 
1.1.1.3   root      271:   /* otherwise, this signal is being negated: */
                    272:   else {
                    273: 
                    274:     /* if this device was asserting this signal: */
                    275:     if (conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
                    276:        & signal_mask) {
1.1       root      277: 
1.1.1.3   root      278:       /* it is no longer asserting this signal: */
                    279:       conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
                    280:        &= ~signal_mask;
                    281:       assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] > 0);
                    282:       bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)]--;
                    283: 
                    284:       /* if this was the last device asserting this signal, propagate
                    285:         the change across the bus: */
                    286:       if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] == 0) {
                    287:        need_propagate = TRUE;
1.1       root      288:       }
1.1.1.3   root      289:     }
                    290: 
                    291:     /* otherwise, this device was not asserting this signal, but it
                    292:        negated it anyways.  often, lazy code will only send negating
                    293:        edges for signals (for example, see the do_reset code in
                    294:        machine/sun2/sun2-mainbus.c, which should really assert RESET,
                    295:        sleep, then negate it), so if we get a negated edge for a
                    296:        signal that no one else (including the edger) was asserting, we
                    297:        propagate the edge anyways.
                    298: 
                    299:        so, TME_BUS_SIGNAL_EDGE should only be used for this purpose: */
                    300:     else if ((level_edge & TME_BUS_SIGNAL_EDGE)
                    301:             && bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] == 0) {
1.1       root      302:       need_propagate = TRUE;
                    303:     }
                    304:   }
                    305: 
                    306:   /* if we're propagating this signal across the bus: */
                    307:   rc = TME_OK;
                    308:   if (need_propagate) {
                    309: 
                    310:     /* put the level and edge back in: */
                    311:     signal |= level_edge;
                    312: 
                    313:     /* assume that we won't deadlock: */
                    314:     deadlocked = FALSE;
                    315: 
                    316:     /* propagate the signal to each connection to the bus: */
                    317:     for (conn_bus_int = bus->tme_bus_connections;
                    318:         conn_bus_int != NULL;
                    319:         conn_bus_int =
                    320:           (struct tme_bus_connection_int *) 
                    321:           conn_bus_int->tme_bus_connection_int
                    322:           .tme_bus_connection
                    323:           .tme_connection_next) {
                    324:       conn_bus = &conn_bus_int->tme_bus_connection_int;
                    325:       conn_bus_other = 
                    326:        (struct tme_bus_connection *) 
                    327:        conn_bus->tme_bus_connection.tme_connection_other;
                    328:       
                    329:       /* skip this device if it edged the line to begin with: */
                    330:       if (conn_bus == conn_bus_edger) {
                    331:        continue;
                    332:       }
                    333: 
                    334:       /* skip this device if it doesn't care about bus signals: */
                    335:       if (conn_bus_other->tme_bus_signal == NULL) {
                    336:        continue;
                    337:       }
                    338: 
                    339:       /* give the edge to this connection: */
                    340:       rc =  (*conn_bus_other->tme_bus_signal)(conn_bus_other, signal);
                    341: 
                    342:       /* if we deadlocked, remember to tell the caller: */
                    343:       if (rc == TME_EDEADLK) {
                    344:        deadlocked = TRUE;
                    345:       }
                    346:     }
                    347:     rc = (deadlocked ? TME_EDEADLK : TME_OK);
                    348:   }
                    349: 
                    350:   /* unlock the bus: */
                    351:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    352: 
                    353:   /* done: */
                    354:   return (rc);
                    355: }
                    356:                              
                    357: /* this handles a bus interrupt acknowledge: */
                    358: static int
                    359: _tme_bus_intack(struct tme_bus_connection *conn_bus_acker, unsigned int signal, int *vector)
                    360: {
                    361:   struct tme_bus *bus;
                    362:   struct tme_bus_connection_int *conn_bus_int;
                    363:   struct tme_bus_connection *conn_bus;
                    364:   struct tme_bus_connection *conn_bus_other;
                    365:   unsigned int signal_index;
                    366:   tme_uint8_t signal_mask;
                    367:   int rc;
                    368: 
                    369:   /* recover our bus: */
                    370:   bus = conn_bus_acker->tme_bus_connection.tme_connection_element->tme_element_private;
                    371: 
                    372:   /* get rid of any level and edge: */
1.1.1.3   root      373:   signal = TME_BUS_SIGNAL_WHICH(signal);
1.1       root      374: 
                    375:   /* this must be an interrupt signal: */
                    376:   assert(TME_BUS_SIGNAL_IS_INT(signal));
                    377: 
                    378:   /* lock the bus for writing: */
                    379:   rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    380:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    381:     return (TME_THREADS_ERRNO(rc));
                    382:   }
                    383:   
                    384:   /* get the index and mask of this signal in signal byte arrays: */
                    385:   signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal);
                    386:   signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal);
                    387: 
                    388:   /* find the first connection to the bus that is asserting this
                    389:      interrupt signal.  if no connection is asserting the signal,
                    390:      return ENOENT: */
                    391:   rc = ENOENT;
                    392:   for (conn_bus_int = bus->tme_bus_connections;
                    393:        conn_bus_int != NULL;
                    394:        conn_bus_int =
                    395:         (struct tme_bus_connection_int *) 
                    396:         conn_bus_int->tme_bus_connection_int
                    397:         .tme_bus_connection
                    398:         .tme_connection_next) {
                    399:     conn_bus = &conn_bus_int->tme_bus_connection_int;
                    400:     conn_bus_other = 
                    401:       (struct tme_bus_connection *) 
                    402:       conn_bus->tme_bus_connection.tme_connection_other;
                    403:     
                    404:     /* if this device is asserting this interrupt signal: */
                    405:     if (conn_bus_int->tme_bus_connection_int_signals[signal_index]
                    406:        & signal_mask) {
                    407: 
1.1.1.4 ! root      408:       /* unlock the bus: */
        !           409:       tme_rwlock_unlock(&bus->tme_bus_rwlock);
        !           410: 
1.1.1.3   root      411:       /* if this device doesn't acknowledge interrupts, return any
                    412:         user-specified vector or TME_BUS_INTERRUPT_VECTOR_UNDEF: */
1.1       root      413:       if (conn_bus_other->tme_bus_intack == NULL) {
1.1.1.3   root      414:        *vector = conn_bus_int->tme_bus_connection_int_vector_int;
1.1       root      415:        rc = TME_OK;
                    416:       }
                    417: 
                    418:       /* otherwise, run the interrupt acknowledge with this connection: */
                    419:       else {
                    420:        rc = (*conn_bus_other->tme_bus_intack)(conn_bus_other, signal, vector);
                    421:       }
                    422: 
1.1.1.4 ! root      423:       /* done: */
        !           424:       return (rc);
1.1       root      425:     }
                    426:   }
                    427: 
                    428:   /* unlock the bus: */
                    429:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    430: 
                    431:   /* done: */
                    432:   return (rc);
                    433: }
                    434: 
                    435: static int
                    436: _tme_bus_fault(void *junk0, struct tme_bus_cycle *junk1)
                    437: {
                    438:   return (ENOENT);
                    439: }
                    440: 
                    441: /* this fills a TLB entry: */
                    442: static int
                    443: _tme_bus_tlb_fill(struct tme_bus_connection *conn_bus_asker, 
                    444:                  struct tme_bus_tlb *tlb,
                    445:                  tme_bus_addr_t address, 
                    446:                  unsigned int cycles)
                    447: {
                    448:   struct tme_bus *bus;
                    449:   struct tme_bus_connection_int *conn_int;
                    450:   int rc;
                    451: 
                    452:   /* recover our bus and our connection to the asker: */
                    453:   bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
                    454:   conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
                    455: 
                    456:   /* put our fault handler in the TLB entry: */
                    457:   tlb->tme_bus_tlb_cycle_private = NULL;
                    458:   tlb->tme_bus_tlb_cycle = _tme_bus_fault;
                    459: 
                    460:   /* lock the bus for reading: */
                    461:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    462:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    463:     return (TME_THREADS_ERRNO(rc));
                    464:   }
                    465: 
                    466:   /* call the generic bus support function: */
                    467:   rc = tme_bus_tlb_fill(bus,
                    468:                        conn_int,
                    469:                        tlb, address, cycles);
                    470: 
                    471:   /* unlock the bus: */
                    472:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    473: 
                    474:   /* done: */
                    475:   return (rc);
                    476: }
                    477: 
                    478: /* this allocates a new TLB set: */
                    479: static int
                    480: _tme_bus_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
                    481:                          unsigned int count, unsigned int sizeof_one, 
1.1.1.4 ! root      482:                          struct tme_bus_tlb * tme_shared *_tlbs,
        !           483:                          tme_rwlock_t *_tlbs_rwlock)
1.1       root      484: {
                    485:   struct tme_bus *bus;
                    486:   struct tme_bus_connection_int *conn_int;
                    487:   int rc;
                    488: 
                    489:   /* recover our bus and our connection to the asker: */
                    490:   bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
                    491:   conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
                    492: 
                    493:   /* lock the bus for reading: */
                    494:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    495:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    496:     return (TME_THREADS_ERRNO(rc));
                    497:   }
                    498: 
                    499:   /* call the generic bus support function: */
                    500:   rc = tme_bus_tlb_set_allocate(bus,
                    501:                                conn_int,
                    502:                                count, sizeof_one, 
1.1.1.4 ! root      503:                                _tlbs,
        !           504:                                _tlbs_rwlock);
1.1       root      505: 
                    506:   /* unlock the bus: */
                    507:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    508: 
                    509:   /* done: */
                    510:   return (rc);
                    511: }
                    512: 
                    513: /* this scores a new connection: */
                    514: static int
                    515: _tme_bus_connection_score(struct tme_connection *conn, unsigned int *_score)
                    516: {
                    517:   struct tme_bus *bus;
                    518:   struct tme_bus_connection_int *conn_int;
                    519:   int rc, ok;
                    520: 
                    521:   /* both sides must be generic bus connections: */
                    522:   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    523:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    524: 
                    525:   /* recover our bus and our internal connection side: */
                    526:   bus = conn->tme_connection_element->tme_element_private;
                    527:   conn_int = (struct tme_bus_connection_int *) conn;
                    528: 
                    529:   /* lock the bus for reading: */
                    530:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    531:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    532:     return (TME_THREADS_ERRNO(rc));
                    533:   }
                    534:   
                    535:   /* call the generic bus support function: */
                    536:   ok = tme_bus_connection_ok(bus,
                    537:                             conn_int);
                    538: 
                    539:   /* unlock the bus: */
                    540:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    541: 
                    542:   /* return the score: */
                    543:   *_score = (ok ? 1 : 0);
                    544:   return (TME_OK);
                    545: }
                    546: 
                    547: /* this makes a new connection: */
                    548: static int
                    549: _tme_bus_connection_make(struct tme_connection *conn, unsigned int state)
                    550: {
                    551:   struct tme_bus *bus;
                    552:   struct tme_bus_connection_int *conn_int;
1.1.1.3   root      553:   const struct tme_bus_signals *bus_signals;
1.1       root      554:   int rc;
                    555: 
                    556:   /* both sides must be generic bus connections: */
                    557:   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    558:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    559: 
                    560:   /* recover our bus and our internal connection side: */
                    561:   bus = conn->tme_connection_element->tme_element_private;
                    562:   conn_int = (struct tme_bus_connection_int *) conn;
                    563:   
                    564:   /* lock the bus for writing: */
                    565:   rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    566:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    567:     return (TME_THREADS_ERRNO(rc));
                    568:   }
                    569: 
                    570:   /* call the generic bus support function: */
                    571:   rc = tme_bus_connection_make(bus,
                    572:                               conn_int,
                    573:                               state);
                    574: 
1.1.1.3   root      575:   /* XXX this is a perfect example of the poor division between
                    576:      bus-el.c and bus.c.  should the signal handling code be in bus.c?  */
                    577:   if (rc == TME_OK) {
                    578:     bus_signals = &bus->tme_bus_signals[bus->tme_bus_signals_count - 1];
                    579:     conn_int->tme_bus_connection_int_signals
                    580:       = tme_new0(tme_uint8_t,
                    581:                 TME_BUS_SIGNAL_BIT_BYTES(TME_BUS_SIGNAL_INDEX(bus_signals->tme_bus_signals_first)
                    582:                                          + bus_signals->tme_bus_signals_count));
                    583:   }
                    584: 
1.1       root      585:   /* unlock the bus: */
                    586:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    587: 
                    588:   return (rc);
                    589: }
                    590: 
                    591: /* this breaks a connection: */
                    592: static int 
                    593: _tme_bus_connection_break(struct tme_connection *conn, unsigned int state)
                    594: {
                    595:   abort();
                    596: }
                    597: 
                    598: /* this returns the new connections possible: */
                    599: static int
                    600: _tme_bus_connections_new(struct tme_element *element,
                    601:                         const char * const *args,
                    602:                         struct tme_connection **_conns,
                    603:                         char **_output)
                    604: {
                    605:   const struct tme_bus *bus;
                    606:   struct tme_bus_connection_int *conn_int;
                    607:   struct tme_bus_connection *conn_bus;
                    608:   struct tme_connection *conn;
                    609:   int ipl;
1.1.1.3   root      610:   int vector;
1.1.1.4 ! root      611:   const struct tme_bus_slot *bus_slot;
1.1       root      612:   int arg_i;
                    613:   int usage;
                    614: 
                    615:   /* recover our bus.  we only read the address mask, so we don't lock
                    616:      the rwlock: */
                    617:   bus = element->tme_element_private;
                    618: 
                    619:   /* allocate the new connection side: */
                    620:   conn_int = tme_new0(struct tme_bus_connection_int, 1);
                    621:   conn_bus = &conn_int->tme_bus_connection_int;
                    622:   conn = &conn_bus->tme_bus_connection;
                    623: 
                    624:   /* loop reading our arguments: */
                    625:   usage = FALSE;
                    626:   arg_i = 1;
1.1.1.3   root      627:   conn_int->tme_bus_connection_int_vector_int = TME_BUS_INTERRUPT_VECTOR_UNDEF;
1.1.1.4 ! root      628:   bus_slot = NULL;
1.1       root      629:   for (;;) {
                    630: 
                    631:     /* the address of this connection: */
                    632:     if (TME_ARG_IS(args[arg_i + 0], "addr")) {
1.1.1.4 ! root      633:       conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE;
1.1       root      634:       conn_int->tme_bus_connection_int_address = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
                    635:       if (usage
                    636:          || (conn_int->tme_bus_connection_int_address
                    637:              > bus->tme_bus_address_mask)) {
                    638:        usage = TRUE;
                    639:        break;
                    640:       }
                    641:       arg_i += 2;
                    642:     }
                    643: 
                    644:     /* the interrupt signal for this connection: */
                    645:     else if (TME_ARG_IS(args[arg_i + 0], "ipl")
                    646:             && args[arg_i + 1] != NULL
                    647:             && (ipl = atoi(args[arg_i + 1])) > 0) {
                    648:       conn_int->tme_bus_connection_int_signal_int = TME_BUS_SIGNAL_INT(ipl);
                    649:       arg_i += 2;
                    650:     }
                    651: 
1.1.1.3   root      652:     /* the interrupt vector for this connection: */
                    653:     else if (TME_ARG_IS(args[arg_i + 0], "vector")
                    654:             && args[arg_i + 1] != NULL
                    655:             && (vector = atoi(args[arg_i + 1])) > 0) {
                    656:       conn_int->tme_bus_connection_int_vector_int = vector;
                    657:       arg_i += 2;
                    658:     }      
                    659: 
1.1.1.4 ! root      660:     /* the slot for this connection: */
        !           661:     else if (TME_ARG_IS(args[arg_i + 0], "slot")
        !           662:             && args[arg_i + 1] != NULL) {
        !           663: 
        !           664:       /* you can't give more than one slot for a connection: */
        !           665:       if (bus_slot != NULL) {
        !           666:        tme_output_append_error(_output,
        !           667:                                "slot %s %s, ",
        !           668:                                args[arg_i + 1],
        !           669:                                _("redefined"));
        !           670:        usage = TRUE;
        !           671:        break;
        !           672:       }
        !           673: 
        !           674:       /* make sure this slot has been defined: */
        !           675:       for (bus_slot = bus->tme_bus_slots;
        !           676:           bus_slot != NULL;
        !           677:           bus_slot = bus_slot->tme_bus_slot_next) {
        !           678:        if (strcmp(bus_slot->tme_bus_slot_name,
        !           679:                   args[arg_i + 1]) == 0) {
        !           680:          break;
        !           681:        }
        !           682:       }
        !           683:       if (bus_slot == NULL) {
        !           684:        tme_output_append_error(_output,
        !           685:                                "slot %s %s, ",
        !           686:                                args[arg_i + 1],
        !           687:                                _("unknown"));
        !           688:        usage = TRUE;
        !           689:        break;
        !           690:       }
        !           691:       arg_i += 2;
        !           692:     }
        !           693: 
        !           694:     /* the slot offset for this connection: */
        !           695:     else if (TME_ARG_IS(args[arg_i + 0], "offset")) {
        !           696:       if (bus_slot == NULL) {
        !           697:        tme_output_append_error(_output,
        !           698:                                "slot %s, ",
        !           699:                                _("unknown"));
        !           700:        usage = TRUE;
        !           701:        break;
        !           702:       }
        !           703:       conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE;
        !           704:       conn_int->tme_bus_connection_int_address
        !           705:        = (bus_slot->tme_bus_slot_address
        !           706:           + tme_bus_addr_parse_any(args[arg_i + 1], &usage));
        !           707:       if (usage
        !           708:          || (conn_int->tme_bus_connection_int_address
        !           709:              > bus->tme_bus_address_mask)) {
        !           710:        usage = TRUE;
        !           711:        break;
        !           712:       }
        !           713:       arg_i += 2;
        !           714:     }
        !           715: 
        !           716:     /* if this connection is for a slot controller: */
        !           717:     else if (TME_ARG_IS(args[arg_i + 0], "controller")) {
        !           718:       if (bus->tme_bus_controller != NULL) {
        !           719:        tme_free(conn_int);
        !           720:        return (EEXIST);
        !           721:       }
        !           722:       conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_CONTROLLER;
        !           723:       arg_i++;
        !           724:     }
        !           725: 
        !           726:     /* if this connection has an automatic DMA offset: */
        !           727:     else if (TME_ARG_IS(args[arg_i + 0], "dma-offset")) {
        !           728:       conn_int->tme_bus_connection_int_sourced = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
        !           729:       if (usage
        !           730:          || (conn_int->tme_bus_connection_int_sourced
        !           731:              > bus->tme_bus_address_mask)) {
        !           732:        usage = TRUE;
        !           733:        break;
        !           734:       }
        !           735:       arg_i += 2;
        !           736:     }
        !           737: 
1.1       root      738:     /* if we've run out of arguments: */
                    739:     else if (args[arg_i + 0] == NULL) {
                    740:       break;
                    741:     }
                    742: 
                    743:     /* this is a bad argument: */
                    744:     else {
                    745:       tme_output_append_error(_output,
                    746:                              "%s %s, ",
                    747:                              args[arg_i],
                    748:                              _("unexpected"));
                    749:       usage = TRUE;
                    750:       break;
                    751:     }
                    752:   }
                    753: 
                    754:   if (usage) {
                    755:     tme_output_append_error(_output, 
1.1.1.4 ! root      756:                            "%s %s [ controller ] [ addr %s ] [ slot %s offset %s ] [ dma-offset %s ] [ ipl %s ] [ vector %s ]",
1.1       root      757:                            _("usage:"),
                    758:                            args[0],
                    759:                            _("BUS-ADDRESS"),
1.1.1.4 ! root      760:                            _("SLOT"),
        !           761:                            _("OFFSET"),
        !           762:                            _("OFFSET"),
1.1.1.3   root      763:                            _("INTERRUPT-LEVEL"),
                    764:                            _("INTERRUPT-VECTOR"));
1.1       root      765:     tme_free(conn_int);
                    766:     return (EINVAL);
                    767:   }
                    768: 
                    769:   /* fill in the bus connection: */
1.1.1.2   root      770:   conn_bus->tme_bus_subregions.tme_bus_subregion_address_first
                    771:     = 0;
                    772:   conn_bus->tme_bus_subregions.tme_bus_subregion_address_last
                    773:     = bus->tme_bus_address_mask;
                    774:   conn_bus->tme_bus_subregions.tme_bus_subregion_next
                    775:     = NULL;
1.1.1.3   root      776:   conn_bus->tme_bus_signals_add = _tme_bus_signals_add;
1.1       root      777:   conn_bus->tme_bus_signal = _tme_bus_signal;
                    778:   conn_bus->tme_bus_intack = _tme_bus_intack;
                    779:   conn_bus->tme_bus_tlb_set_allocate = _tme_bus_tlb_set_allocate;
                    780:   conn_bus->tme_bus_tlb_fill = _tme_bus_tlb_fill;
                    781: 
                    782:   /* fill in the generic connection: */
                    783:   conn->tme_connection_next = *_conns;
                    784:   conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
                    785:   conn->tme_connection_score = _tme_bus_connection_score;
                    786:   conn->tme_connection_make = _tme_bus_connection_make;
                    787:   conn->tme_connection_break = _tme_bus_connection_break;
                    788:   
                    789:   /* return the new connection side: */
                    790:   *_conns = conn;
                    791:   return (TME_OK);
                    792: }
                    793: 
                    794: /* this creates a new bus element: */
                    795: TME_ELEMENT_SUB_NEW_DECL(tme_generic,bus) {
                    796:   struct tme_bus *bus;
1.1.1.4 ! root      797:   tme_bus_addr_t bus_size_mask;
        !           798:   tme_bus_addr_t bus_slot_size;
        !           799:   tme_bus_addr_t bus_slot_addr;
        !           800:   int bus_slot_addr_defined;
        !           801:   struct tme_bus_slot *bus_slot;
        !           802:   struct tme_bus_slot *bus_slots;
        !           803:   int arg_i;
1.1       root      804:   int failed;
                    805: 
                    806:   /* our arguments must include the bus size, and the
                    807:      bus size must be a power of two: */
1.1.1.4 ! root      808:   failed = FALSE;
        !           809:   arg_i = 1;
        !           810:   bus_size_mask = 0;
        !           811:   bus_slot_size = 0;
        !           812:   bus_slot_addr_defined = FALSE;
        !           813:   bus_slot_addr = 0;
        !           814:   bus_slots = NULL;
        !           815:   for (; !failed; ) {
        !           816: 
        !           817:     /* the bus size: */
        !           818:     if (TME_ARG_IS(args[arg_i + 0], "size")) {
        !           819:       /* XXX FIXME - this is a hack: */
        !           820:       if (sizeof(bus_size_mask) == sizeof(tme_uint32_t) &&
        !           821:          TME_ARG_IS(args[arg_i + 1], "4GB")) {
        !           822:        bus_size_mask = ((tme_bus_addr_t) 0) - 1;
        !           823:       }
        !           824:       else {
        !           825:        bus_size_mask = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
        !           826:        if (!failed
        !           827:            && bus_size_mask < 2) {
        !           828:          failed = TRUE;
        !           829:        }
        !           830:        else {
        !           831:          bus_size_mask -= 1;
        !           832:        }
        !           833:       }
        !           834:       if (bus_size_mask & (bus_size_mask + 1)) {
        !           835:        failed = TRUE;
        !           836:       }
        !           837:       arg_i += 2;
1.1.1.3   root      838:     }
1.1.1.4 ! root      839: 
        !           840:     /* the address for the next slots: */
        !           841:     else if (TME_ARG_IS(args[arg_i + 0], "slot-addr")) {
        !           842:       bus_slot_addr = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
        !           843:       bus_slot_addr_defined = TRUE;
        !           844:       arg_i += 2;
        !           845:     }
        !           846: 
        !           847:     /* the size for the next slots: */
        !           848:     else if (TME_ARG_IS(args[arg_i + 0], "slot-size")) {
        !           849:       bus_slot_size = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
        !           850:       if (bus_slot_size < 1) {
        !           851:        failed = TRUE;
        !           852:       }
        !           853:       arg_i += 2;
1.1.1.3   root      854:     }
1.1.1.4 ! root      855: 
        !           856:     /* a slot definition: */
        !           857:     else if (TME_ARG_IS(args[arg_i + 0], "slot")) {
        !           858:       if (args[arg_i + 1] == NULL) {
        !           859:        failed = TRUE;
        !           860:        break;
        !           861:       }
        !           862:       if (!bus_slot_addr_defined) {
        !           863:        failed = TRUE;
        !           864:        break;
        !           865:       }
        !           866:       if (bus_slot_size == 0) {
        !           867:        failed = TRUE;
        !           868:        break;
        !           869:       }
        !           870: 
        !           871:       /* make sure this slot hasn't already been defined: */
        !           872:       for (bus_slot = bus_slots;
        !           873:           bus_slot != NULL;
        !           874:           bus_slot = bus_slot->tme_bus_slot_next) {
        !           875:        if (strcmp(bus_slot->tme_bus_slot_name,
        !           876:                   args[arg_i + 1]) == 0) {
        !           877:          tme_output_append_error(_output,
        !           878:                                  "slot %s %s",
        !           879:                                  args[arg_i + 1],
        !           880:                                  _("redefined"));
        !           881:          failed = TRUE;
        !           882:          break;
        !           883:        }
        !           884:       }
        !           885:       if (failed) {
        !           886:        break;
        !           887:       }
        !           888: 
        !           889:       /* add this slot: */
        !           890:       bus_slot = tme_new0(struct tme_bus_slot, 1);
        !           891:       bus_slot->tme_bus_slot_next = bus_slots;
        !           892:       bus_slots = bus_slot;
        !           893:       bus_slot->tme_bus_slot_name = tme_strdup(args[arg_i + 1]);
        !           894:       bus_slot->tme_bus_slot_address = bus_slot_addr;
        !           895:       bus_slot->tme_bus_slot_size = bus_slot_size;
        !           896: 
        !           897:       /* advance for the next slot: */
        !           898:       bus_slot_addr += bus_slot_size;
        !           899:       arg_i += 2;
        !           900:     }
        !           901: 
        !           902:     /* if we've run out of arguments: */
        !           903:     else if (args[arg_i + 0] == NULL) {
        !           904:       break;
        !           905:     }
        !           906: 
        !           907:     /* an unknown argument: */
        !           908:     else {
        !           909:       tme_output_append_error(_output,
        !           910:                              "%s %s, ",
        !           911:                              args[arg_i],
        !           912:                              _("unexpected"));
1.1       root      913:       failed = TRUE;
                    914:     }
                    915:   }
                    916:   if (failed) {
                    917:     tme_output_append_error(_output,
1.1.1.4 ! root      918:                            "%s %s size %s [ slot-addr %s slot-size %s slot %s0 .. slot %sN ]",
1.1       root      919:                            _("usage:"),
                    920:                            args[0],
1.1.1.4 ! root      921:                            _("SIZE"),
        !           922:                            _("ADDRESS"),
        !           923:                            _("SIZE"),
        !           924:                            _("SLOT-NAME"),
        !           925:                            _("SLOT-NAME"));
        !           926:     for (; (bus_slot = bus_slots) != NULL; ) {
        !           927:       bus_slots = bus_slots->tme_bus_slot_next;
        !           928:       tme_free(bus_slot->tme_bus_slot_name);
        !           929:       tme_free(bus_slot);
        !           930:     }
1.1       root      931:     return (EINVAL);
                    932:   }
                    933: 
                    934:   /* allocate and initialize the new bus: */
                    935:   bus = tme_new0(struct tme_bus, 1);
                    936:   tme_rwlock_init(&bus->tme_bus_rwlock);
1.1.1.4 ! root      937:   bus->tme_bus_address_mask = bus_size_mask;
1.1       root      938:   bus->tme_bus_addressables_count = 0;
                    939:   bus->tme_bus_addressables_size = 1;
1.1.1.2   root      940:   bus->tme_bus_addressables = tme_new(struct tme_bus_addressable,
1.1       root      941:                                      bus->tme_bus_addressables_size);
1.1.1.3   root      942:   bus->tme_bus_signals_count = TME_ARRAY_ELS(_tme_bus_signals_default);
                    943:   bus->tme_bus_signals = tme_dup(struct tme_bus_signals,
                    944:                                 _tme_bus_signals_default,
                    945:                                 TME_ARRAY_ELS(_tme_bus_signals_default));
                    946:   bus->tme_bus_signal_asserts = tme_new0(unsigned int,
                    947:                                         _tme_bus_signals_default[0].tme_bus_signals_count);
1.1.1.4 ! root      948:   bus->tme_bus_slots = bus_slots;
1.1       root      949: 
                    950:   /* fill the element: */
                    951:   element->tme_element_private = bus;
                    952:   element->tme_element_connections_new = _tme_bus_connections_new;
                    953: 
                    954:   return (TME_OK);
                    955: }

unix.superglobalmegacorp.com

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