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

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

unix.superglobalmegacorp.com

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