|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.