|
|
1.1.1.2 ! root 1: /* $Id: bus.c,v 1.5 2003/10/16 02:48:18 fredette Exp $ */ 1.1 root 2: 3: /* generic/gen-bus.c - generic bus support: */ 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.c,v 1.5 2003/10/16 02:48:18 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus.h> 41: #include <stdlib.h> 42: #include <string.h> 43: 44: /* this does a binary search of the addressable connections: */ 45: int 46: tme_bus_address_search(struct tme_bus *bus, tme_bus_addr_t address) 47: { 48: int left, right, pivot; 49: struct tme_bus_connection_int *conn_int; 1.1.1.2 ! root 50: const struct tme_bus_subregion *subregion; 1.1 root 51: 52: /* initialize for the search: */ 53: left = 0; 54: right = bus->tme_bus_addressables_count - 1; 55: 56: /* do the search: */ 57: pivot = 0; 58: for (; left <= right; ) { 59: 60: /* get the pivot: */ 61: pivot = (left + right) / 2; 1.1.1.2 ! root 62: conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection; ! 63: subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion; 1.1 root 64: 65: /* if we have to move left: */ 1.1.1.2 ! root 66: if (address ! 67: < (conn_int->tme_bus_connection_int_address ! 68: + subregion->tme_bus_subregion_address_first)) { 1.1 root 69: /* if we're done searching, pivot is already the index of the 70: first element we need to shift to the right in order to 71: insert a new element: */ 72: right = pivot - 1; 73: } 74: 75: /* if we have to move right: */ 1.1.1.2 ! root 76: else if (address ! 77: > (conn_int->tme_bus_connection_int_address ! 78: + subregion->tme_bus_subregion_address_last)) { 1.1 root 79: /* if we're done searching, pivot + 1 is the index of the 80: first element we need to shift to the right in order to 81: insert a new element: */ 82: left = ++pivot; 83: } 84: 85: /* we found the addressable: */ 86: else { 87: return (pivot); 88: } 89: } 90: 91: /* we failed to find an addressable that covers the address: */ 92: return (-1 - pivot); 93: } 94: 95: /* this fills a TLB entry: */ 96: int 97: tme_bus_tlb_fill(struct tme_bus *bus, 98: struct tme_bus_connection_int *conn_int_asker, 99: struct tme_bus_tlb *tlb, 100: tme_bus_addr_t address, 101: unsigned int cycles) 102: { 103: int pivot; 104: struct tme_bus_connection_int *conn_int; 1.1.1.2 ! root 105: const struct tme_bus_subregion *subregion; 1.1 root 106: struct tme_bus_connection *conn_bus_other; 107: tme_bus_addr_t sourced_address_mask, conn_address; 108: tme_bus_addr_t hole_first, hole_last; 109: struct tme_bus_tlb tlb_bus; 110: void *cycle_fault_private; 111: tme_bus_cycle_handler cycle_fault; 112: int rc; 113: 114: /* get the sourced address mask: */ 115: sourced_address_mask = conn_int_asker->tme_bus_connection_int_sourced; 116: 117: /* search for this address on the bus: */ 118: pivot = tme_bus_address_search(bus, sourced_address_mask | address); 119: 120: /* if this address doesn't exist: */ 121: if (pivot < 0) { 122: 123: /* save the bus' fault cycle handler: */ 124: cycle_fault_private = tlb->tme_bus_tlb_cycle_private; 125: cycle_fault = tlb->tme_bus_tlb_cycle; 126: 127: /* initialize the TLB entry: */ 128: tme_bus_tlb_initialize(tlb); 129: 130: /* this TLB entry can cover the entire hole in the address space, 131: limited by the sourced address mask of this device: */ 132: pivot = -1 - pivot; 133: hole_first = (pivot == 0 134: ? 0 1.1.1.2 ! root 135: : ((bus->tme_bus_addressables[pivot - 1] ! 136: .tme_bus_addressable_connection->tme_bus_connection_int_address) ! 137: + (bus->tme_bus_addressables[pivot - 1] ! 138: .tme_bus_addressable_subregion->tme_bus_subregion_address_last) 1.1 root 139: + 1)); 140: hole_first = TME_MAX(hole_first, sourced_address_mask); 141: hole_last = (pivot == bus->tme_bus_addressables_count 142: ? bus->tme_bus_address_mask 1.1.1.2 ! root 143: : ((bus->tme_bus_addressables[pivot] ! 144: .tme_bus_addressable_connection->tme_bus_connection_int_address) ! 145: - 1)); 1.1 root 146: hole_last = TME_MIN(hole_last, 147: sourced_address_mask 148: + conn_int_asker->tme_bus_connection_int_address_last); 149: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, hole_first); 150: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, hole_last); 151: 152: /* reads and writes are allowed: */ 153: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 154: 155: /* reads and writes in this region always fault: */ 156: tlb->tme_bus_tlb_cycle_private = cycle_fault_private; 157: tlb->tme_bus_tlb_cycle = cycle_fault; 158: rc = TME_OK; 159: } 160: 161: /* otherwise, this address does exist: */ 162: else { 1.1.1.2 ! root 163: conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection; ! 164: subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion; 1.1 root 165: conn_bus_other = 166: (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other; 167: 168: /* call the TLB fill function for the connection: */ 169: conn_address = (sourced_address_mask | address) - conn_int->tme_bus_connection_int_address; 170: rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb, 171: conn_address, cycles); 172: 173: /* if that succeeded: */ 174: if (rc == TME_OK) { 175: 176: /* create the mapping TLB entry: */ 177: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_bus.tme_bus_tlb_addr_first, 178: (conn_int->tme_bus_connection_int_address 1.1.1.2 ! root 179: + subregion->tme_bus_subregion_address_first 1.1 root 180: - sourced_address_mask)); 181: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb_bus.tme_bus_tlb_addr_last, 182: (conn_int->tme_bus_connection_int_address 1.1.1.2 ! root 183: + subregion->tme_bus_subregion_address_last 1.1 root 184: - sourced_address_mask)); 185: tlb_bus.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 186: 187: /* map the filled TLB entry: */ 188: tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address); 189: } 190: } 191: 192: /* done: */ 193: return (rc); 194: } 195: 196: /* this allocates a new TLB set: */ 197: int 198: tme_bus_tlb_set_allocate(struct tme_bus *bus, 199: struct tme_bus_connection_int *conn_int_asker, 200: unsigned int count, unsigned int sizeof_one, 201: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs) 202: { 203: struct tme_bus_connection *conn_bus_other, *conn_bus_dma; 204: int conn_int_i; 205: int rc; 206: struct tme_bus_tlb *tlbs, *tlb; 207: unsigned int tlb_i; 208: 209: /* at most one of our addressable connections may provide a TLB set 210: allocator. generally, this means that connection is 211: DMA-controller-like connection to the bus, where it may need to 212: invalidate at any later time the TLBs it fills out, due to sudden 213: changes in how the DMA region on the bus is mapped: */ 214: conn_bus_dma = NULL; 215: for (conn_int_i = 0; 216: conn_int_i < bus->tme_bus_addressables_count; 217: conn_int_i++) { 218: conn_bus_other = 1.1.1.2 ! root 219: ((struct tme_bus_connection *) ! 220: bus->tme_bus_addressables[conn_int_i].tme_bus_addressable_connection ! 221: ->tme_bus_connection_int.tme_bus_connection.tme_connection_other); 1.1 root 222: 223: /* if this bus connection offers a TLB set allocator, it is 224: a DMA-controller-like connection to the bus: */ 225: if (conn_bus_other->tme_bus_tlb_set_allocate != NULL) { 226: 227: /* if there is more than one of these, it is likely a 228: configuration error. if we had some way of specifying which 229: of several DMA regions a given connection will always use, we 230: could avoid this: */ 231: if (conn_bus_dma != NULL) { 232: abort(); 233: } 234: 235: conn_bus_dma = conn_bus_other; 236: } 237: } 238: 239: /* if there is a DMA-controller-like connection to the bus, 240: let it allocate the TLB set: */ 241: if (conn_bus_dma != NULL) { 242: rc = (*conn_bus_dma->tme_bus_tlb_set_allocate) 243: (conn_bus_dma, count, sizeof_one, _tlbs); 244: } 245: 246: /* otherwise, allocate and initialize a singleton set ourselves: */ 247: else { 248: tlbs = (struct tme_bus_tlb *) tme_malloc(count * sizeof_one); 249: tlb = tlbs; 250: for (tlb_i = 0; tlb_i < count; tlb_i++) { 251: tme_bus_tlb_invalidate(tlb); 252: tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one); 253: } 254: TME_ATOMIC_WRITE(struct tme_bus_tlb *, *_tlbs, tlbs); 255: rc = TME_OK; 256: } 257: 258: /* done: */ 259: return (rc); 260: } 261: 262: /* this returns nonzero if the connection's address space is available: */ 263: int 264: tme_bus_connection_ok(struct tme_bus *bus, 265: struct tme_bus_connection_int *conn_int) 266: { 1.1.1.2 ! root 267: const struct tme_bus_subregion *subregion; ! 268: const struct tme_bus_connection *conn_bus_other; 1.1 root 269: int pivot_start, pivot_end; 270: 271: /* if this connection isn't addressable, it's always OK: */ 272: if (!conn_int->tme_bus_connection_int_addressable) { 273: return (TRUE); 274: } 275: 1.1.1.2 ! root 276: /* all subregions of this connection must fit on the bus, ! 277: and they must not overlap with any other subregion on ! 278: any other existing connection: */ ! 279: /* XXX we should also check that the connection's subregions don't ! 280: overlap with each other: */ ! 281: conn_bus_other ! 282: = ((struct tme_bus_connection *) ! 283: conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other); ! 284: for (subregion = &conn_bus_other->tme_bus_subregions; ! 285: subregion != NULL; ! 286: subregion = subregion->tme_bus_subregion_next) { ! 287: ! 288: /* the subregion's last address cannot be less than ! 289: the first address: */ ! 290: if (subregion->tme_bus_subregion_address_last ! 291: < subregion->tme_bus_subregion_address_first) { ! 292: return (FALSE); ! 293: } ! 294: ! 295: /* this subregion must fit on the bus: */ ! 296: if (subregion->tme_bus_subregion_address_last > ! 297: (bus->tme_bus_address_mask ! 298: - conn_int->tme_bus_connection_int_address)) { ! 299: return (FALSE); ! 300: } ! 301: ! 302: /* search for anything covering the start or end of the new ! 303: addressable subregion: */ ! 304: pivot_start = ! 305: tme_bus_address_search(bus, ! 306: (conn_int->tme_bus_connection_int_address ! 307: + subregion->tme_bus_subregion_address_first)); ! 308: pivot_end = ! 309: tme_bus_address_search(bus, ! 310: (conn_int->tme_bus_connection_int_address ! 311: + subregion->tme_bus_subregion_address_last)); ! 312: ! 313: /* both searches must have failed, and they must have stopped at the ! 314: same point in the sorted addressables, further indicating that no ! 315: addressable exists anywhere *between* the start and end of the ! 316: new addressable, either. otherwise, this connection fails: */ ! 317: if (pivot_start >= 0 ! 318: || pivot_end >= 0 ! 319: || pivot_start != pivot_end) { ! 320: return (FALSE); ! 321: } 1.1 root 322: } 323: 324: /* this connection's address space is available: */ 325: return (TRUE); 326: } 327: 328: /* this makes a new connection: */ 329: int 330: tme_bus_connection_make(struct tme_bus *bus, 331: struct tme_bus_connection_int *conn_int, 332: unsigned int state) 333: { 1.1.1.2 ! root 334: const struct tme_bus_connection *conn_bus_other; ! 335: const struct tme_bus_subregion *subregion; 1.1 root 336: int pivot; 337: 338: /* if this connection is not full, return now: */ 339: if (state == TME_CONNECTION_HALF) { 340: return (TME_OK); 341: } 342: 343: /* add this connection to our list: */ 344: conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_next 345: = (struct tme_connection *) bus->tme_bus_connections; 346: bus->tme_bus_connections = conn_int; 347: 348: /* if this connection is addressable, and this is connection is now 349: fully made, add it to our list of addressables: */ 350: if (conn_int->tme_bus_connection_int_addressable 351: && state == TME_CONNECTION_FULL) { 352: 1.1.1.2 ! root 353: /* add all subregions of this connection as addressables: */ ! 354: conn_int->tme_bus_connection_int_address_last = 0; ! 355: conn_bus_other ! 356: = ((struct tme_bus_connection *) ! 357: conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other); ! 358: for (subregion = &conn_bus_other->tme_bus_subregions; ! 359: subregion != NULL; ! 360: subregion = subregion->tme_bus_subregion_next) { ! 361: ! 362: /* search for the place to insert this new addressable: */ ! 363: pivot = tme_bus_address_search(bus, ! 364: (conn_int->tme_bus_connection_int_address ! 365: + subregion->tme_bus_subregion_address_first)); ! 366: assert(pivot < 0); ! 367: pivot = -1 - pivot; 1.1 root 368: 1.1.1.2 ! root 369: /* if we have to, grow the addressable array: */ ! 370: if (bus->tme_bus_addressables_count ! 371: == bus->tme_bus_addressables_size) { ! 372: bus->tme_bus_addressables_size += (bus->tme_bus_addressables_size >> 1) + 1; ! 373: bus->tme_bus_addressables = tme_renew(struct tme_bus_addressable, ! 374: bus->tme_bus_addressables, ! 375: bus->tme_bus_addressables_size); ! 376: } ! 377: ! 378: /* move all of the later addressables down: */ ! 379: memmove(&bus->tme_bus_addressables[pivot + 1], ! 380: &bus->tme_bus_addressables[pivot], ! 381: sizeof(bus->tme_bus_addressables[pivot]) ! 382: * (bus->tme_bus_addressables_count ! 383: - pivot)); ! 384: ! 385: /* insert this new addressable: */ ! 386: bus->tme_bus_addressables[pivot].tme_bus_addressable_connection = conn_int; ! 387: bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion = subregion; ! 388: bus->tme_bus_addressables_count++; ! 389: ! 390: /* update the last address on this connection. NB that the ! 391: subregion information should be used almost always. ! 392: currently this value is only used as the width of the ! 393: connection for the purposes of determining TLB entry limits ! 394: when the connection itself asks to fill a TLB entry: */ ! 395: conn_int->tme_bus_connection_int_address_last ! 396: = TME_MAX(conn_int->tme_bus_connection_int_address_last, ! 397: subregion->tme_bus_subregion_address_last); ! 398: } 1.1 root 399: } 400: 401: return (TME_OK); 402: } 403: 404: /* this breaks a connection: */ 405: int 406: tme_bus_connection_break(struct tme_bus *bus, 407: struct tme_bus_connection_int *conn_int, 408: unsigned int state) 409: { 410: abort(); 411: } 412: 413: /* this map the first bus TLB entry to be valid on another bus, according to 414: the information in the second bus TLB entry: */ 415: void 416: tme_bus_tlb_map(struct tme_bus_tlb *tlb0, tme_bus_addr_t addr0, 417: const struct tme_bus_tlb *tlb1, tme_bus_addr_t addr1) 418: { 419: tme_bus_addr_t extra_before0, extra_after0; 420: tme_bus_addr_t extra_before1, extra_after1; 421: tme_bus_addr_t addr_offset; 422: unsigned int cycles_ok; 423: 424: /* get the address offset: */ 425: addr_offset = addr1 - addr0; 426: 427: /* intersect the amount of bus address space covered: */ 428: extra_before0 = addr0 - TME_ATOMIC_READ(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_first); 429: extra_after0 = TME_ATOMIC_READ(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_last) - addr0; 430: extra_before1 = addr1 - TME_ATOMIC_READ(tme_bus_addr_t, tlb1->tme_bus_tlb_addr_first); 431: extra_after1 = TME_ATOMIC_READ(tme_bus_addr_t, tlb1->tme_bus_tlb_addr_last) - addr1; 432: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_first, 433: addr1 - TME_MIN(extra_before0, extra_before1)); 434: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb0->tme_bus_tlb_addr_last, 435: addr1 + TME_MIN(extra_after0, extra_after1)); 436: 437: /* intersect the kinds of bus cycles allowed: */ 438: cycles_ok = (tlb0->tme_bus_tlb_cycles_ok &= tlb1->tme_bus_tlb_cycles_ok); 439: if (!(cycles_ok & TME_BUS_CYCLE_READ)) { 440: tlb0->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 441: } 442: else if (tlb0->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF) { 443: tlb0->tme_bus_tlb_emulator_off_read -= addr_offset; 444: } 445: if (!(cycles_ok & TME_BUS_CYCLE_WRITE)) { 446: tlb0->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 447: } 448: else if (tlb0->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) { 449: tlb0->tme_bus_tlb_emulator_off_write -= addr_offset; 450: } 451: 452: /* update the address shift for the cycle handler: */ 453: tlb0->tme_bus_tlb_addr_offset -= addr_offset; 454: } 455: 456: /* this invalidates a bus TLB entry: */ 457: void 458: tme_bus_tlb_invalidate(struct tme_bus_tlb *tlb) 459: { 460: 461: /* make the first address covered all-bits-one. the only bus TLB 462: entries this will not invalidate are those that have a last 463: address covered of all-bits one: */ 464: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, -1); 465: 466: /* make the last address covered all-bits-zero. this will 467: invalidate the TLB entries we didn't catch above: */ 468: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, 0); 469: } 470: 471: /* this initializes a bus TLB entry: */ 472: void 473: tme_bus_tlb_initialize(struct tme_bus_tlb *tlb) 474: { 475: 476: /* make the first address covered all-bits-one: */ 477: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, -1); 478: 479: /* make the last address covered all-bits-zero: */ 480: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, 0); 481: 482: /* no fast (memory) transfers allowed: */ 483: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 484: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 485: tlb->tme_bus_tlb_rwlock = NULL; 486: 487: /* no bus cycles allowed: */ 488: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_UNDEF; 489: 490: /* no address offset or shift: */ 491: tlb->tme_bus_tlb_addr_offset = 0; 492: tlb->tme_bus_tlb_addr_shift = 0; 493: 494: /* no bus cycle handler: */ 495: tlb->tme_bus_tlb_cycle_private = NULL; 496: tlb->tme_bus_tlb_cycle = NULL; 497: 498: /* no bus fault handlers: */ 499: tlb->tme_bus_tlb_fault_handler_count = 0; 500: } 501: 502: /* this calls a TLB entry's fault handlers: */ 503: int 504: tme_bus_tlb_fault(struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) 505: { 506: unsigned int i; 507: 508: /* call all of the fault handlers: */ 509: for (i = 0; i < tlb->tme_bus_tlb_fault_handler_count; i++) { 510: rc = ((*tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler) 511: (tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler_private, 512: tlb, cycle, rc)); 513: } 514: 515: return (rc); 516: } 517: 518: /* this parses any bus address: */ 519: tme_bus_addr_t 520: tme_bus_addr_parse_any(const char *address_string, int *_failed) 521: { 522: unsigned long address; 523: char *units; 524: 525: /* catch a NULL string: */ 526: if (address_string == NULL) { 527: *_failed = TRUE; 528: return (0); 529: } 530: 531: /* assume we will succeed: */ 532: *_failed = FALSE; 533: 534: /* convert the string: */ 535: address = strtoul(address_string, &units, 0); 536: if (units == address_string) { 537: *_failed = TRUE; 538: return (0); 539: } 540: 541: /* handle any units: */ 542: if (!strcmp(units, "GB") 543: || !strcasecmp(units, "G")) { 544: return (((tme_bus_addr_t) address) * 1024 * 1024 * 1024); 545: } 546: else if (!strcmp(units, "MB") 547: || !strcasecmp(units, "M")) { 548: return (((tme_bus_addr_t) address) * 1024 * 1024); 549: } 550: else if (!strcmp(units, "KB") 551: || !strcasecmp(units, "k")) { 552: return (((tme_bus_addr_t) address) * 1024); 553: } 554: else if (*units == '\0') { 555: return ((tme_bus_addr_t) address); 556: } 557: *_failed = TRUE; 558: return (0); 559: } 560: 561: /* this parses a bus address that has a restricted range: */ 562: tme_bus_addr_t 563: tme_bus_addr_parse(const char *address_string, tme_bus_addr_t failure_value) 564: { 565: int failed; 566: tme_bus_addr_t address; 567: address = tme_bus_addr_parse_any(address_string, &failed); 568: return (failed ? failure_value : address); 569: } 570: 571: /* this transfers bytes between the two participants in a bus cycle: */ 572: void 573: tme_bus_cycle_xfer(struct tme_bus_cycle *cycle_init, struct tme_bus_cycle *cycle_resp) 574: { 575: struct tme_bus_cycle *cycle_reader, *cycle_writer; 576: int buffer_increment_mask_reader, buffer_increment_mask_writer; 577: int port_size_reader, port_size_writer; 578: int port_overlap_lane_least, port_overlap_size, port_overlap_size_lg2; 579: int lane, lane_end; 580: int lane_reader, lane_writer; 581: int lane_in_reader, lane_in_writer; 582: int lane_routing_offset_reader, lane_routing_offset_writer; 583: tme_bus_lane_t lane_routing_reader, lane_routing_writer; 584: tme_uint8_t lane_value; 585: int warn_on_lane; 586: unsigned int cycle_size_reader, cycle_size_writer; 587: 588: /* sort the initiator and responder into bus reader and bus writer: */ 589: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) { 590: assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); 591: cycle_reader = cycle_init; 592: cycle_writer = cycle_resp; 593: } 594: else { 595: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); 596: assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_READ); 597: cycle_reader = cycle_resp; 598: cycle_writer = cycle_init; 599: } 600: 601: /* get the increment masks for the reader and writer. since 602: tme_bus_cycle_buffer_increment is always 1 or -1, this mask is 603: used to negate values without multiplication: */ 604: if (cycle_reader->tme_bus_cycle_buffer_increment == -1) { 605: buffer_increment_mask_reader = -1; 606: } 607: else { 608: assert(cycle_reader->tme_bus_cycle_buffer_increment == 1); 609: buffer_increment_mask_reader = 0; 610: } 611: if (cycle_writer->tme_bus_cycle_buffer_increment == -1) { 612: buffer_increment_mask_writer = -1; 613: } 614: else { 615: assert(cycle_writer->tme_bus_cycle_buffer_increment == 1); 616: buffer_increment_mask_writer = 0; 617: } 618: #define _TME_BUS_CYCLE_BUFFER_MULTIPLY(value, mask) \ 619: (((value) ^ (mask)) + ((mask) & 1)) 620: 621: /* get the sizes, in bytes, of the reader and writer ports: */ 622: port_size_reader = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port)); 623: port_size_writer = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port)); 624: 625: /* determine how the writer's port and the reader's port overlap: */ 626: port_overlap_size = port_size_writer; 627: port_overlap_lane_least = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port); 628: lane = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port); 629: if (port_overlap_lane_least < lane) { 630: port_overlap_size -= (lane - port_overlap_lane_least); 631: port_overlap_lane_least = lane; 632: } 633: lane += port_size_reader; 634: if ((port_overlap_lane_least + port_overlap_size) > lane) { 635: port_overlap_size -= (lane - (port_overlap_lane_least + port_overlap_size)); 636: } 637: assert(port_overlap_size > 0); 638: for (port_overlap_size_lg2 = 0; 639: (port_overlap_size >>= 1) != 0; 640: port_overlap_size_lg2++); 641: 642: /* select the reader's lane routing: */ 643: lane_routing_offset_reader = 644: TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port), 645: port_overlap_size_lg2, 646: port_overlap_lane_least 647: - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port)); 648: 649: /* select the writer's lane routing: */ 650: lane_routing_offset_writer = 651: TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port), 652: port_overlap_size_lg2, 653: port_overlap_lane_least 654: - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port)); 655: 656: /* loop over all byte lanes in one or both ports: */ 657: lane = TME_MIN(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port), 658: TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port)); 659: lane_end = TME_MAX(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port) + port_size_reader, 660: TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port) + port_size_writer); 661: cycle_size_reader = cycle_size_writer = 0; 662: for (; lane < lane_end; lane++) { 663: 664: /* assume that we won't have to warn on this lane: */ 665: warn_on_lane = FALSE; 666: 667: /* see if this lane falls in the reader or writer's port: */ 668: lane_reader = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port); 669: lane_writer = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port); 670: lane_in_reader = (lane_reader >= 0 && lane_reader < port_size_reader); 671: lane_in_writer = (lane_writer >= 0 && lane_writer < port_size_writer); 672: 673: /* get the value being written to this byte lane. assume a 674: garbage value: */ 675: lane_value = 0xd2; 676: 677: /* if this lane is in the writer's port, it may supply a real 678: lane value: */ 679: if (lane_in_writer) { 680: 681: /* get the routing for the writer: */ 682: lane_routing_writer = 683: cycle_writer->tme_bus_cycle_lane_routing[lane_routing_offset_writer + lane_writer]; 684: 685: /* if the writer doesn't expect this lane to be connected to the 686: reader, we will issue a warning on this lane: */ 687: if ((lane_routing_writer & TME_BUS_LANE_WARN) 688: && lane_in_reader) { 689: warn_on_lane = TRUE; 690: } 691: lane_routing_writer &= ~TME_BUS_LANE_WARN; 692: 693: /* dispatch on the routing to get the lane value: */ 694: if (lane_routing_writer == TME_BUS_LANE_ABORT) { 695: abort(); 696: } 697: else if (lane_routing_writer != TME_BUS_LANE_UNDEF) { 698: if (!(lane_routing_writer & TME_BUS_LANE_ROUTE_WRITE_IGNORE) 699: && lane_routing_writer >= cycle_size_writer) { 700: cycle_size_writer = lane_routing_writer + 1; 701: } 702: lane_routing_writer &= ~TME_BUS_LANE_ROUTE_WRITE_IGNORE; 703: 704: /* if the writer is the responder, make sure that only bytes 705: in the given register are ever referenced. given the 706: writer's port size, we could warp the reference index as 707: needed, but hopefully we'll never have to: */ 708: assert(!(cycle_writer == cycle_resp 709: && (((cycle_writer->tme_bus_cycle_address + lane_routing_writer) 710: ^ cycle_writer->tme_bus_cycle_address) 711: & ~(port_size_writer - 1)) != 0)); 712: 713: lane_value = 714: *(cycle_writer->tme_bus_cycle_buffer 715: + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_writer, 716: buffer_increment_mask_writer)); 717: } 718: } 719: 720: /* if this lane is in the reader's port, it may take the lane 721: value: */ 722: if (lane_in_reader) { 723: 724: /* get the routing for the reader: */ 725: lane_routing_reader = 726: cycle_reader->tme_bus_cycle_lane_routing[lane_routing_offset_reader + lane_reader]; 727: 728: /* if the reader doesn't expect this lane to be connected to the 729: writer, we will issue a warning on this lane: */ 730: if ((lane_routing_reader & TME_BUS_LANE_WARN) 731: && lane_in_writer) { 732: warn_on_lane = TRUE; 733: } 734: lane_routing_reader &= ~TME_BUS_LANE_WARN; 735: 736: /* dispatch on the routing to take the lane value: */ 737: if (lane_routing_reader == TME_BUS_LANE_ABORT) { 738: abort(); 739: } 740: else if (lane_routing_reader != TME_BUS_LANE_UNDEF 741: && !(lane_routing_reader & TME_BUS_LANE_ROUTE_WRITE_IGNORE)) { 742: if (lane_routing_reader >= cycle_size_reader) { 743: cycle_size_reader = lane_routing_reader + 1; 744: } 745: 746: /* if the reader is the responder, make sure that only bytes 747: in the given register are ever referenced. given the 748: reader's port size, we could warp the reference index as 749: needed, but hopefully we'll never have to: */ 750: assert(!(cycle_reader == cycle_resp 751: && (((cycle_reader->tme_bus_cycle_address + lane_routing_reader) 752: ^ cycle_reader->tme_bus_cycle_address) 753: & ~(port_size_reader - 1)) != 0)); 754: 755: *(cycle_reader->tme_bus_cycle_buffer 756: + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_reader, 757: buffer_increment_mask_reader)) = 758: lane_value; 759: } 760: } 761: 762: /* if we need to issue a warning on this lane: */ 763: if (warn_on_lane) { 764: /* XXX TBD: */ 765: abort(); 766: } 767: } 768: 769: /* give the reader feedback: */ 770: cycle_reader->tme_bus_cycle_size = cycle_size_reader; 771: cycle_reader->tme_bus_cycle_address += cycle_size_reader; 772: cycle_reader->tme_bus_cycle_buffer += 773: _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_reader, 774: buffer_increment_mask_reader); 775: cycle_reader->tme_bus_cycle_lane_routing += lane_routing_offset_reader; 776: cycle_reader->tme_bus_cycle_port = 777: TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2); 778: 779: /* give the writer feedback: */ 780: cycle_writer->tme_bus_cycle_size = cycle_size_writer; 781: cycle_writer->tme_bus_cycle_address += cycle_size_writer; 782: cycle_writer->tme_bus_cycle_buffer += 783: _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_writer, 784: buffer_increment_mask_writer); 785: cycle_writer->tme_bus_cycle_lane_routing += lane_routing_offset_writer; 786: cycle_writer->tme_bus_cycle_port = 787: TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2); 788: } 789: 790: /* this handles a bus cycle for a memory-like device: */ 791: void 792: tme_bus_cycle_xfer_memory(struct tme_bus_cycle *cycle_init, tme_uint8_t *memory, tme_bus_addr_t address_last) 793: { 794: tme_uint8_t memory_junk[sizeof(tme_bus_addr_t)]; 795: struct tme_bus_cycle cycle_resp; 796: 797: /* check the starting address: */ 798: assert(cycle_init->tme_bus_cycle_address <= address_last); 799: 800: /* get the start of the buffer for this starting address: */ 801: if (memory != NULL) { 802: memory += cycle_init->tme_bus_cycle_address; 803: } 804: else { 805: assert(sizeof(memory_junk) 1.1.1.2 ! root 806: >= ((unsigned int) 1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port))); 1.1 root 807: memory = memory_junk; 808: } 809: 810: /* create the responder cycle: */ 811: cycle_resp.tme_bus_cycle_buffer = memory; 812: cycle_resp.tme_bus_cycle_buffer_increment = 1; 813: cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing; 814: cycle_resp.tme_bus_cycle_address = cycle_init->tme_bus_cycle_address; 815: cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type 816: ^ (TME_BUS_CYCLE_WRITE 817: | TME_BUS_CYCLE_READ)); 818: cycle_resp.tme_bus_cycle_port = cycle_init->tme_bus_cycle_port; 819: 820: /* run the cycle: */ 821: tme_bus_cycle_xfer(cycle_init, &cycle_resp); 822: 823: /* check the finishing address: */ 824: assert((cycle_init->tme_bus_cycle_address - 1) <= address_last); 825: } 826:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.