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

1.1.1.5 ! root        1: /* $Id: bus-el.c,v 1.18 2009/08/29 17:59:17 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.5 ! root       37: _TME_RCSID("$Id: bus-el.c,v 1.18 2009/08/29 17:59:17 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: 
1.1.1.5 ! root      478: /* this adds a new TLB set: */
1.1       root      479: static int
1.1.1.5 ! root      480: _tme_bus_tlb_set_add(struct tme_bus_connection *conn_bus_asker,
        !           481:                     struct tme_bus_tlb_set_info *tlb_set_info)
1.1       root      482: {
                    483:   struct tme_bus *bus;
                    484:   struct tme_bus_connection_int *conn_int;
                    485:   int rc;
                    486: 
                    487:   /* recover our bus and our connection to the asker: */
                    488:   bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
                    489:   conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
                    490: 
                    491:   /* lock the bus for reading: */
                    492:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    493:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    494:     return (TME_THREADS_ERRNO(rc));
                    495:   }
                    496: 
                    497:   /* call the generic bus support function: */
1.1.1.5 ! root      498:   rc = tme_bus_tlb_set_add(bus,
        !           499:                           conn_int,
        !           500:                           tlb_set_info);
1.1       root      501: 
                    502:   /* unlock the bus: */
                    503:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    504: 
                    505:   /* done: */
                    506:   return (rc);
                    507: }
                    508: 
                    509: /* this scores a new connection: */
                    510: static int
                    511: _tme_bus_connection_score(struct tme_connection *conn, unsigned int *_score)
                    512: {
                    513:   struct tme_bus *bus;
                    514:   struct tme_bus_connection_int *conn_int;
                    515:   int rc, ok;
                    516: 
                    517:   /* both sides must be generic bus connections: */
                    518:   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    519:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    520: 
                    521:   /* recover our bus and our internal connection side: */
                    522:   bus = conn->tme_connection_element->tme_element_private;
                    523:   conn_int = (struct tme_bus_connection_int *) conn;
                    524: 
                    525:   /* lock the bus for reading: */
                    526:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    527:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    528:     return (TME_THREADS_ERRNO(rc));
                    529:   }
                    530:   
                    531:   /* call the generic bus support function: */
                    532:   ok = tme_bus_connection_ok(bus,
                    533:                             conn_int);
                    534: 
                    535:   /* unlock the bus: */
                    536:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    537: 
                    538:   /* return the score: */
                    539:   *_score = (ok ? 1 : 0);
                    540:   return (TME_OK);
                    541: }
                    542: 
                    543: /* this makes a new connection: */
                    544: static int
                    545: _tme_bus_connection_make(struct tme_connection *conn, unsigned int state)
                    546: {
                    547:   struct tme_bus *bus;
                    548:   struct tme_bus_connection_int *conn_int;
1.1.1.3   root      549:   const struct tme_bus_signals *bus_signals;
1.1       root      550:   int rc;
                    551: 
                    552:   /* both sides must be generic bus connections: */
                    553:   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    554:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    555: 
                    556:   /* recover our bus and our internal connection side: */
                    557:   bus = conn->tme_connection_element->tme_element_private;
                    558:   conn_int = (struct tme_bus_connection_int *) conn;
                    559:   
                    560:   /* lock the bus for writing: */
                    561:   rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    562:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    563:     return (TME_THREADS_ERRNO(rc));
                    564:   }
                    565: 
                    566:   /* call the generic bus support function: */
                    567:   rc = tme_bus_connection_make(bus,
                    568:                               conn_int,
                    569:                               state);
                    570: 
1.1.1.3   root      571:   /* XXX this is a perfect example of the poor division between
                    572:      bus-el.c and bus.c.  should the signal handling code be in bus.c?  */
                    573:   if (rc == TME_OK) {
                    574:     bus_signals = &bus->tme_bus_signals[bus->tme_bus_signals_count - 1];
                    575:     conn_int->tme_bus_connection_int_signals
                    576:       = tme_new0(tme_uint8_t,
                    577:                 TME_BUS_SIGNAL_BIT_BYTES(TME_BUS_SIGNAL_INDEX(bus_signals->tme_bus_signals_first)
                    578:                                          + bus_signals->tme_bus_signals_count));
                    579:   }
                    580: 
1.1       root      581:   /* unlock the bus: */
                    582:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    583: 
                    584:   return (rc);
                    585: }
                    586: 
                    587: /* this breaks a connection: */
                    588: static int 
                    589: _tme_bus_connection_break(struct tme_connection *conn, unsigned int state)
                    590: {
                    591:   abort();
                    592: }
                    593: 
                    594: /* this returns the new connections possible: */
                    595: static int
                    596: _tme_bus_connections_new(struct tme_element *element,
                    597:                         const char * const *args,
                    598:                         struct tme_connection **_conns,
                    599:                         char **_output)
                    600: {
                    601:   const struct tme_bus *bus;
                    602:   struct tme_bus_connection_int *conn_int;
                    603:   struct tme_bus_connection *conn_bus;
                    604:   struct tme_connection *conn;
                    605:   int ipl;
1.1.1.3   root      606:   int vector;
1.1.1.4   root      607:   const struct tme_bus_slot *bus_slot;
1.1       root      608:   int arg_i;
                    609:   int usage;
                    610: 
                    611:   /* recover our bus.  we only read the address mask, so we don't lock
                    612:      the rwlock: */
                    613:   bus = element->tme_element_private;
                    614: 
                    615:   /* allocate the new connection side: */
                    616:   conn_int = tme_new0(struct tme_bus_connection_int, 1);
                    617:   conn_bus = &conn_int->tme_bus_connection_int;
                    618:   conn = &conn_bus->tme_bus_connection;
                    619: 
                    620:   /* loop reading our arguments: */
                    621:   usage = FALSE;
                    622:   arg_i = 1;
1.1.1.3   root      623:   conn_int->tme_bus_connection_int_vector_int = TME_BUS_INTERRUPT_VECTOR_UNDEF;
1.1.1.4   root      624:   bus_slot = NULL;
1.1       root      625:   for (;;) {
                    626: 
                    627:     /* the address of this connection: */
                    628:     if (TME_ARG_IS(args[arg_i + 0], "addr")) {
1.1.1.4   root      629:       conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE;
1.1       root      630:       conn_int->tme_bus_connection_int_address = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
                    631:       if (usage
                    632:          || (conn_int->tme_bus_connection_int_address
                    633:              > bus->tme_bus_address_mask)) {
                    634:        usage = TRUE;
                    635:        break;
                    636:       }
                    637:       arg_i += 2;
                    638:     }
                    639: 
                    640:     /* the interrupt signal for this connection: */
                    641:     else if (TME_ARG_IS(args[arg_i + 0], "ipl")
                    642:             && args[arg_i + 1] != NULL
                    643:             && (ipl = atoi(args[arg_i + 1])) > 0) {
                    644:       conn_int->tme_bus_connection_int_signal_int = TME_BUS_SIGNAL_INT(ipl);
                    645:       arg_i += 2;
                    646:     }
                    647: 
1.1.1.3   root      648:     /* the interrupt vector for this connection: */
                    649:     else if (TME_ARG_IS(args[arg_i + 0], "vector")
                    650:             && args[arg_i + 1] != NULL
                    651:             && (vector = atoi(args[arg_i + 1])) > 0) {
                    652:       conn_int->tme_bus_connection_int_vector_int = vector;
                    653:       arg_i += 2;
                    654:     }      
                    655: 
1.1.1.4   root      656:     /* the slot for this connection: */
                    657:     else if (TME_ARG_IS(args[arg_i + 0], "slot")
                    658:             && args[arg_i + 1] != NULL) {
                    659: 
                    660:       /* you can't give more than one slot for a connection: */
                    661:       if (bus_slot != NULL) {
                    662:        tme_output_append_error(_output,
                    663:                                "slot %s %s, ",
                    664:                                args[arg_i + 1],
                    665:                                _("redefined"));
                    666:        usage = TRUE;
                    667:        break;
                    668:       }
                    669: 
                    670:       /* make sure this slot has been defined: */
                    671:       for (bus_slot = bus->tme_bus_slots;
                    672:           bus_slot != NULL;
                    673:           bus_slot = bus_slot->tme_bus_slot_next) {
                    674:        if (strcmp(bus_slot->tme_bus_slot_name,
                    675:                   args[arg_i + 1]) == 0) {
                    676:          break;
                    677:        }
                    678:       }
                    679:       if (bus_slot == NULL) {
                    680:        tme_output_append_error(_output,
                    681:                                "slot %s %s, ",
                    682:                                args[arg_i + 1],
                    683:                                _("unknown"));
                    684:        usage = TRUE;
                    685:        break;
                    686:       }
                    687:       arg_i += 2;
                    688:     }
                    689: 
                    690:     /* the slot offset for this connection: */
                    691:     else if (TME_ARG_IS(args[arg_i + 0], "offset")) {
                    692:       if (bus_slot == NULL) {
                    693:        tme_output_append_error(_output,
                    694:                                "slot %s, ",
                    695:                                _("unknown"));
                    696:        usage = TRUE;
                    697:        break;
                    698:       }
                    699:       conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE;
                    700:       conn_int->tme_bus_connection_int_address
                    701:        = (bus_slot->tme_bus_slot_address
                    702:           + tme_bus_addr_parse_any(args[arg_i + 1], &usage));
                    703:       if (usage
                    704:          || (conn_int->tme_bus_connection_int_address
                    705:              > bus->tme_bus_address_mask)) {
                    706:        usage = TRUE;
                    707:        break;
                    708:       }
                    709:       arg_i += 2;
                    710:     }
                    711: 
                    712:     /* if this connection is for a slot controller: */
                    713:     else if (TME_ARG_IS(args[arg_i + 0], "controller")) {
                    714:       if (bus->tme_bus_controller != NULL) {
                    715:        tme_free(conn_int);
                    716:        return (EEXIST);
                    717:       }
                    718:       conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_CONTROLLER;
                    719:       arg_i++;
                    720:     }
                    721: 
                    722:     /* if this connection has an automatic DMA offset: */
                    723:     else if (TME_ARG_IS(args[arg_i + 0], "dma-offset")) {
                    724:       conn_int->tme_bus_connection_int_sourced = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
                    725:       if (usage
                    726:          || (conn_int->tme_bus_connection_int_sourced
                    727:              > bus->tme_bus_address_mask)) {
                    728:        usage = TRUE;
                    729:        break;
                    730:       }
                    731:       arg_i += 2;
                    732:     }
                    733: 
1.1       root      734:     /* if we've run out of arguments: */
                    735:     else if (args[arg_i + 0] == NULL) {
                    736:       break;
                    737:     }
                    738: 
                    739:     /* this is a bad argument: */
                    740:     else {
                    741:       tme_output_append_error(_output,
                    742:                              "%s %s, ",
                    743:                              args[arg_i],
                    744:                              _("unexpected"));
                    745:       usage = TRUE;
                    746:       break;
                    747:     }
                    748:   }
                    749: 
                    750:   if (usage) {
                    751:     tme_output_append_error(_output, 
1.1.1.4   root      752:                            "%s %s [ controller ] [ addr %s ] [ slot %s offset %s ] [ dma-offset %s ] [ ipl %s ] [ vector %s ]",
1.1       root      753:                            _("usage:"),
                    754:                            args[0],
                    755:                            _("BUS-ADDRESS"),
1.1.1.4   root      756:                            _("SLOT"),
                    757:                            _("OFFSET"),
                    758:                            _("OFFSET"),
1.1.1.3   root      759:                            _("INTERRUPT-LEVEL"),
                    760:                            _("INTERRUPT-VECTOR"));
1.1       root      761:     tme_free(conn_int);
                    762:     return (EINVAL);
                    763:   }
                    764: 
                    765:   /* fill in the bus connection: */
1.1.1.2   root      766:   conn_bus->tme_bus_subregions.tme_bus_subregion_address_first
                    767:     = 0;
                    768:   conn_bus->tme_bus_subregions.tme_bus_subregion_address_last
                    769:     = bus->tme_bus_address_mask;
                    770:   conn_bus->tme_bus_subregions.tme_bus_subregion_next
                    771:     = NULL;
1.1.1.3   root      772:   conn_bus->tme_bus_signals_add = _tme_bus_signals_add;
1.1       root      773:   conn_bus->tme_bus_signal = _tme_bus_signal;
                    774:   conn_bus->tme_bus_intack = _tme_bus_intack;
1.1.1.5 ! root      775:   conn_bus->tme_bus_tlb_set_add = _tme_bus_tlb_set_add;
1.1       root      776:   conn_bus->tme_bus_tlb_fill = _tme_bus_tlb_fill;
                    777: 
                    778:   /* fill in the generic connection: */
                    779:   conn->tme_connection_next = *_conns;
                    780:   conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
                    781:   conn->tme_connection_score = _tme_bus_connection_score;
                    782:   conn->tme_connection_make = _tme_bus_connection_make;
                    783:   conn->tme_connection_break = _tme_bus_connection_break;
                    784:   
                    785:   /* return the new connection side: */
                    786:   *_conns = conn;
                    787:   return (TME_OK);
                    788: }
                    789: 
                    790: /* this creates a new bus element: */
                    791: TME_ELEMENT_SUB_NEW_DECL(tme_generic,bus) {
                    792:   struct tme_bus *bus;
1.1.1.4   root      793:   tme_bus_addr_t bus_size_mask;
                    794:   tme_bus_addr_t bus_slot_size;
                    795:   tme_bus_addr_t bus_slot_addr;
                    796:   int bus_slot_addr_defined;
                    797:   struct tme_bus_slot *bus_slot;
                    798:   struct tme_bus_slot *bus_slots;
                    799:   int arg_i;
1.1       root      800:   int failed;
                    801: 
                    802:   /* our arguments must include the bus size, and the
                    803:      bus size must be a power of two: */
1.1.1.4   root      804:   failed = FALSE;
                    805:   arg_i = 1;
                    806:   bus_size_mask = 0;
                    807:   bus_slot_size = 0;
                    808:   bus_slot_addr_defined = FALSE;
                    809:   bus_slot_addr = 0;
                    810:   bus_slots = NULL;
                    811:   for (; !failed; ) {
                    812: 
                    813:     /* the bus size: */
                    814:     if (TME_ARG_IS(args[arg_i + 0], "size")) {
                    815:       /* XXX FIXME - this is a hack: */
                    816:       if (sizeof(bus_size_mask) == sizeof(tme_uint32_t) &&
                    817:          TME_ARG_IS(args[arg_i + 1], "4GB")) {
                    818:        bus_size_mask = ((tme_bus_addr_t) 0) - 1;
                    819:       }
                    820:       else {
                    821:        bus_size_mask = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
                    822:        if (!failed
                    823:            && bus_size_mask < 2) {
                    824:          failed = TRUE;
                    825:        }
                    826:        else {
                    827:          bus_size_mask -= 1;
                    828:        }
                    829:       }
                    830:       if (bus_size_mask & (bus_size_mask + 1)) {
                    831:        failed = TRUE;
                    832:       }
                    833:       arg_i += 2;
1.1.1.3   root      834:     }
1.1.1.4   root      835: 
                    836:     /* the address for the next slots: */
                    837:     else if (TME_ARG_IS(args[arg_i + 0], "slot-addr")) {
                    838:       bus_slot_addr = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
                    839:       bus_slot_addr_defined = TRUE;
                    840:       arg_i += 2;
                    841:     }
                    842: 
                    843:     /* the size for the next slots: */
                    844:     else if (TME_ARG_IS(args[arg_i + 0], "slot-size")) {
                    845:       bus_slot_size = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
                    846:       if (bus_slot_size < 1) {
                    847:        failed = TRUE;
                    848:       }
                    849:       arg_i += 2;
1.1.1.3   root      850:     }
1.1.1.4   root      851: 
                    852:     /* a slot definition: */
                    853:     else if (TME_ARG_IS(args[arg_i + 0], "slot")) {
                    854:       if (args[arg_i + 1] == NULL) {
                    855:        failed = TRUE;
                    856:        break;
                    857:       }
                    858:       if (!bus_slot_addr_defined) {
                    859:        failed = TRUE;
                    860:        break;
                    861:       }
                    862:       if (bus_slot_size == 0) {
                    863:        failed = TRUE;
                    864:        break;
                    865:       }
                    866: 
                    867:       /* make sure this slot hasn't already been defined: */
                    868:       for (bus_slot = bus_slots;
                    869:           bus_slot != NULL;
                    870:           bus_slot = bus_slot->tme_bus_slot_next) {
                    871:        if (strcmp(bus_slot->tme_bus_slot_name,
                    872:                   args[arg_i + 1]) == 0) {
                    873:          tme_output_append_error(_output,
                    874:                                  "slot %s %s",
                    875:                                  args[arg_i + 1],
                    876:                                  _("redefined"));
                    877:          failed = TRUE;
                    878:          break;
                    879:        }
                    880:       }
                    881:       if (failed) {
                    882:        break;
                    883:       }
                    884: 
                    885:       /* add this slot: */
                    886:       bus_slot = tme_new0(struct tme_bus_slot, 1);
                    887:       bus_slot->tme_bus_slot_next = bus_slots;
                    888:       bus_slots = bus_slot;
                    889:       bus_slot->tme_bus_slot_name = tme_strdup(args[arg_i + 1]);
                    890:       bus_slot->tme_bus_slot_address = bus_slot_addr;
                    891:       bus_slot->tme_bus_slot_size = bus_slot_size;
                    892: 
                    893:       /* advance for the next slot: */
                    894:       bus_slot_addr += bus_slot_size;
                    895:       arg_i += 2;
                    896:     }
                    897: 
                    898:     /* if we've run out of arguments: */
                    899:     else if (args[arg_i + 0] == NULL) {
                    900:       break;
                    901:     }
                    902: 
                    903:     /* an unknown argument: */
                    904:     else {
                    905:       tme_output_append_error(_output,
                    906:                              "%s %s, ",
                    907:                              args[arg_i],
                    908:                              _("unexpected"));
1.1       root      909:       failed = TRUE;
                    910:     }
                    911:   }
                    912:   if (failed) {
                    913:     tme_output_append_error(_output,
1.1.1.4   root      914:                            "%s %s size %s [ slot-addr %s slot-size %s slot %s0 .. slot %sN ]",
1.1       root      915:                            _("usage:"),
                    916:                            args[0],
1.1.1.4   root      917:                            _("SIZE"),
                    918:                            _("ADDRESS"),
                    919:                            _("SIZE"),
                    920:                            _("SLOT-NAME"),
                    921:                            _("SLOT-NAME"));
                    922:     for (; (bus_slot = bus_slots) != NULL; ) {
                    923:       bus_slots = bus_slots->tme_bus_slot_next;
                    924:       tme_free(bus_slot->tme_bus_slot_name);
                    925:       tme_free(bus_slot);
                    926:     }
1.1       root      927:     return (EINVAL);
                    928:   }
                    929: 
                    930:   /* allocate and initialize the new bus: */
                    931:   bus = tme_new0(struct tme_bus, 1);
                    932:   tme_rwlock_init(&bus->tme_bus_rwlock);
1.1.1.4   root      933:   bus->tme_bus_address_mask = bus_size_mask;
1.1       root      934:   bus->tme_bus_addressables_count = 0;
                    935:   bus->tme_bus_addressables_size = 1;
1.1.1.2   root      936:   bus->tme_bus_addressables = tme_new(struct tme_bus_addressable,
1.1       root      937:                                      bus->tme_bus_addressables_size);
1.1.1.3   root      938:   bus->tme_bus_signals_count = TME_ARRAY_ELS(_tme_bus_signals_default);
                    939:   bus->tme_bus_signals = tme_dup(struct tme_bus_signals,
                    940:                                 _tme_bus_signals_default,
                    941:                                 TME_ARRAY_ELS(_tme_bus_signals_default));
                    942:   bus->tme_bus_signal_asserts = tme_new0(unsigned int,
                    943:                                         _tme_bus_signals_default[0].tme_bus_signals_count);
1.1.1.4   root      944:   bus->tme_bus_slots = bus_slots;
1.1       root      945: 
                    946:   /* fill the element: */
                    947:   element->tme_element_private = bus;
                    948:   element->tme_element_connections_new = _tme_bus_connections_new;
                    949: 
                    950:   return (TME_OK);
                    951: }

unix.superglobalmegacorp.com

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