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