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