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