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