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

1.1.1.3 ! root        1: /* $Id: bus-el.c,v 1.13 2005/02/17 12:37:24 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.3 ! root       37: _TME_RCSID("$Id: bus-el.c,v 1.13 2005/02/17 12:37:24 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.3 ! root      408:       /* if this device doesn't acknowledge interrupts, return any
        !           409:         user-specified vector or TME_BUS_INTERRUPT_VECTOR_UNDEF: */
1.1       root      410:       if (conn_bus_other->tme_bus_intack == NULL) {
1.1.1.3 ! root      411:        *vector = conn_bus_int->tme_bus_connection_int_vector_int;
1.1       root      412:        rc = TME_OK;
                    413:       }
                    414: 
                    415:       /* otherwise, run the interrupt acknowledge with this connection: */
                    416:       else {
                    417:        rc = (*conn_bus_other->tme_bus_intack)(conn_bus_other, signal, vector);
                    418:       }
                    419: 
                    420:       /* stop: */
                    421:       break;
                    422:     }
                    423:   }
                    424: 
                    425:   /* unlock the bus: */
                    426:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    427: 
                    428:   /* done: */
                    429:   return (rc);
                    430: }
                    431: 
                    432: static int
                    433: _tme_bus_fault(void *junk0, struct tme_bus_cycle *junk1)
                    434: {
                    435:   return (ENOENT);
                    436: }
                    437: 
                    438: /* this fills a TLB entry: */
                    439: static int
                    440: _tme_bus_tlb_fill(struct tme_bus_connection *conn_bus_asker, 
                    441:                  struct tme_bus_tlb *tlb,
                    442:                  tme_bus_addr_t address, 
                    443:                  unsigned int cycles)
                    444: {
                    445:   struct tme_bus *bus;
                    446:   struct tme_bus_connection_int *conn_int;
                    447:   int rc;
                    448: 
                    449:   /* recover our bus and our connection to the asker: */
                    450:   bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
                    451:   conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
                    452: 
                    453:   /* put our fault handler in the TLB entry: */
                    454:   tlb->tme_bus_tlb_cycle_private = NULL;
                    455:   tlb->tme_bus_tlb_cycle = _tme_bus_fault;
                    456: 
                    457:   /* lock the bus for reading: */
                    458:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    459:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    460:     return (TME_THREADS_ERRNO(rc));
                    461:   }
                    462: 
                    463:   /* call the generic bus support function: */
                    464:   rc = tme_bus_tlb_fill(bus,
                    465:                        conn_int,
                    466:                        tlb, address, cycles);
                    467: 
                    468:   /* unlock the bus: */
                    469:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    470: 
                    471:   /* done: */
                    472:   return (rc);
                    473: }
                    474: 
                    475: /* this allocates a new TLB set: */
                    476: static int
                    477: _tme_bus_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
                    478:                          unsigned int count, unsigned int sizeof_one, 
1.1.1.3 ! root      479:                          TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb *) _tlbs)
1.1       root      480: {
                    481:   struct tme_bus *bus;
                    482:   struct tme_bus_connection_int *conn_int;
                    483:   int rc;
                    484: 
                    485:   /* recover our bus and our connection to the asker: */
                    486:   bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
                    487:   conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
                    488: 
                    489:   /* lock the bus for reading: */
                    490:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    491:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    492:     return (TME_THREADS_ERRNO(rc));
                    493:   }
                    494: 
                    495:   /* call the generic bus support function: */
                    496:   rc = tme_bus_tlb_set_allocate(bus,
                    497:                                conn_int,
                    498:                                count, sizeof_one, 
                    499:                                _tlbs);
                    500: 
                    501:   /* unlock the bus: */
                    502:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    503: 
                    504:   /* done: */
                    505:   return (rc);
                    506: }
                    507: 
                    508: /* this scores a new connection: */
                    509: static int
                    510: _tme_bus_connection_score(struct tme_connection *conn, unsigned int *_score)
                    511: {
                    512:   struct tme_bus *bus;
                    513:   struct tme_bus_connection_int *conn_int;
                    514:   int rc, ok;
                    515: 
                    516:   /* both sides must be generic bus connections: */
                    517:   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    518:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    519: 
                    520:   /* recover our bus and our internal connection side: */
                    521:   bus = conn->tme_connection_element->tme_element_private;
                    522:   conn_int = (struct tme_bus_connection_int *) conn;
                    523: 
                    524:   /* lock the bus for reading: */
                    525:   rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    526:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    527:     return (TME_THREADS_ERRNO(rc));
                    528:   }
                    529:   
                    530:   /* call the generic bus support function: */
                    531:   ok = tme_bus_connection_ok(bus,
                    532:                             conn_int);
                    533: 
                    534:   /* unlock the bus: */
                    535:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    536: 
                    537:   /* return the score: */
                    538:   *_score = (ok ? 1 : 0);
                    539:   return (TME_OK);
                    540: }
                    541: 
                    542: /* this makes a new connection: */
                    543: static int
                    544: _tme_bus_connection_make(struct tme_connection *conn, unsigned int state)
                    545: {
                    546:   struct tme_bus *bus;
                    547:   struct tme_bus_connection_int *conn_int;
1.1.1.3 ! root      548:   const struct tme_bus_signals *bus_signals;
1.1       root      549:   int rc;
                    550: 
                    551:   /* both sides must be generic bus connections: */
                    552:   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    553:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
                    554: 
                    555:   /* recover our bus and our internal connection side: */
                    556:   bus = conn->tme_connection_element->tme_element_private;
                    557:   conn_int = (struct tme_bus_connection_int *) conn;
                    558:   
                    559:   /* lock the bus for writing: */
                    560:   rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
                    561:   if (TME_THREADS_ERRNO(rc) != TME_OK) {
                    562:     return (TME_THREADS_ERRNO(rc));
                    563:   }
                    564: 
                    565:   /* call the generic bus support function: */
                    566:   rc = tme_bus_connection_make(bus,
                    567:                               conn_int,
                    568:                               state);
                    569: 
1.1.1.3 ! root      570:   /* XXX this is a perfect example of the poor division between
        !           571:      bus-el.c and bus.c.  should the signal handling code be in bus.c?  */
        !           572:   if (rc == TME_OK) {
        !           573:     bus_signals = &bus->tme_bus_signals[bus->tme_bus_signals_count - 1];
        !           574:     conn_int->tme_bus_connection_int_signals
        !           575:       = tme_new0(tme_uint8_t,
        !           576:                 TME_BUS_SIGNAL_BIT_BYTES(TME_BUS_SIGNAL_INDEX(bus_signals->tme_bus_signals_first)
        !           577:                                          + bus_signals->tme_bus_signals_count));
        !           578:   }
        !           579: 
1.1       root      580:   /* unlock the bus: */
                    581:   tme_rwlock_unlock(&bus->tme_bus_rwlock);
                    582: 
                    583:   return (rc);
                    584: }
                    585: 
                    586: /* this breaks a connection: */
                    587: static int 
                    588: _tme_bus_connection_break(struct tme_connection *conn, unsigned int state)
                    589: {
                    590:   abort();
                    591: }
                    592: 
                    593: /* this returns the new connections possible: */
                    594: static int
                    595: _tme_bus_connections_new(struct tme_element *element,
                    596:                         const char * const *args,
                    597:                         struct tme_connection **_conns,
                    598:                         char **_output)
                    599: {
                    600:   const struct tme_bus *bus;
                    601:   struct tme_bus_connection_int *conn_int;
                    602:   struct tme_bus_connection *conn_bus;
                    603:   struct tme_connection *conn;
                    604:   int ipl;
1.1.1.3 ! root      605:   int vector;
1.1       root      606:   int arg_i;
                    607:   int usage;
                    608: 
                    609:   /* recover our bus.  we only read the address mask, so we don't lock
                    610:      the rwlock: */
                    611:   bus = element->tme_element_private;
                    612: 
                    613:   /* allocate the new connection side: */
                    614:   conn_int = tme_new0(struct tme_bus_connection_int, 1);
                    615:   conn_bus = &conn_int->tme_bus_connection_int;
                    616:   conn = &conn_bus->tme_bus_connection;
                    617: 
                    618:   /* loop reading our arguments: */
                    619:   usage = FALSE;
                    620:   arg_i = 1;
1.1.1.3 ! root      621:   conn_int->tme_bus_connection_int_vector_int = TME_BUS_INTERRUPT_VECTOR_UNDEF;
1.1       root      622:   for (;;) {
                    623: 
                    624:     /* the address of this connection: */
                    625:     if (TME_ARG_IS(args[arg_i + 0], "addr")) {
                    626:       conn_int->tme_bus_connection_int_addressable = TRUE;
                    627:       conn_int->tme_bus_connection_int_address = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
                    628:       if (usage
                    629:          || (conn_int->tme_bus_connection_int_address
                    630:              > bus->tme_bus_address_mask)) {
                    631:        usage = TRUE;
                    632:        break;
                    633:       }
                    634:       arg_i += 2;
                    635:     }
                    636: 
                    637:     /* the interrupt signal for this connection: */
                    638:     else if (TME_ARG_IS(args[arg_i + 0], "ipl")
                    639:             && args[arg_i + 1] != NULL
                    640:             && (ipl = atoi(args[arg_i + 1])) > 0) {
                    641:       conn_int->tme_bus_connection_int_signal_int = TME_BUS_SIGNAL_INT(ipl);
                    642:       arg_i += 2;
                    643:     }
                    644: 
1.1.1.3 ! root      645:     /* the interrupt vector for this connection: */
        !           646:     else if (TME_ARG_IS(args[arg_i + 0], "vector")
        !           647:             && args[arg_i + 1] != NULL
        !           648:             && (vector = atoi(args[arg_i + 1])) > 0) {
        !           649:       conn_int->tme_bus_connection_int_vector_int = vector;
        !           650:       arg_i += 2;
        !           651:     }      
        !           652: 
1.1       root      653:     /* if we've run out of arguments: */
                    654:     else if (args[arg_i + 0] == NULL) {
                    655:       break;
                    656:     }
                    657: 
                    658:     /* this is a bad argument: */
                    659:     else {
                    660:       tme_output_append_error(_output,
                    661:                              "%s %s, ",
                    662:                              args[arg_i],
                    663:                              _("unexpected"));
                    664:       usage = TRUE;
                    665:       break;
                    666:     }
                    667:   }
                    668: 
                    669:   if (usage) {
                    670:     tme_output_append_error(_output, 
1.1.1.3 ! root      671:                            "%s %s [ addr %s ] [ ipl %s ] [ vector %s ]",
1.1       root      672:                            _("usage:"),
                    673:                            args[0],
                    674:                            _("BUS-ADDRESS"),
1.1.1.3 ! root      675:                            _("INTERRUPT-LEVEL"),
        !           676:                            _("INTERRUPT-VECTOR"));
1.1       root      677:     tme_free(conn_int);
                    678:     return (EINVAL);
                    679:   }
                    680: 
                    681:   /* fill in the bus connection: */
1.1.1.2   root      682:   conn_bus->tme_bus_subregions.tme_bus_subregion_address_first
                    683:     = 0;
                    684:   conn_bus->tme_bus_subregions.tme_bus_subregion_address_last
                    685:     = bus->tme_bus_address_mask;
                    686:   conn_bus->tme_bus_subregions.tme_bus_subregion_next
                    687:     = NULL;
1.1.1.3 ! root      688:   conn_bus->tme_bus_signals_add = _tme_bus_signals_add;
1.1       root      689:   conn_bus->tme_bus_signal = _tme_bus_signal;
                    690:   conn_bus->tme_bus_intack = _tme_bus_intack;
                    691:   conn_bus->tme_bus_tlb_set_allocate = _tme_bus_tlb_set_allocate;
                    692:   conn_bus->tme_bus_tlb_fill = _tme_bus_tlb_fill;
                    693: 
                    694:   /* fill in the generic connection: */
                    695:   conn->tme_connection_next = *_conns;
                    696:   conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
                    697:   conn->tme_connection_score = _tme_bus_connection_score;
                    698:   conn->tme_connection_make = _tme_bus_connection_make;
                    699:   conn->tme_connection_break = _tme_bus_connection_break;
                    700:   
                    701:   /* return the new connection side: */
                    702:   *_conns = conn;
                    703:   return (TME_OK);
                    704: }
                    705: 
                    706: /* this creates a new bus element: */
                    707: TME_ELEMENT_SUB_NEW_DECL(tme_generic,bus) {
                    708:   struct tme_bus *bus;
                    709:   tme_bus_addr_t bus_size;
                    710:   int failed;
                    711: 
                    712:   /* our arguments must include the bus size, and the
                    713:      bus size must be a power of two: */
                    714:   failed = TRUE;
                    715:   bus_size = 0;
                    716:   if (TME_ARG_IS(args[1], "size")) {
1.1.1.3 ! root      717:     /* XXX FIXME - this is a hack: */
        !           718:     if (sizeof(bus_size) == sizeof(tme_uint32_t) &&
        !           719:        TME_ARG_IS(args[1], "4GB")) {
        !           720:       bus_size = 0;
        !           721:     }
        !           722:     else {
        !           723:       bus_size = tme_bus_addr_parse_any(args[2], &failed);
        !           724:     }
1.1       root      725:     if (bus_size & (bus_size - 1)) {
                    726:       failed = TRUE;
                    727:     }
                    728:   }
                    729:   if (failed) {
                    730:     tme_output_append_error(_output,
                    731:                            "%s %s size %s",
                    732:                            _("usage:"),
                    733:                            args[0],
                    734:                            _("SIZE"));
                    735:     return (EINVAL);
                    736:   }
                    737: 
                    738:   /* allocate and initialize the new bus: */
                    739:   bus = tme_new0(struct tme_bus, 1);
                    740:   tme_rwlock_init(&bus->tme_bus_rwlock);
                    741:   bus->tme_bus_address_mask = bus_size - 1;
                    742:   bus->tme_bus_addressables_count = 0;
                    743:   bus->tme_bus_addressables_size = 1;
1.1.1.2   root      744:   bus->tme_bus_addressables = tme_new(struct tme_bus_addressable,
1.1       root      745:                                      bus->tme_bus_addressables_size);
1.1.1.3 ! root      746:   bus->tme_bus_signals_count = TME_ARRAY_ELS(_tme_bus_signals_default);
        !           747:   bus->tme_bus_signals = tme_dup(struct tme_bus_signals,
        !           748:                                 _tme_bus_signals_default,
        !           749:                                 TME_ARRAY_ELS(_tme_bus_signals_default));
        !           750:   bus->tme_bus_signal_asserts = tme_new0(unsigned int,
        !           751:                                         _tme_bus_signals_default[0].tme_bus_signals_count);
1.1       root      752: 
                    753:   /* fill the element: */
                    754:   element->tme_element_private = bus;
                    755:   element->tme_element_connections_new = _tme_bus_connections_new;
                    756: 
                    757:   return (TME_OK);
                    758: }

unix.superglobalmegacorp.com

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