|
|
1.1.1.2 ! root 1: /* $Id: bus-el.c,v 1.9 2003/07/29 18:19:12 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.2 ! root 37: _TME_RCSID("$Id: bus-el.c,v 1.9 2003/07/29 18:19:12 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus.h> 41: #include <stdlib.h> 42: #include <string.h> 43: 44: /* macros: */ 45: 46: /* structures: */ 47: 48: /* this handles a bus connection signal edge: */ 49: static int 50: _tme_bus_signal(struct tme_bus_connection *conn_bus_edger, unsigned int signal) 51: { 52: struct tme_bus *bus; 53: struct tme_bus_connection_int *conn_bus_int_edger; 54: struct tme_bus_connection_int *conn_bus_int; 55: unsigned int level_edge; 56: struct tme_bus_connection *conn_bus; 57: struct tme_bus_connection *conn_bus_other; 58: int signal_asserted, need_propagate; 59: unsigned int signal_index; 60: tme_uint8_t signal_mask; 61: int rc; 62: int deadlocked; 63: 64: /* recover our bus: */ 65: bus = conn_bus_edger->tme_bus_connection.tme_connection_element->tme_element_private; 66: conn_bus_int_edger = (struct tme_bus_connection_int *) conn_bus_edger; 67: 68: /* take out the level and edge: */ 69: level_edge = signal & (TME_BUS_SIGNAL_LEVEL_MASK 70: | TME_BUS_SIGNAL_EDGE); 71: signal &= ~(TME_BUS_SIGNAL_LEVEL_MASK 72: | TME_BUS_SIGNAL_EDGE); 73: 74: /* lock the bus for writing: */ 75: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); 76: if (TME_THREADS_ERRNO(rc) != TME_OK) { 77: return (TME_THREADS_ERRNO(rc)); 78: } 79: 80: /* if this device doesn't know its interrupt signal, fix it: */ 81: if (signal == TME_BUS_SIGNAL_INT_UNSPEC) { 82: signal = conn_bus_int_edger->tme_bus_connection_int_signal_int; 83: if (signal == TME_BUS_SIGNAL_INT_UNSPEC) { 84: /* this bus connection is misconfigured: */ 85: if (!conn_bus_int_edger->tme_bus_connection_int_logged_int) { 86: conn_bus_int_edger->tme_bus_connection_int_logged_int = TRUE; 87: /* XXX diagnostic */ 88: abort(); 89: } 90: tme_rwlock_unlock(&bus->tme_bus_rwlock); 91: return (TME_OK); 92: } 93: } 94: 95: /* assume we don't need to propagate this signal across the bus: */ 96: need_propagate = FALSE; 97: 98: /* if this is a random bus-specific signal, just propagate it: */ 99: if (TME_BUS_SIGNAL_IS_X(signal)) { 100: need_propagate = TRUE; 101: } 102: 103: /* otherwise, this is a generic bus signal: */ 104: else { 105: 106: /* decide whether the device is asserting or negating this signal: */ 107: /* XXX we currently assume that for all bus signals handled by this 108: function, low implies assertion, and signals are always ORed 109: together. this could be configurable, possibly even per-signal: */ 110: signal_asserted = TRUE; 111: switch (level_edge & TME_BUS_SIGNAL_LEVEL_MASK) { 112: case TME_BUS_SIGNAL_LEVEL_LOW: 113: case TME_BUS_SIGNAL_LEVEL_ASSERTED: 114: break; 115: case TME_BUS_SIGNAL_LEVEL_HIGH: 116: case TME_BUS_SIGNAL_LEVEL_NEGATED: 117: signal_asserted = FALSE; 118: break; 119: } 120: level_edge = ((level_edge & TME_BUS_SIGNAL_EDGE) 121: | (signal_asserted 122: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 123: : TME_BUS_SIGNAL_LEVEL_NEGATED)); 124: 125: /* get the index and mask of this signal in signal byte arrays: */ 126: signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal); 127: signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal); 128: 129: /* if this signal is being asserted: */ 130: if (signal_asserted) { 131: 132: /* if this device wasn't already asserting this signal: */ 133: if (!(conn_bus_int_edger->tme_bus_connection_int_signals[signal_index] 134: & signal_mask)) { 135: 136: /* it is now asserting this signal: */ 137: conn_bus_int_edger->tme_bus_connection_int_signals[signal_index] 138: |= signal_mask; 139: bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)]++; 140: 141: /* if this is the only device asserting this signal, 142: propagate the change across the bus: */ 143: if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] == 1) { 144: need_propagate = TRUE; 145: } 146: } 147: 148: /* otherwise, this device was already asserting this signal: */ 149: else { 150: assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] > 0); 151: } 152: } 153: 154: /* otherwise, this signal is being negated: */ 155: else { 156: 157: /* if this device was asserting this signal: */ 158: if (conn_bus_int_edger->tme_bus_connection_int_signals[signal_index] 159: & signal_mask) { 160: 161: /* it is no longer asserting this signal: */ 162: conn_bus_int_edger->tme_bus_connection_int_signals[signal_index] 163: &= ~signal_mask; 164: assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] > 0); 165: bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)]--; 166: } 167: 168: /* we always propagate across the bus a signal that some device 169: has negated, because often code will lazily only send 170: negating edges, or other devices might still be asserting it, 171: we assume these signals are always ORed together, and it 172: kicks (even though this signal isn't edging) emulated 173: circuitry that is meant to do things like interrupt 174: arbitration, etc.: */ 175: if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] > 0) { 176: level_edge = TME_BUS_SIGNAL_LEVEL_ASSERTED; 177: } 178: need_propagate = TRUE; 179: } 180: } 181: 182: /* if we're propagating this signal across the bus: */ 183: rc = TME_OK; 184: if (need_propagate) { 185: 186: /* put the level and edge back in: */ 187: signal |= level_edge; 188: 189: /* assume that we won't deadlock: */ 190: deadlocked = FALSE; 191: 192: /* propagate the signal to each connection to the bus: */ 193: for (conn_bus_int = bus->tme_bus_connections; 194: conn_bus_int != NULL; 195: conn_bus_int = 196: (struct tme_bus_connection_int *) 197: conn_bus_int->tme_bus_connection_int 198: .tme_bus_connection 199: .tme_connection_next) { 200: conn_bus = &conn_bus_int->tme_bus_connection_int; 201: conn_bus_other = 202: (struct tme_bus_connection *) 203: conn_bus->tme_bus_connection.tme_connection_other; 204: 205: /* skip this device if it edged the line to begin with: */ 206: if (conn_bus == conn_bus_edger) { 207: continue; 208: } 209: 210: /* skip this device if it doesn't care about bus signals: */ 211: if (conn_bus_other->tme_bus_signal == NULL) { 212: continue; 213: } 214: 215: /* give the edge to this connection: */ 216: rc = (*conn_bus_other->tme_bus_signal)(conn_bus_other, signal); 217: 218: /* if we deadlocked, remember to tell the caller: */ 219: if (rc == TME_EDEADLK) { 220: deadlocked = TRUE; 221: } 222: } 223: rc = (deadlocked ? TME_EDEADLK : TME_OK); 224: } 225: 226: /* unlock the bus: */ 227: tme_rwlock_unlock(&bus->tme_bus_rwlock); 228: 229: /* done: */ 230: return (rc); 231: } 232: 233: /* this handles a bus interrupt acknowledge: */ 234: static int 235: _tme_bus_intack(struct tme_bus_connection *conn_bus_acker, unsigned int signal, int *vector) 236: { 237: struct tme_bus *bus; 238: struct tme_bus_connection_int *conn_bus_int; 239: struct tme_bus_connection *conn_bus; 240: struct tme_bus_connection *conn_bus_other; 241: unsigned int signal_index; 242: tme_uint8_t signal_mask; 243: int rc; 244: 245: /* recover our bus: */ 246: bus = conn_bus_acker->tme_bus_connection.tme_connection_element->tme_element_private; 247: 248: /* get rid of any level and edge: */ 249: signal &= ~(TME_BUS_SIGNAL_LEVEL_MASK 250: | TME_BUS_SIGNAL_EDGE); 251: 252: /* this must be an interrupt signal: */ 253: assert(TME_BUS_SIGNAL_IS_INT(signal)); 254: 255: /* lock the bus for writing: */ 256: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); 257: if (TME_THREADS_ERRNO(rc) != TME_OK) { 258: return (TME_THREADS_ERRNO(rc)); 259: } 260: 261: /* get the index and mask of this signal in signal byte arrays: */ 262: signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal); 263: signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal); 264: 265: /* find the first connection to the bus that is asserting this 266: interrupt signal. if no connection is asserting the signal, 267: return ENOENT: */ 268: rc = ENOENT; 269: for (conn_bus_int = bus->tme_bus_connections; 270: conn_bus_int != NULL; 271: conn_bus_int = 272: (struct tme_bus_connection_int *) 273: conn_bus_int->tme_bus_connection_int 274: .tme_bus_connection 275: .tme_connection_next) { 276: conn_bus = &conn_bus_int->tme_bus_connection_int; 277: conn_bus_other = 278: (struct tme_bus_connection *) 279: conn_bus->tme_bus_connection.tme_connection_other; 280: 281: /* if this device is asserting this interrupt signal: */ 282: if (conn_bus_int->tme_bus_connection_int_signals[signal_index] 283: & signal_mask) { 284: 285: /* if this device doesn't acknowledge interrupts, 286: return an undefined vector: */ 287: if (conn_bus_other->tme_bus_intack == NULL) { 288: *vector = TME_BUS_INTERRUPT_VECTOR_UNDEF; 289: rc = TME_OK; 290: } 291: 292: /* otherwise, run the interrupt acknowledge with this connection: */ 293: else { 294: rc = (*conn_bus_other->tme_bus_intack)(conn_bus_other, signal, vector); 295: } 296: 297: /* stop: */ 298: break; 299: } 300: } 301: 302: /* unlock the bus: */ 303: tme_rwlock_unlock(&bus->tme_bus_rwlock); 304: 305: /* done: */ 306: return (rc); 307: } 308: 309: static int 310: _tme_bus_fault(void *junk0, struct tme_bus_cycle *junk1) 311: { 312: return (ENOENT); 313: } 314: 315: /* this fills a TLB entry: */ 316: static int 317: _tme_bus_tlb_fill(struct tme_bus_connection *conn_bus_asker, 318: struct tme_bus_tlb *tlb, 319: tme_bus_addr_t address, 320: unsigned int cycles) 321: { 322: struct tme_bus *bus; 323: struct tme_bus_connection_int *conn_int; 324: int rc; 325: 326: /* recover our bus and our connection to the asker: */ 327: bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; 328: conn_int = (struct tme_bus_connection_int *) conn_bus_asker; 329: 330: /* put our fault handler in the TLB entry: */ 331: tlb->tme_bus_tlb_cycle_private = NULL; 332: tlb->tme_bus_tlb_cycle = _tme_bus_fault; 333: 334: /* lock the bus for reading: */ 335: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); 336: if (TME_THREADS_ERRNO(rc) != TME_OK) { 337: return (TME_THREADS_ERRNO(rc)); 338: } 339: 340: /* call the generic bus support function: */ 341: rc = tme_bus_tlb_fill(bus, 342: conn_int, 343: tlb, address, cycles); 344: 345: /* unlock the bus: */ 346: tme_rwlock_unlock(&bus->tme_bus_rwlock); 347: 348: /* done: */ 349: return (rc); 350: } 351: 352: /* this allocates a new TLB set: */ 353: static int 354: _tme_bus_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker, 355: unsigned int count, unsigned int sizeof_one, 356: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs) 357: { 358: struct tme_bus *bus; 359: struct tme_bus_connection_int *conn_int; 360: int rc; 361: 362: /* recover our bus and our connection to the asker: */ 363: bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private; 364: conn_int = (struct tme_bus_connection_int *) conn_bus_asker; 365: 366: /* lock the bus for reading: */ 367: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); 368: if (TME_THREADS_ERRNO(rc) != TME_OK) { 369: return (TME_THREADS_ERRNO(rc)); 370: } 371: 372: /* call the generic bus support function: */ 373: rc = tme_bus_tlb_set_allocate(bus, 374: conn_int, 375: count, sizeof_one, 376: _tlbs); 377: 378: /* unlock the bus: */ 379: tme_rwlock_unlock(&bus->tme_bus_rwlock); 380: 381: /* done: */ 382: return (rc); 383: } 384: 385: /* this scores a new connection: */ 386: static int 387: _tme_bus_connection_score(struct tme_connection *conn, unsigned int *_score) 388: { 389: struct tme_bus *bus; 390: struct tme_bus_connection_int *conn_int; 391: int rc, ok; 392: 393: /* both sides must be generic bus connections: */ 394: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 395: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 396: 397: /* recover our bus and our internal connection side: */ 398: bus = conn->tme_connection_element->tme_element_private; 399: conn_int = (struct tme_bus_connection_int *) conn; 400: 401: /* lock the bus for reading: */ 402: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); 403: if (TME_THREADS_ERRNO(rc) != TME_OK) { 404: return (TME_THREADS_ERRNO(rc)); 405: } 406: 407: /* call the generic bus support function: */ 408: ok = tme_bus_connection_ok(bus, 409: conn_int); 410: 411: /* unlock the bus: */ 412: tme_rwlock_unlock(&bus->tme_bus_rwlock); 413: 414: /* return the score: */ 415: *_score = (ok ? 1 : 0); 416: return (TME_OK); 417: } 418: 419: /* this makes a new connection: */ 420: static int 421: _tme_bus_connection_make(struct tme_connection *conn, unsigned int state) 422: { 423: struct tme_bus *bus; 424: struct tme_bus_connection_int *conn_int; 425: int rc; 426: 427: /* both sides must be generic bus connections: */ 428: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 429: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC); 430: 431: /* recover our bus and our internal connection side: */ 432: bus = conn->tme_connection_element->tme_element_private; 433: conn_int = (struct tme_bus_connection_int *) conn; 434: 435: /* lock the bus for writing: */ 436: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); 437: if (TME_THREADS_ERRNO(rc) != TME_OK) { 438: return (TME_THREADS_ERRNO(rc)); 439: } 440: 441: /* call the generic bus support function: */ 442: rc = tme_bus_connection_make(bus, 443: conn_int, 444: state); 445: 446: /* unlock the bus: */ 447: tme_rwlock_unlock(&bus->tme_bus_rwlock); 448: 449: return (rc); 450: } 451: 452: /* this breaks a connection: */ 453: static int 454: _tme_bus_connection_break(struct tme_connection *conn, unsigned int state) 455: { 456: abort(); 457: } 458: 459: /* this returns the new connections possible: */ 460: static int 461: _tme_bus_connections_new(struct tme_element *element, 462: const char * const *args, 463: struct tme_connection **_conns, 464: char **_output) 465: { 466: const struct tme_bus *bus; 467: struct tme_bus_connection_int *conn_int; 468: struct tme_bus_connection *conn_bus; 469: struct tme_connection *conn; 470: int ipl; 471: int arg_i; 472: int usage; 473: 474: /* recover our bus. we only read the address mask, so we don't lock 475: the rwlock: */ 476: bus = element->tme_element_private; 477: 478: /* allocate the new connection side: */ 479: conn_int = tme_new0(struct tme_bus_connection_int, 1); 480: conn_bus = &conn_int->tme_bus_connection_int; 481: conn = &conn_bus->tme_bus_connection; 482: 483: /* loop reading our arguments: */ 484: usage = FALSE; 485: arg_i = 1; 486: for (;;) { 487: 488: /* the address of this connection: */ 489: if (TME_ARG_IS(args[arg_i + 0], "addr")) { 490: conn_int->tme_bus_connection_int_addressable = TRUE; 491: conn_int->tme_bus_connection_int_address = tme_bus_addr_parse_any(args[arg_i + 1], &usage); 492: if (usage 493: || (conn_int->tme_bus_connection_int_address 494: > bus->tme_bus_address_mask)) { 495: usage = TRUE; 496: break; 497: } 498: arg_i += 2; 499: } 500: 501: /* the interrupt signal for this connection: */ 502: else if (TME_ARG_IS(args[arg_i + 0], "ipl") 503: && args[arg_i + 1] != NULL 504: && (ipl = atoi(args[arg_i + 1])) > 0) { 505: conn_int->tme_bus_connection_int_signal_int = TME_BUS_SIGNAL_INT(ipl); 506: arg_i += 2; 507: } 508: 509: /* if we've run out of arguments: */ 510: else if (args[arg_i + 0] == NULL) { 511: break; 512: } 513: 514: /* this is a bad argument: */ 515: else { 516: tme_output_append_error(_output, 517: "%s %s, ", 518: args[arg_i], 519: _("unexpected")); 520: usage = TRUE; 521: break; 522: } 523: } 524: 525: if (usage) { 526: tme_output_append_error(_output, 527: "%s %s [ addr %s ] [ ipl %s ]", 528: _("usage:"), 529: args[0], 530: _("BUS-ADDRESS"), 531: _("INTERRUPT-LEVEL")); 532: tme_free(conn_int); 533: return (EINVAL); 534: } 535: 536: /* fill in the bus connection: */ 1.1.1.2 ! root 537: conn_bus->tme_bus_subregions.tme_bus_subregion_address_first ! 538: = 0; ! 539: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last ! 540: = bus->tme_bus_address_mask; ! 541: conn_bus->tme_bus_subregions.tme_bus_subregion_next ! 542: = NULL; 1.1 root 543: conn_bus->tme_bus_signal = _tme_bus_signal; 544: conn_bus->tme_bus_intack = _tme_bus_intack; 545: conn_bus->tme_bus_tlb_set_allocate = _tme_bus_tlb_set_allocate; 546: conn_bus->tme_bus_tlb_fill = _tme_bus_tlb_fill; 547: 548: /* fill in the generic connection: */ 549: conn->tme_connection_next = *_conns; 550: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC; 551: conn->tme_connection_score = _tme_bus_connection_score; 552: conn->tme_connection_make = _tme_bus_connection_make; 553: conn->tme_connection_break = _tme_bus_connection_break; 554: 555: /* return the new connection side: */ 556: *_conns = conn; 557: return (TME_OK); 558: } 559: 560: /* this creates a new bus element: */ 561: TME_ELEMENT_SUB_NEW_DECL(tme_generic,bus) { 562: struct tme_bus *bus; 563: tme_bus_addr_t bus_size; 564: int failed; 565: 566: /* our arguments must include the bus size, and the 567: bus size must be a power of two: */ 568: failed = TRUE; 569: bus_size = 0; 570: if (TME_ARG_IS(args[1], "size")) { 571: bus_size = tme_bus_addr_parse_any(args[2], &failed); 572: if (bus_size & (bus_size - 1)) { 573: failed = TRUE; 574: } 575: } 576: if (failed) { 577: tme_output_append_error(_output, 578: "%s %s size %s", 579: _("usage:"), 580: args[0], 581: _("SIZE")); 582: return (EINVAL); 583: } 584: 585: /* allocate and initialize the new bus: */ 586: bus = tme_new0(struct tme_bus, 1); 587: tme_rwlock_init(&bus->tme_bus_rwlock); 588: bus->tme_bus_address_mask = bus_size - 1; 589: bus->tme_bus_addressables_count = 0; 590: bus->tme_bus_addressables_size = 1; 1.1.1.2 ! root 591: bus->tme_bus_addressables = tme_new(struct tme_bus_addressable, 1.1 root 592: bus->tme_bus_addressables_size); 593: 594: /* fill the element: */ 595: element->tme_element_private = bus; 596: element->tme_element_connections_new = _tme_bus_connections_new; 597: 598: return (TME_OK); 599: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.