|
|
1.1.1.4 ! root 1: /* $Id: bus.c,v 1.13 2007/02/12 23:36: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.4 ! root 37: _TME_RCSID("$Id: bus.c,v 1.13 2007/02/12 23:36:18 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus.h> 1.1.1.3 root 41: #include <tme/misc.h> 1.1 root 42: #include <stdlib.h> 43: #include <string.h> 44: 45: /* this does a binary search of the addressable connections: */ 46: int 47: tme_bus_address_search(struct tme_bus *bus, tme_bus_addr_t address) 48: { 49: int left, right, pivot; 50: struct tme_bus_connection_int *conn_int; 1.1.1.2 root 51: const struct tme_bus_subregion *subregion; 1.1 root 52: 53: /* initialize for the search: */ 54: left = 0; 55: right = bus->tme_bus_addressables_count - 1; 56: 57: /* do the search: */ 58: pivot = 0; 59: for (; left <= right; ) { 60: 61: /* get the pivot: */ 62: pivot = (left + right) / 2; 1.1.1.2 root 63: conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection; 64: subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion; 1.1 root 65: 66: /* if we have to move left: */ 1.1.1.2 root 67: if (address 68: < (conn_int->tme_bus_connection_int_address 69: + subregion->tme_bus_subregion_address_first)) { 1.1 root 70: /* if we're done searching, pivot is already the index of the 71: first element we need to shift to the right in order to 72: insert a new element: */ 73: right = pivot - 1; 74: } 75: 76: /* if we have to move right: */ 1.1.1.2 root 77: else if (address 78: > (conn_int->tme_bus_connection_int_address 79: + subregion->tme_bus_subregion_address_last)) { 1.1 root 80: /* if we're done searching, pivot + 1 is the index of the 81: first element we need to shift to the right in order to 82: insert a new element: */ 83: left = ++pivot; 84: } 85: 86: /* we found the addressable: */ 87: else { 88: return (pivot); 89: } 90: } 91: 92: /* we failed to find an addressable that covers the address: */ 93: return (-1 - pivot); 94: } 95: 96: /* this fills a TLB entry: */ 97: int 98: tme_bus_tlb_fill(struct tme_bus *bus, 99: struct tme_bus_connection_int *conn_int_asker, 100: struct tme_bus_tlb *tlb, 101: tme_bus_addr_t address, 102: unsigned int cycles) 103: { 104: int pivot; 105: struct tme_bus_connection_int *conn_int; 1.1.1.2 root 106: const struct tme_bus_subregion *subregion; 1.1 root 107: struct tme_bus_connection *conn_bus_other; 108: tme_bus_addr_t sourced_address_mask, conn_address; 109: tme_bus_addr_t hole_first, hole_last; 110: struct tme_bus_tlb tlb_bus; 111: void *cycle_fault_private; 112: tme_bus_cycle_handler cycle_fault; 113: int rc; 114: 115: /* get the sourced address mask: */ 116: sourced_address_mask = conn_int_asker->tme_bus_connection_int_sourced; 117: 1.1.1.4 ! root 118: /* get the asked address on the bus: */ ! 119: conn_address = (sourced_address_mask | address); ! 120: ! 121: /* start the mapping TLB entry: */ ! 122: tlb_bus.tme_bus_tlb_addr_first = 0; ! 123: tlb_bus.tme_bus_tlb_addr_last = TME_MIN(((sourced_address_mask ! 124: | (sourced_address_mask - 1)) ! 125: ^ sourced_address_mask), ! 126: bus->tme_bus_address_mask); ! 127: tlb_bus.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 128: ! 129: /* if this bus has a controller, and this request isn't coming from ! 130: the controller: */ ! 131: conn_int = bus->tme_bus_controller; ! 132: if (conn_int != NULL ! 133: && conn_int != conn_int_asker) { ! 134: ! 135: /* get the controller's connection: */ ! 136: conn_bus_other = ! 137: (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other; ! 138: ! 139: /* unlock the bus: */ ! 140: tme_rwlock_unlock(&bus->tme_bus_rwlock); ! 141: ! 142: /* call the controller's TLB fill function: */ ! 143: rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb, ! 144: conn_address, cycles); ! 145: ! 146: /* relock the bus: */ ! 147: /* XXX FIXME - we assume that this succeeds: */ ! 148: (void) tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK); ! 149: ! 150: /* if the TLB fill succeeded: */ ! 151: if (rc == TME_OK) { ! 152: ! 153: /* map the filled TLB entry: */ ! 154: tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address); ! 155: } ! 156: ! 157: return (rc); ! 158: } ! 159: 1.1 root 160: /* search for this address on the bus: */ 1.1.1.4 ! root 161: pivot = tme_bus_address_search(bus, conn_address); 1.1 root 162: 163: /* if this address doesn't exist: */ 164: if (pivot < 0) { 165: 166: /* save the bus' fault cycle handler: */ 167: cycle_fault_private = tlb->tme_bus_tlb_cycle_private; 168: cycle_fault = tlb->tme_bus_tlb_cycle; 169: 170: /* initialize the TLB entry: */ 171: tme_bus_tlb_initialize(tlb); 172: 1.1.1.4 ! root 173: /* this TLB entry can cover the entire hole in the address space: */ 1.1 root 174: pivot = -1 - pivot; 175: hole_first = (pivot == 0 176: ? 0 1.1.1.2 root 177: : ((bus->tme_bus_addressables[pivot - 1] 178: .tme_bus_addressable_connection->tme_bus_connection_int_address) 179: + (bus->tme_bus_addressables[pivot - 1] 180: .tme_bus_addressable_subregion->tme_bus_subregion_address_last) 1.1 root 181: + 1)); 182: hole_last = (pivot == bus->tme_bus_addressables_count 183: ? bus->tme_bus_address_mask 1.1.1.2 root 184: : ((bus->tme_bus_addressables[pivot] 185: .tme_bus_addressable_connection->tme_bus_connection_int_address) 186: - 1)); 1.1.1.4 ! root 187: tlb->tme_bus_tlb_addr_first = hole_first; ! 188: tlb->tme_bus_tlb_addr_last = hole_last; 1.1 root 189: 190: /* reads and writes are allowed: */ 191: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 192: 193: /* reads and writes in this region always fault: */ 194: tlb->tme_bus_tlb_cycle_private = cycle_fault_private; 195: tlb->tme_bus_tlb_cycle = cycle_fault; 196: rc = TME_OK; 197: } 198: 199: /* otherwise, this address does exist: */ 200: else { 1.1.1.2 root 201: conn_int = bus->tme_bus_addressables[pivot].tme_bus_addressable_connection; 202: subregion = bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion; 1.1 root 203: conn_bus_other = 204: (struct tme_bus_connection *) conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other; 205: 206: /* call the TLB fill function for the connection: */ 1.1.1.4 ! root 207: conn_address -= conn_int->tme_bus_connection_int_address; 1.1 root 208: rc = (*conn_bus_other->tme_bus_tlb_fill)(conn_bus_other, tlb, 209: conn_address, cycles); 210: 211: /* if that succeeded: */ 212: if (rc == TME_OK) { 213: 214: /* create the mapping TLB entry: */ 1.1.1.4 ! root 215: tlb_bus.tme_bus_tlb_addr_first = ! 216: (TME_MAX((conn_int->tme_bus_connection_int_address ! 217: + subregion->tme_bus_subregion_address_first), ! 218: (sourced_address_mask ! 219: | tlb_bus.tme_bus_tlb_addr_first)) ! 220: - sourced_address_mask); ! 221: tlb_bus.tme_bus_tlb_addr_last = ! 222: (TME_MIN((conn_int->tme_bus_connection_int_address ! 223: + subregion->tme_bus_subregion_address_last), ! 224: (sourced_address_mask ! 225: | tlb_bus.tme_bus_tlb_addr_last)) ! 226: - sourced_address_mask); 1.1 root 227: } 228: } 229: 1.1.1.4 ! root 230: /* if the TLB fill succeeded: */ ! 231: if (rc == TME_OK) { ! 232: ! 233: /* map the filled TLB entry: */ ! 234: tme_bus_tlb_map(tlb, conn_address, &tlb_bus, address); ! 235: } ! 236: 1.1 root 237: /* done: */ 238: return (rc); 239: } 240: 241: /* this allocates a new TLB set: */ 242: int 243: tme_bus_tlb_set_allocate(struct tme_bus *bus, 244: struct tme_bus_connection_int *conn_int_asker, 245: unsigned int count, unsigned int sizeof_one, 1.1.1.4 ! root 246: struct tme_bus_tlb * tme_shared *_tlbs, ! 247: tme_rwlock_t *_tlbs_rwlock) 1.1 root 248: { 249: struct tme_bus_connection *conn_bus_other, *conn_bus_dma; 250: int conn_int_i; 251: int rc; 252: struct tme_bus_tlb *tlbs, *tlb; 253: unsigned int tlb_i; 254: 255: /* at most one of our addressable connections may provide a TLB set 256: allocator. generally, this means that connection is 257: DMA-controller-like connection to the bus, where it may need to 258: invalidate at any later time the TLBs it fills out, due to sudden 259: changes in how the DMA region on the bus is mapped: */ 260: conn_bus_dma = NULL; 261: for (conn_int_i = 0; 262: conn_int_i < bus->tme_bus_addressables_count; 263: conn_int_i++) { 264: conn_bus_other = 1.1.1.2 root 265: ((struct tme_bus_connection *) 266: bus->tme_bus_addressables[conn_int_i].tme_bus_addressable_connection 267: ->tme_bus_connection_int.tme_bus_connection.tme_connection_other); 1.1 root 268: 269: /* if this bus connection offers a TLB set allocator, it is 270: a DMA-controller-like connection to the bus: */ 271: if (conn_bus_other->tme_bus_tlb_set_allocate != NULL) { 272: 273: /* if there is more than one of these, it is likely a 274: configuration error. if we had some way of specifying which 275: of several DMA regions a given connection will always use, we 276: could avoid this: */ 277: if (conn_bus_dma != NULL) { 278: abort(); 279: } 280: 281: conn_bus_dma = conn_bus_other; 282: } 283: } 284: 285: /* if there is a DMA-controller-like connection to the bus, 286: let it allocate the TLB set: */ 287: if (conn_bus_dma != NULL) { 288: rc = (*conn_bus_dma->tme_bus_tlb_set_allocate) 1.1.1.4 ! root 289: (conn_bus_dma, count, sizeof_one, _tlbs, _tlbs_rwlock); 1.1 root 290: } 291: 292: /* otherwise, allocate and initialize a singleton set ourselves: */ 293: else { 294: tlbs = (struct tme_bus_tlb *) tme_malloc(count * sizeof_one); 295: tlb = tlbs; 296: for (tlb_i = 0; tlb_i < count; tlb_i++) { 1.1.1.4 ! root 297: tme_bus_tlb_construct(tlb); 1.1 root 298: tlb = (struct tme_bus_tlb *) (((tme_uint8_t *) tlb) + sizeof_one); 299: } 1.1.1.4 ! root 300: tme_memory_atomic_pointer_write(struct tme_bus_tlb *, *_tlbs, tlbs, _tlbs_rwlock); 1.1 root 301: rc = TME_OK; 302: } 303: 304: /* done: */ 305: return (rc); 306: } 307: 308: /* this returns nonzero if the connection's address space is available: */ 309: int 310: tme_bus_connection_ok(struct tme_bus *bus, 311: struct tme_bus_connection_int *conn_int) 312: { 1.1.1.2 root 313: const struct tme_bus_subregion *subregion; 314: const struct tme_bus_connection *conn_bus_other; 1.1 root 315: int pivot_start, pivot_end; 316: 317: /* if this connection isn't addressable, it's always OK: */ 1.1.1.4 ! root 318: if (!(conn_int->tme_bus_connection_int_flags ! 319: & TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE)) { 1.1 root 320: return (TRUE); 321: } 322: 1.1.1.2 root 323: /* all subregions of this connection must fit on the bus, 324: and they must not overlap with any other subregion on 325: any other existing connection: */ 326: /* XXX we should also check that the connection's subregions don't 327: overlap with each other: */ 328: conn_bus_other 329: = ((struct tme_bus_connection *) 330: conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other); 331: for (subregion = &conn_bus_other->tme_bus_subregions; 332: subregion != NULL; 333: subregion = subregion->tme_bus_subregion_next) { 334: 335: /* the subregion's last address cannot be less than 336: the first address: */ 337: if (subregion->tme_bus_subregion_address_last 338: < subregion->tme_bus_subregion_address_first) { 339: return (FALSE); 340: } 341: 342: /* this subregion must fit on the bus: */ 343: if (subregion->tme_bus_subregion_address_last > 344: (bus->tme_bus_address_mask 345: - conn_int->tme_bus_connection_int_address)) { 346: return (FALSE); 347: } 348: 349: /* search for anything covering the start or end of the new 350: addressable subregion: */ 351: pivot_start = 352: tme_bus_address_search(bus, 353: (conn_int->tme_bus_connection_int_address 354: + subregion->tme_bus_subregion_address_first)); 355: pivot_end = 356: tme_bus_address_search(bus, 357: (conn_int->tme_bus_connection_int_address 358: + subregion->tme_bus_subregion_address_last)); 359: 360: /* both searches must have failed, and they must have stopped at the 361: same point in the sorted addressables, further indicating that no 362: addressable exists anywhere *between* the start and end of the 363: new addressable, either. otherwise, this connection fails: */ 364: if (pivot_start >= 0 365: || pivot_end >= 0 366: || pivot_start != pivot_end) { 367: return (FALSE); 368: } 1.1 root 369: } 370: 371: /* this connection's address space is available: */ 372: return (TRUE); 373: } 374: 375: /* this makes a new connection: */ 376: int 377: tme_bus_connection_make(struct tme_bus *bus, 378: struct tme_bus_connection_int *conn_int, 379: unsigned int state) 380: { 1.1.1.2 root 381: const struct tme_bus_connection *conn_bus_other; 382: const struct tme_bus_subregion *subregion; 1.1 root 383: int pivot; 384: 385: /* if this connection is not full, return now: */ 386: if (state == TME_CONNECTION_HALF) { 387: return (TME_OK); 388: } 389: 1.1.1.4 ! root 390: /* if this connection is to a bus controller: */ ! 391: if (conn_int->tme_bus_connection_int_flags ! 392: & TME_BUS_CONNECTION_INT_FLAG_CONTROLLER) { ! 393: ! 394: /* if this bus already has a controller: */ ! 395: if (bus->tme_bus_controller != NULL) { ! 396: ! 397: /* we can't make this connection: */ ! 398: return (EEXIST); ! 399: } ! 400: ! 401: /* this connection is to the bus controller: */ ! 402: bus->tme_bus_controller = conn_int; ! 403: } ! 404: 1.1 root 405: /* add this connection to our list: */ 406: conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_next 407: = (struct tme_connection *) bus->tme_bus_connections; 408: bus->tme_bus_connections = conn_int; 409: 410: /* if this connection is addressable, and this is connection is now 411: fully made, add it to our list of addressables: */ 1.1.1.4 ! root 412: if ((conn_int->tme_bus_connection_int_flags ! 413: & TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE) 1.1 root 414: && state == TME_CONNECTION_FULL) { 415: 1.1.1.2 root 416: /* add all subregions of this connection as addressables: */ 417: conn_int->tme_bus_connection_int_address_last = 0; 418: conn_bus_other 419: = ((struct tme_bus_connection *) 420: conn_int->tme_bus_connection_int.tme_bus_connection.tme_connection_other); 421: for (subregion = &conn_bus_other->tme_bus_subregions; 422: subregion != NULL; 423: subregion = subregion->tme_bus_subregion_next) { 424: 425: /* search for the place to insert this new addressable: */ 426: pivot = tme_bus_address_search(bus, 427: (conn_int->tme_bus_connection_int_address 428: + subregion->tme_bus_subregion_address_first)); 429: assert(pivot < 0); 430: pivot = -1 - pivot; 1.1 root 431: 1.1.1.2 root 432: /* if we have to, grow the addressable array: */ 433: if (bus->tme_bus_addressables_count 434: == bus->tme_bus_addressables_size) { 435: bus->tme_bus_addressables_size += (bus->tme_bus_addressables_size >> 1) + 1; 436: bus->tme_bus_addressables = tme_renew(struct tme_bus_addressable, 437: bus->tme_bus_addressables, 438: bus->tme_bus_addressables_size); 439: } 440: 441: /* move all of the later addressables down: */ 442: memmove(&bus->tme_bus_addressables[pivot + 1], 443: &bus->tme_bus_addressables[pivot], 444: sizeof(bus->tme_bus_addressables[pivot]) 445: * (bus->tme_bus_addressables_count 446: - pivot)); 447: 448: /* insert this new addressable: */ 449: bus->tme_bus_addressables[pivot].tme_bus_addressable_connection = conn_int; 450: bus->tme_bus_addressables[pivot].tme_bus_addressable_subregion = subregion; 451: bus->tme_bus_addressables_count++; 452: 453: /* update the last address on this connection. NB that the 454: subregion information should be used almost always. 455: currently this value is only used as the width of the 456: connection for the purposes of determining TLB entry limits 457: when the connection itself asks to fill a TLB entry: */ 458: conn_int->tme_bus_connection_int_address_last 459: = TME_MAX(conn_int->tme_bus_connection_int_address_last, 460: subregion->tme_bus_subregion_address_last); 461: } 1.1 root 462: } 463: 464: return (TME_OK); 465: } 466: 467: /* this breaks a connection: */ 468: int 469: tme_bus_connection_break(struct tme_bus *bus, 470: struct tme_bus_connection_int *conn_int, 471: unsigned int state) 472: { 473: abort(); 474: } 475: 476: /* this map the first bus TLB entry to be valid on another bus, according to 477: the information in the second bus TLB entry: */ 478: void 479: tme_bus_tlb_map(struct tme_bus_tlb *tlb0, tme_bus_addr_t addr0, 480: const struct tme_bus_tlb *tlb1, tme_bus_addr_t addr1) 481: { 482: tme_bus_addr_t extra_before0, extra_after0; 483: tme_bus_addr_t extra_before1, extra_after1; 1.1.1.4 ! root 484: long addr_offset; 1.1 root 485: unsigned int cycles_ok; 486: 487: /* get the address offset: */ 1.1.1.4 ! root 488: addr_offset = addr1; ! 489: addr_offset -= addr0; 1.1 root 490: 491: /* intersect the amount of bus address space covered: */ 1.1.1.4 ! root 492: extra_before0 = addr0 - tlb0->tme_bus_tlb_addr_first; ! 493: extra_after0 = tlb0->tme_bus_tlb_addr_last - addr0; ! 494: extra_before1 = addr1 - tlb1->tme_bus_tlb_addr_first; ! 495: extra_after1 = tlb1->tme_bus_tlb_addr_last - addr1; ! 496: tlb0->tme_bus_tlb_addr_first = addr1 - TME_MIN(extra_before0, extra_before1); ! 497: tlb0->tme_bus_tlb_addr_last = addr1 + TME_MIN(extra_after0, extra_after1); 1.1 root 498: 499: /* intersect the kinds of bus cycles allowed: */ 500: cycles_ok = (tlb0->tme_bus_tlb_cycles_ok &= tlb1->tme_bus_tlb_cycles_ok); 501: if (!(cycles_ok & TME_BUS_CYCLE_READ)) { 502: tlb0->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 503: } 504: else if (tlb0->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF) { 505: tlb0->tme_bus_tlb_emulator_off_read -= addr_offset; 506: } 507: if (!(cycles_ok & TME_BUS_CYCLE_WRITE)) { 508: tlb0->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 509: } 510: else if (tlb0->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) { 511: tlb0->tme_bus_tlb_emulator_off_write -= addr_offset; 512: } 513: 514: /* update the address shift for the cycle handler: */ 515: tlb0->tme_bus_tlb_addr_offset -= addr_offset; 516: } 517: 1.1.1.4 ! root 518: /* this constructs a new global TLB entry: */ 1.1.1.3 root 519: void 1.1.1.4 ! root 520: tme_bus_tlb_construct(struct tme_bus_tlb *tlb) 1.1.1.3 root 521: { 1.1.1.4 ! root 522: /* a new global TLB entry is invalid and not busy: */ ! 523: tlb->tme_bus_tlb_invalid = TRUE; ! 524: tme_rwlock_init(&tlb->tme_bus_tlb_invalid_rwlock); ! 525: tlb->tme_bus_tlb_busy = FALSE; ! 526: tme_rwlock_init(&tlb->tme_bus_tlb_busy_rwlock); ! 527: tlb->tme_bus_tlb_global = tlb; 1.1.1.3 root 528: } 529: 1.1.1.4 ! root 530: /* this saves a bus TLB entry in automatic storage into a backing ! 531: global bus TLB entry: */ 1.1.1.3 root 532: void 533: tme_bus_tlb_back(const struct tme_bus_tlb *tlb_local) 534: { 535: struct tme_bus_tlb *tlb_backing; 536: 537: /* get the backing TLB entry: */ 1.1.1.4 ! root 538: tlb_backing = tlb_local->tme_bus_tlb_global; 1.1.1.3 root 539: 540: #define TLB_BACK(f) tlb_backing->f = tlb_local->f 541: 542: /* the first address covered: */ 1.1.1.4 ! root 543: TLB_BACK(tme_bus_tlb_addr_first); 1.1.1.3 root 544: 545: /* the last address covered: */ 1.1.1.4 ! root 546: TLB_BACK(tme_bus_tlb_addr_last); 1.1.1.3 root 547: 548: /* the fast (memory) transfers: */ 549: TLB_BACK(tme_bus_tlb_emulator_off_read); 550: TLB_BACK(tme_bus_tlb_emulator_off_write); 551: 552: /* fast (memory) reads and writes are protected by this rwlock: */ 553: TLB_BACK(tme_bus_tlb_rwlock); 554: 555: /* when one or both of TLB_BUS_CYCLE_READ and TLB_BUS_CYCLE_WRITE 556: are set in this value, this TLB entry allows slow (function call) 557: reads of and/or writes to the bus region: */ 558: TLB_BACK(tme_bus_tlb_cycles_ok); 559: 560: /* adding an address in the bus region to this offset, and then 561: shifting that result to the right (shift > 0) or to the left 562: (shift < 0) yields an address for the bus cycle handler: */ 563: TLB_BACK(tme_bus_tlb_addr_offset); 564: TLB_BACK(tme_bus_tlb_addr_shift); 565: 566: /* the bus cycle handler: */ 567: TLB_BACK(tme_bus_tlb_cycle_private); 568: TLB_BACK(tme_bus_tlb_cycle); 569: 570: /* the bus fault handlers: */ 571: TLB_BACK(tme_bus_tlb_fault_handler_count); 572: memcpy (&tlb_backing->tme_bus_tlb_fault_handlers[0], 573: &tlb_local->tme_bus_tlb_fault_handlers[0], 574: sizeof (tlb_local->tme_bus_tlb_fault_handlers[0]) 575: * tlb_local->tme_bus_tlb_fault_handler_count); 576: 577: #undef TLB_BACK 578: } 579: 1.1 root 580: /* this invalidates a bus TLB entry: */ 581: void 582: tme_bus_tlb_invalidate(struct tme_bus_tlb *tlb) 583: { 1.1.1.3 root 584: 1.1.1.4 ! root 585: /* lock this TLB entry for invalidation: */ ! 586: tme_rwlock_wrlock(&tlb->tme_bus_tlb_invalid_rwlock); 1.1.1.3 root 587: 1.1.1.4 ! root 588: /* invalidate this TLB entry: */ ! 589: tlb->tme_bus_tlb_invalid = TRUE; ! 590: ! 591: #if TME_THREADS_COOPERATIVE ! 592: #ifndef TME_NO_DEBUG_LOCKS ! 593: assert(!tme_memory_atomic_read_flag(&tlb->tme_bus_tlb_busy, ! 594: &tlb->tme_bus_tlb_busy_rwlock)); ! 595: #endif /* !TME_NO_DEBUG_LOCKS */ ! 596: #else /* !TME_THREADS_COOPERATIVE */ ! 597: /* spin while the TLB entry is busy: */ ! 598: do { } while(tme_memory_atomic_read_flag(&tlb->tme_bus_tlb_busy, ! 599: &tlb->tme_bus_tlb_busy_rwlock)); ! 600: #endif /* !TME_THREADS_COOPERATIVE */ 1.1.1.3 root 601: 1.1.1.4 ! root 602: /* unlock this TLB entry for invalidation: */ ! 603: tme_rwlock_unlock(&tlb->tme_bus_tlb_invalid_rwlock); 1.1 root 604: } 605: 606: /* this initializes a bus TLB entry: */ 607: void 608: tme_bus_tlb_initialize(struct tme_bus_tlb *tlb) 609: { 610: 611: /* make the first address covered all-bits-one: */ 1.1.1.4 ! root 612: tlb->tme_bus_tlb_addr_first = (((tme_bus_addr_t) 0) - 1); 1.1 root 613: 614: /* make the last address covered all-bits-zero: */ 1.1.1.4 ! root 615: tlb->tme_bus_tlb_addr_last = 0; 1.1 root 616: 617: /* no fast (memory) transfers allowed: */ 618: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF; 619: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; 620: tlb->tme_bus_tlb_rwlock = NULL; 621: 622: /* no bus cycles allowed: */ 623: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_UNDEF; 624: 625: /* no address offset or shift: */ 626: tlb->tme_bus_tlb_addr_offset = 0; 627: tlb->tme_bus_tlb_addr_shift = 0; 628: 629: /* no bus cycle handler: */ 630: tlb->tme_bus_tlb_cycle_private = NULL; 631: tlb->tme_bus_tlb_cycle = NULL; 632: 633: /* no bus fault handlers: */ 634: tlb->tme_bus_tlb_fault_handler_count = 0; 635: } 636: 637: /* this calls a TLB entry's fault handlers: */ 638: int 639: tme_bus_tlb_fault(struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc) 640: { 641: unsigned int i; 642: 643: /* call all of the fault handlers: */ 644: for (i = 0; i < tlb->tme_bus_tlb_fault_handler_count; i++) { 645: rc = ((*tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler) 646: (tlb->tme_bus_tlb_fault_handlers[i].tme_bus_tlb_fault_handler_private, 647: tlb, cycle, rc)); 648: } 649: 650: return (rc); 651: } 652: 653: /* this parses any bus address: */ 654: tme_bus_addr_t 655: tme_bus_addr_parse_any(const char *address_string, int *_failed) 656: { 1.1.1.3 root 657: return (tme_misc_unumber_parse_any(address_string, _failed)); 1.1 root 658: } 659: 660: /* this parses a bus address that has a restricted range: */ 661: tme_bus_addr_t 662: tme_bus_addr_parse(const char *address_string, tme_bus_addr_t failure_value) 663: { 664: int failed; 665: tme_bus_addr_t address; 666: address = tme_bus_addr_parse_any(address_string, &failed); 667: return (failed ? failure_value : address); 668: } 669: 670: /* this transfers bytes between the two participants in a bus cycle: */ 671: void 672: tme_bus_cycle_xfer(struct tme_bus_cycle *cycle_init, struct tme_bus_cycle *cycle_resp) 673: { 674: struct tme_bus_cycle *cycle_reader, *cycle_writer; 675: int buffer_increment_mask_reader, buffer_increment_mask_writer; 676: int port_size_reader, port_size_writer; 677: int port_overlap_lane_least, port_overlap_size, port_overlap_size_lg2; 678: int lane, lane_end; 679: int lane_reader, lane_writer; 680: int lane_in_reader, lane_in_writer; 681: int lane_routing_offset_reader, lane_routing_offset_writer; 682: tme_bus_lane_t lane_routing_reader, lane_routing_writer; 683: tme_uint8_t lane_value; 684: int warn_on_lane; 685: unsigned int cycle_size_reader, cycle_size_writer; 686: 687: /* sort the initiator and responder into bus reader and bus writer: */ 688: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) { 689: assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); 690: cycle_reader = cycle_init; 691: cycle_writer = cycle_resp; 692: } 693: else { 694: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); 695: assert(cycle_resp->tme_bus_cycle_type == TME_BUS_CYCLE_READ); 696: cycle_reader = cycle_resp; 697: cycle_writer = cycle_init; 698: } 699: 700: /* get the increment masks for the reader and writer. since 701: tme_bus_cycle_buffer_increment is always 1 or -1, this mask is 702: used to negate values without multiplication: */ 703: if (cycle_reader->tme_bus_cycle_buffer_increment == -1) { 704: buffer_increment_mask_reader = -1; 705: } 706: else { 707: assert(cycle_reader->tme_bus_cycle_buffer_increment == 1); 708: buffer_increment_mask_reader = 0; 709: } 710: if (cycle_writer->tme_bus_cycle_buffer_increment == -1) { 711: buffer_increment_mask_writer = -1; 712: } 713: else { 714: assert(cycle_writer->tme_bus_cycle_buffer_increment == 1); 715: buffer_increment_mask_writer = 0; 716: } 717: #define _TME_BUS_CYCLE_BUFFER_MULTIPLY(value, mask) \ 718: (((value) ^ (mask)) + ((mask) & 1)) 719: 720: /* get the sizes, in bytes, of the reader and writer ports: */ 721: port_size_reader = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port)); 722: port_size_writer = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port)); 723: 724: /* determine how the writer's port and the reader's port overlap: */ 725: port_overlap_size = port_size_writer; 726: port_overlap_lane_least = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port); 727: lane = TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port); 728: if (port_overlap_lane_least < lane) { 729: port_overlap_size -= (lane - port_overlap_lane_least); 730: port_overlap_lane_least = lane; 731: } 732: lane += port_size_reader; 733: if ((port_overlap_lane_least + port_overlap_size) > lane) { 734: port_overlap_size -= (lane - (port_overlap_lane_least + port_overlap_size)); 735: } 736: assert(port_overlap_size > 0); 737: for (port_overlap_size_lg2 = 0; 738: (port_overlap_size >>= 1) != 0; 739: port_overlap_size_lg2++); 740: 741: /* select the reader's lane routing: */ 742: lane_routing_offset_reader = 743: TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_reader->tme_bus_cycle_port), 744: port_overlap_size_lg2, 745: port_overlap_lane_least 746: - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port)); 747: 748: /* select the writer's lane routing: */ 749: lane_routing_offset_writer = 750: TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_writer->tme_bus_cycle_port), 751: port_overlap_size_lg2, 752: port_overlap_lane_least 753: - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port)); 754: 755: /* loop over all byte lanes in one or both ports: */ 756: lane = TME_MIN(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port), 757: TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port)); 758: lane_end = TME_MAX(TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port) + port_size_reader, 759: TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port) + port_size_writer); 760: cycle_size_reader = cycle_size_writer = 0; 761: for (; lane < lane_end; lane++) { 762: 763: /* assume that we won't have to warn on this lane: */ 764: warn_on_lane = FALSE; 765: 766: /* see if this lane falls in the reader or writer's port: */ 767: lane_reader = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_reader->tme_bus_cycle_port); 768: lane_writer = lane - TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_writer->tme_bus_cycle_port); 769: lane_in_reader = (lane_reader >= 0 && lane_reader < port_size_reader); 770: lane_in_writer = (lane_writer >= 0 && lane_writer < port_size_writer); 771: 772: /* get the value being written to this byte lane. assume a 773: garbage value: */ 774: lane_value = 0xd2; 775: 776: /* if this lane is in the writer's port, it may supply a real 777: lane value: */ 778: if (lane_in_writer) { 779: 780: /* get the routing for the writer: */ 781: lane_routing_writer = 782: cycle_writer->tme_bus_cycle_lane_routing[lane_routing_offset_writer + lane_writer]; 783: 784: /* if the writer doesn't expect this lane to be connected to the 785: reader, we will issue a warning on this lane: */ 786: if ((lane_routing_writer & TME_BUS_LANE_WARN) 787: && lane_in_reader) { 788: warn_on_lane = TRUE; 789: } 790: lane_routing_writer &= ~TME_BUS_LANE_WARN; 791: 792: /* dispatch on the routing to get the lane value: */ 793: if (lane_routing_writer == TME_BUS_LANE_ABORT) { 794: abort(); 795: } 796: else if (lane_routing_writer != TME_BUS_LANE_UNDEF) { 797: if (!(lane_routing_writer & TME_BUS_LANE_ROUTE_WRITE_IGNORE) 798: && lane_routing_writer >= cycle_size_writer) { 799: cycle_size_writer = lane_routing_writer + 1; 800: } 801: lane_routing_writer &= ~TME_BUS_LANE_ROUTE_WRITE_IGNORE; 802: 803: /* if the writer is the responder, make sure that only bytes 804: in the given register are ever referenced. given the 805: writer's port size, we could warp the reference index as 806: needed, but hopefully we'll never have to: */ 807: assert(!(cycle_writer == cycle_resp 808: && (((cycle_writer->tme_bus_cycle_address + lane_routing_writer) 809: ^ cycle_writer->tme_bus_cycle_address) 810: & ~(port_size_writer - 1)) != 0)); 811: 812: lane_value = 813: *(cycle_writer->tme_bus_cycle_buffer 814: + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_writer, 815: buffer_increment_mask_writer)); 816: } 817: } 818: 819: /* if this lane is in the reader's port, it may take the lane 820: value: */ 821: if (lane_in_reader) { 822: 823: /* get the routing for the reader: */ 824: lane_routing_reader = 825: cycle_reader->tme_bus_cycle_lane_routing[lane_routing_offset_reader + lane_reader]; 826: 827: /* if the reader doesn't expect this lane to be connected to the 828: writer, we will issue a warning on this lane: */ 829: if ((lane_routing_reader & TME_BUS_LANE_WARN) 830: && lane_in_writer) { 831: warn_on_lane = TRUE; 832: } 833: lane_routing_reader &= ~TME_BUS_LANE_WARN; 834: 835: /* dispatch on the routing to take the lane value: */ 836: if (lane_routing_reader == TME_BUS_LANE_ABORT) { 837: abort(); 838: } 839: else if (lane_routing_reader != TME_BUS_LANE_UNDEF 840: && !(lane_routing_reader & TME_BUS_LANE_ROUTE_WRITE_IGNORE)) { 841: if (lane_routing_reader >= cycle_size_reader) { 842: cycle_size_reader = lane_routing_reader + 1; 843: } 844: 845: /* if the reader is the responder, make sure that only bytes 846: in the given register are ever referenced. given the 847: reader's port size, we could warp the reference index as 848: needed, but hopefully we'll never have to: */ 849: assert(!(cycle_reader == cycle_resp 850: && (((cycle_reader->tme_bus_cycle_address + lane_routing_reader) 851: ^ cycle_reader->tme_bus_cycle_address) 852: & ~(port_size_reader - 1)) != 0)); 853: 854: *(cycle_reader->tme_bus_cycle_buffer 855: + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing_reader, 856: buffer_increment_mask_reader)) = 857: lane_value; 858: } 859: } 860: 861: /* if we need to issue a warning on this lane: */ 862: if (warn_on_lane) { 863: /* XXX TBD: */ 864: abort(); 865: } 866: } 867: 868: /* give the reader feedback: */ 869: cycle_reader->tme_bus_cycle_size = cycle_size_reader; 870: cycle_reader->tme_bus_cycle_address += cycle_size_reader; 871: cycle_reader->tme_bus_cycle_buffer += 872: _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_reader, 873: buffer_increment_mask_reader); 874: cycle_reader->tme_bus_cycle_lane_routing += lane_routing_offset_reader; 875: cycle_reader->tme_bus_cycle_port = 876: TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2); 877: 878: /* give the writer feedback: */ 879: cycle_writer->tme_bus_cycle_size = cycle_size_writer; 880: cycle_writer->tme_bus_cycle_address += cycle_size_writer; 881: cycle_writer->tme_bus_cycle_buffer += 882: _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_writer, 883: buffer_increment_mask_writer); 884: cycle_writer->tme_bus_cycle_lane_routing += lane_routing_offset_writer; 885: cycle_writer->tme_bus_cycle_port = 886: TME_BUS_CYCLE_PORT(port_overlap_lane_least, port_overlap_size_lg2); 887: } 888: 889: /* this handles a bus cycle for a memory-like device: */ 890: void 891: tme_bus_cycle_xfer_memory(struct tme_bus_cycle *cycle_init, tme_uint8_t *memory, tme_bus_addr_t address_last) 892: { 893: tme_uint8_t memory_junk[sizeof(tme_bus_addr_t)]; 894: struct tme_bus_cycle cycle_resp; 895: 896: /* check the starting address: */ 897: assert(cycle_init->tme_bus_cycle_address <= address_last); 898: 899: /* get the start of the buffer for this starting address: */ 900: if (memory != NULL) { 901: memory += cycle_init->tme_bus_cycle_address; 902: } 903: else { 904: assert(sizeof(memory_junk) 1.1.1.2 root 905: >= ((unsigned int) 1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port))); 1.1 root 906: memory = memory_junk; 907: } 908: 909: /* create the responder cycle: */ 910: cycle_resp.tme_bus_cycle_buffer = memory; 911: cycle_resp.tme_bus_cycle_buffer_increment = 1; 912: cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing; 913: cycle_resp.tme_bus_cycle_address = cycle_init->tme_bus_cycle_address; 914: cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type 915: ^ (TME_BUS_CYCLE_WRITE 916: | TME_BUS_CYCLE_READ)); 917: cycle_resp.tme_bus_cycle_port = cycle_init->tme_bus_cycle_port; 918: 919: /* run the cycle: */ 920: tme_bus_cycle_xfer(cycle_init, &cycle_resp); 921: 922: /* check the finishing address: */ 923: assert((cycle_init->tme_bus_cycle_address - 1) <= address_last); 924: } 925: 1.1.1.3 root 926: /* given an initiator's cycle and a responder's port size, assuming 927: that the responder's port fits completely within the initiator's 928: port, this internal function returns the "correct" least lane for 929: the responder's port, relative to the least lane of the initiator's 930: port. this requires that the initiator's lane routing use either 931: TME_BUS_LANE_ABORT or TME_BUS_LANE_WARN on routings for incorrect 932: lanes: */ 933: static unsigned int 934: _tme_bus_cycle_xfer_resp_least_lane(const struct tme_bus_cycle *cycle_init, 935: unsigned int port_size_log2_resp) 936: { 937: unsigned int port_size_resp; 938: unsigned int port_lane_least_max_resp; 939: unsigned int port_lane_least_resp; 940: const tme_bus_lane_t *lane_routing_init; 941: unsigned int lane; 942: int lane_routing; 943: 944: /* get the responder's port size: */ 945: port_size_resp = (1 << port_size_log2_resp); 946: 947: /* calculate the maximum possible least lane for the responder. we 948: require that the responder's port fit completely within the 949: initiator's port: */ 950: port_lane_least_max_resp = (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port)); 951: if (__tme_predict_false(port_size_resp > port_lane_least_max_resp)) { 952: abort(); 953: } 954: port_lane_least_max_resp -= port_size_resp; 955: 956: /* assume that the responder will have the same least lane as the 957: initiator, and get the initiator's lane routing for that 958: responder least lane: */ 959: port_lane_least_resp = 0; 960: lane_routing_init 961: = (cycle_init->tme_bus_cycle_lane_routing 962: + TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port), 963: port_size_log2_resp, 964: port_lane_least_resp)); 965: 966: /* loop over all of the possible least lanes for the responder: */ 967: for (; 968: port_lane_least_resp <= port_lane_least_max_resp; 969: port_lane_least_resp++) { 970: 971: /* check the routing for all of the lanes in the responder's port, starting 972: from the highest numbered lane and working down: */ 973: lane = port_lane_least_resp + port_size_resp; 974: for (;;) { 975: lane = lane - 1; 976: lane_routing = lane_routing_init[lane]; 977: 978: /* if this lane gets a warning or an abort, this is not the 979: correct least lane for the responder: */ 980: if ((lane_routing & TME_BUS_LANE_WARN) 981: || lane_routing == TME_BUS_LANE_ABORT) { 982: break; 983: } 984: 985: /* if we have now checked all of the lanes in the overlap between 986: initiator and responder, we've found the correct least lane for 987: the responder: */ 988: if (lane == port_lane_least_resp) { 989: return (port_lane_least_resp); 990: } 991: } 992: 993: /* advance the offset into the initiator's lane routing: */ 994: lane_routing_init += (1 << TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port)); 995: } 996: 997: /* if we get here, the initiator doesn't allow responders of the 998: given port size: */ 999: abort(); 1000: } 1001: 1002: /* this handles a bus cycle for a simple register device: */ 1003: void 1004: tme_bus_cycle_xfer_reg(struct tme_bus_cycle *cycle_init, 1005: void *resp_reg, 1006: unsigned int port_size_log2_resp) 1007: { 1008: unsigned int port_lane_least_resp; 1009: const tme_bus_lane_t *lane_routing_init; 1010: unsigned int lane_count; 1011: unsigned int lane; 1012: tme_uint8_t *buffer_init; 1013: tme_uint8_t *buffer_resp; 1014: int lane_routing; 1015: int cycle_size_init; 1016: int buffer_increment_mask_init; 1017: int writer_init; 1018: 1019: /* see if the initiator is writing: */ 1020: writer_init = (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE); 1021: assert (writer_init || cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); 1022: 1023: /* get the increment mask for the initiator. since 1024: tme_bus_cycle_buffer_increment is always 1 or -1, this mask is 1025: used to negate values without multiplication: */ 1026: if (cycle_init->tme_bus_cycle_buffer_increment == -1) { 1027: buffer_increment_mask_init = -1; 1028: } 1029: else { 1030: assert(cycle_init->tme_bus_cycle_buffer_increment == 1); 1031: buffer_increment_mask_init = 0; 1032: } 1033: 1034: /* get the least lane for the responder's port relative to the 1035: initiator port's least lane, assuming that the responder's port 1036: fits completely within the initiator's port and starts at the 1037: "correct" least lane: */ 1038: port_lane_least_resp = _tme_bus_cycle_xfer_resp_least_lane(cycle_init, 1039: port_size_log2_resp); 1040: 1041: /* get the initiator's lane routing: */ 1042: lane_routing_init 1043: = (cycle_init->tme_bus_cycle_lane_routing 1044: + TME_BUS_ROUTER_INDEX(TME_BUS_CYCLE_PORT_SIZE_LG2(cycle_init->tme_bus_cycle_port), 1045: port_size_log2_resp, 1046: port_lane_least_resp)); 1047: 1048: /* return some things to the initiator: */ 1049: cycle_init->tme_bus_cycle_lane_routing = lane_routing_init; 1050: cycle_init->tme_bus_cycle_port = 1051: TME_BUS_CYCLE_PORT((TME_BUS_CYCLE_PORT_LANE_LEAST(cycle_init->tme_bus_cycle_port) 1052: + port_lane_least_resp), 1053: port_size_log2_resp); 1054: 1055: /* advance the initiator's lane routing to the first lane in the 1056: responder's port: */ 1057: lane_routing_init += port_lane_least_resp; 1058: 1059: /* get the lane count: */ 1060: lane_count = (1 << port_size_log2_resp); 1061: 1062: /* get the initial pointer into the responder's register buffer. we 1063: move from lower-numbered lanes (with data of lesser significance) 1064: to higher-numbered lanes (with data of more significance). we 1065: are always called with pointers to registers in host native byte 1066: order, so if the host is little-endian, we start from the given 1067: pointer, else we start from the other end of the register 1068: buffer: */ 1069: buffer_resp = (((tme_uint8_t *) resp_reg) 1070: + (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG 1071: ? (lane_count - 1) 1072: : 0)); 1073: 1074: /* loop over the lanes: */ 1075: lane = 0; 1076: cycle_size_init = 0; 1077: do { 1078: 1079: /* get the routing for this lane: */ 1080: lane_routing = *(lane_routing_init++); 1081: 1082: /* this cannot be a TME_BUS_LANE_WARN, or a TME_BUS_LANE_ABORT, or 1083: an enabled byte lane with an undefined value: */ 1084: assert (!(lane_routing & TME_BUS_LANE_WARN) 1085: && lane_routing != TME_BUS_LANE_ABORT 1086: && lane_routing != TME_BUS_LANE_UNDEF); 1087: 1088: /* if this is an enabled byte lane: */ 1089: if (__tme_predict_true(!(lane_routing & TME_BUS_LANE_ROUTE_WRITE_IGNORE))) { 1090: 1091: /* get a pointer into the initiator's buffer for this lane: */ 1092: buffer_init 1093: = (cycle_init->tme_bus_cycle_buffer 1094: + _TME_BUS_CYCLE_BUFFER_MULTIPLY(lane_routing, 1095: buffer_increment_mask_init)); 1096: 1097: /* transfer the byte: */ 1098: if (writer_init) { 1099: *buffer_resp = *buffer_init; 1100: } 1101: else { 1102: *buffer_init = *buffer_resp; 1103: } 1104: 1105: /* update the cycle size for the initiator: */ 1106: if (lane_routing >= cycle_size_init) { 1107: cycle_size_init = lane_routing + 1; 1108: } 1109: } 1110: 1111: /* update the pointer into the responder's buffer for the next lane: */ 1112: buffer_resp += (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG ? -1 : 1); 1113: 1114: } while (--lane_count > 0); 1115: 1116: /* give the initiator feedback: */ 1117: cycle_init->tme_bus_cycle_size = cycle_size_init; 1118: cycle_init->tme_bus_cycle_address += cycle_size_init; 1119: cycle_init->tme_bus_cycle_buffer += 1120: _TME_BUS_CYCLE_BUFFER_MULTIPLY(cycle_size_init, 1121: buffer_increment_mask_init); 1122: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.