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