|
|
1.1.1.5 root 1: /* $Id: bus-el.c,v 1.18 2009/08/29 17:59:17 fredette Exp $ */
1.1 root 2:
1.1.1.2 root 3: /* generic/bus-el.c - a real generic bus element: */
1.1 root 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-el.c,v 1.18 2009/08/29 17:59:17 fredette Exp $");
1.1 root 38:
39: /* includes: */
1.1.1.3 root 40: #define TME_BUS_VERSION TME_X_VERSION(0, 0)
1.1 root 41: #include <tme/generic/bus.h>
42: #include <stdlib.h>
43: #include <string.h>
44:
45: /* macros: */
46:
1.1.1.3 root 47: /* globals: */
48:
49: /* the generic bus signals: */
50: static const struct tme_bus_signals _tme_bus_signals_default[] = {
51: TME_BUS_SIGNALS_GENERIC
52: };
53:
1.1.1.6 ! root 54: extern int bradshow;
! 55:
1.1.1.3 root 56: /* this adds a bus signal set to the bus: */
57: static int
58: _tme_bus_signals_add(struct tme_bus_connection *conn_bus_caller,
59: struct tme_bus_signals *bus_signals)
60: {
61: struct tme_bus *bus;
62: unsigned int signal_i;
63: tme_uint32_t signals_count_new;
64: tme_uint32_t signals_count_old;
65: struct tme_bus_connection_int *conn_bus_int;
66: int rc;
67:
68: /* recover our bus: */
69: bus = conn_bus_caller->tme_bus_connection.tme_connection_element->tme_element_private;
70:
71: /* lock the bus for writing: */
72: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
73: if (TME_THREADS_ERRNO(rc) != TME_OK) {
74: return (TME_THREADS_ERRNO(rc));
75: }
76:
77: /* search for an existing bus signals set that matches the caller's: */
78: for (signal_i = 0;
79: signal_i < bus->tme_bus_signals_count;
80: signal_i++) {
81:
82: /* stop if this existing bus signals set has the right ID and the
83: versions overlap: */
84: if ((bus->tme_bus_signals[signal_i].tme_bus_signals_id
85: == bus_signals->tme_bus_signals_id)
86: && TME_X_VERSION_OK(bus->tme_bus_signals[signal_i].tme_bus_signals_version,
87: bus_signals->tme_bus_signals_version)) {
88: break;
89: }
90: }
91:
92: /* assume that this call succeeds: */
93: rc = TME_OK;
94:
95: /* if an existing bus signals set was not found: */
96: if (signal_i == bus->tme_bus_signals_count) {
97:
98: /* get the old count of bus signals from the current last bus
99: signals set in the bus signals sets array: */
100: signals_count_old =
101: (TME_BUS_SIGNAL_INDEX(bus->tme_bus_signals[bus->tme_bus_signals_count - 1].tme_bus_signals_first)
102: + bus->tme_bus_signals[bus->tme_bus_signals_count - 1].tme_bus_signals_count);
103:
104: /* resize the bus signals sets array: */
105: bus->tme_bus_signals
106: = tme_renew(struct tme_bus_signals,
107: bus->tme_bus_signals,
108: bus->tme_bus_signals_count
109: + 1);
110:
111: /* add the new bus signals set: */
112: signals_count_new = signals_count_old + bus_signals->tme_bus_signals_count;
113: assert (signals_count_new > signals_count_old);
114: bus_signals->tme_bus_signals_first = TME_BUS_SIGNAL_X(signals_count_old);
115: bus->tme_bus_signals[bus->tme_bus_signals_count] = *bus_signals;
116: bus->tme_bus_signals_count++;
117:
118: /* reallocate the bus' asserted-signals count array: */
119: bus->tme_bus_signal_asserts
120: = tme_renew(unsigned int,
121: bus->tme_bus_signal_asserts,
122: signals_count_new);
123: memset ((char *) &bus->tme_bus_signal_asserts[signals_count_old],
124: 0,
125: (sizeof(bus->tme_bus_signal_asserts[0])
126: * (signals_count_new
127: - signals_count_old)));
128:
129: /* if needed, reallocate each connection's asserted-signals
130: bitmap: */
131: if (TME_BUS_SIGNAL_BIT_BYTES(signals_count_new)
132: > TME_BUS_SIGNAL_BIT_BYTES(signals_count_old)) {
133: for (conn_bus_int = bus->tme_bus_connections;
134: conn_bus_int != NULL;
135: conn_bus_int =
136: (struct tme_bus_connection_int *)
137: conn_bus_int->tme_bus_connection_int
138: .tme_bus_connection
139: .tme_connection_next) {
140: conn_bus_int->tme_bus_connection_int_signals
141: = tme_renew(tme_uint8_t,
142: conn_bus_int->tme_bus_connection_int_signals,
143: TME_BUS_SIGNAL_BIT_BYTES(signals_count_new));
144: memset ((char *) &conn_bus_int->tme_bus_connection_int_signals[TME_BUS_SIGNAL_BIT_BYTES(signals_count_old)],
145: 0,
146: (sizeof (conn_bus_int->tme_bus_connection_int_signals[0])
147: * (TME_BUS_SIGNAL_BIT_BYTES(signals_count_new)
148: - TME_BUS_SIGNAL_BIT_BYTES(signals_count_old))));
149: }
150: }
151: }
152:
153: /* otherwise, we found an existing bus signals set. however, even
154: though the versions overlap, if they don't support the same least
155: version, something is wrong: */
156: else if ((TME_X_VERSION_CURRENT(bus->tme_bus_signals[signal_i].tme_bus_signals_version)
157: - TME_X_VERSION_AGE(bus->tme_bus_signals[signal_i].tme_bus_signals_version))
158: != (TME_X_VERSION_CURRENT(bus_signals->tme_bus_signals_version)
159: - TME_X_VERSION_AGE(bus_signals->tme_bus_signals_version))) {
160: rc = EINVAL;
161: }
162:
163: /* otherwise, we found an existing bus signals set that fully matches
164: and is compatible with the caller's: */
165: else {
166:
167: /* update the versioning on this bus signals set: */
168: if (TME_X_VERSION_CURRENT(bus_signals->tme_bus_signals_version)
169: > TME_X_VERSION_CURRENT(bus->tme_bus_signals[signal_i].tme_bus_signals_version)) {
170: bus->tme_bus_signals[signal_i].tme_bus_signals_version = bus_signals->tme_bus_signals_version;
171: }
172:
173: /* return the existing bus signals set: */
174: *bus_signals = bus->tme_bus_signals[signal_i];
175: }
176:
177: /* unlock the bus and return: */
178: tme_rwlock_unlock(&bus->tme_bus_rwlock);
179: return (rc);
180: }
1.1 root 181:
182: /* this handles a bus connection signal edge: */
183: static int
184: _tme_bus_signal(struct tme_bus_connection *conn_bus_edger, unsigned int signal)
185: {
186: struct tme_bus *bus;
187: struct tme_bus_connection_int *conn_bus_int_edger;
188: struct tme_bus_connection_int *conn_bus_int;
189: unsigned int level_edge;
190: struct tme_bus_connection *conn_bus;
191: struct tme_bus_connection *conn_bus_other;
192: int signal_asserted, need_propagate;
193: unsigned int signal_index;
194: tme_uint8_t signal_mask;
195: int rc;
196: int deadlocked;
197:
198: /* recover our bus: */
199: bus = conn_bus_edger->tme_bus_connection.tme_connection_element->tme_element_private;
200: conn_bus_int_edger = (struct tme_bus_connection_int *) conn_bus_edger;
201:
202: /* take out the level and edge: */
1.1.1.3 root 203: level_edge = signal;
204: signal = TME_BUS_SIGNAL_WHICH(signal);
205: level_edge ^= signal;
1.1 root 206:
207: /* lock the bus for writing: */
208: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
209: if (TME_THREADS_ERRNO(rc) != TME_OK) {
210: return (TME_THREADS_ERRNO(rc));
211: }
212:
213: /* if this device doesn't know its interrupt signal, fix it: */
214: if (signal == TME_BUS_SIGNAL_INT_UNSPEC) {
215: signal = conn_bus_int_edger->tme_bus_connection_int_signal_int;
216: if (signal == TME_BUS_SIGNAL_INT_UNSPEC) {
217: /* this bus connection is misconfigured: */
218: if (!conn_bus_int_edger->tme_bus_connection_int_logged_int) {
219: conn_bus_int_edger->tme_bus_connection_int_logged_int = TRUE;
220: /* XXX diagnostic */
221: abort();
222: }
223: tme_rwlock_unlock(&bus->tme_bus_rwlock);
224: return (TME_OK);
225: }
226: }
227:
228: /* assume we don't need to propagate this signal across the bus: */
229: need_propagate = FALSE;
230:
1.1.1.3 root 231: /* see whether the device is asserting or negating this signal. iff
232: one or more devices on a bus are asserting a signal, the signal
233: appears asserted on the bus. this gives an ORed effect: */
234: signal_asserted = TRUE;
235: switch (level_edge & TME_BUS_SIGNAL_LEVEL_MASK) {
236: case TME_BUS_SIGNAL_LEVEL_NEGATED:
237: signal_asserted = FALSE;
238: case TME_BUS_SIGNAL_LEVEL_ASSERTED:
239: break;
240: default:
241: abort();
1.1 root 242: }
243:
1.1.1.3 root 244: /* get the index and mask of this signal in signal byte arrays: */
245: signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal);
246: signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal);
1.1 root 247:
1.1.1.3 root 248: /* if this signal is being asserted: */
249: if (signal_asserted) {
250:
251: /* if this device wasn't already asserting this signal: */
252: if (!(conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
253: & signal_mask)) {
254:
255: /* it is now asserting this signal: */
256: conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
257: |= signal_mask;
258: bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)]++;
259:
260: /* if this is the only device asserting this signal,
261: propagate the change across the bus: */
262: if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] == 1) {
263: need_propagate = TRUE;
1.1 root 264: }
265: }
266:
1.1.1.3 root 267: /* otherwise, this device was already asserting this signal: */
1.1 root 268: else {
1.1.1.3 root 269: assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] > 0);
270: }
271: }
1.1 root 272:
1.1.1.3 root 273: /* otherwise, this signal is being negated: */
274: else {
275:
276: /* if this device was asserting this signal: */
277: if (conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
278: & signal_mask) {
1.1 root 279:
1.1.1.3 root 280: /* it is no longer asserting this signal: */
281: conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
282: &= ~signal_mask;
283: assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] > 0);
284: bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)]--;
285:
286: /* if this was the last device asserting this signal, propagate
287: the change across the bus: */
288: if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] == 0) {
289: need_propagate = TRUE;
1.1 root 290: }
1.1.1.3 root 291: }
292:
293: /* otherwise, this device was not asserting this signal, but it
294: negated it anyways. often, lazy code will only send negating
295: edges for signals (for example, see the do_reset code in
296: machine/sun2/sun2-mainbus.c, which should really assert RESET,
297: sleep, then negate it), so if we get a negated edge for a
298: signal that no one else (including the edger) was asserting, we
299: propagate the edge anyways.
300:
301: so, TME_BUS_SIGNAL_EDGE should only be used for this purpose: */
302: else if ((level_edge & TME_BUS_SIGNAL_EDGE)
303: && bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_INDEX(signal)] == 0) {
1.1 root 304: need_propagate = TRUE;
305: }
306: }
307:
308: /* if we're propagating this signal across the bus: */
309: rc = TME_OK;
310: if (need_propagate) {
311:
312: /* put the level and edge back in: */
313: signal |= level_edge;
314:
315: /* assume that we won't deadlock: */
316: deadlocked = FALSE;
317:
318: /* propagate the signal to each connection to the bus: */
319: for (conn_bus_int = bus->tme_bus_connections;
320: conn_bus_int != NULL;
321: conn_bus_int =
322: (struct tme_bus_connection_int *)
323: conn_bus_int->tme_bus_connection_int
324: .tme_bus_connection
325: .tme_connection_next) {
326: conn_bus = &conn_bus_int->tme_bus_connection_int;
327: conn_bus_other =
328: (struct tme_bus_connection *)
329: conn_bus->tme_bus_connection.tme_connection_other;
330:
331: /* skip this device if it edged the line to begin with: */
332: if (conn_bus == conn_bus_edger) {
333: continue;
334: }
335:
336: /* skip this device if it doesn't care about bus signals: */
337: if (conn_bus_other->tme_bus_signal == NULL) {
338: continue;
339: }
340:
341: /* give the edge to this connection: */
342: rc = (*conn_bus_other->tme_bus_signal)(conn_bus_other, signal);
343:
344: /* if we deadlocked, remember to tell the caller: */
345: if (rc == TME_EDEADLK) {
346: deadlocked = TRUE;
347: }
348: }
349: rc = (deadlocked ? TME_EDEADLK : TME_OK);
350: }
351:
352: /* unlock the bus: */
353: tme_rwlock_unlock(&bus->tme_bus_rwlock);
354:
355: /* done: */
356: return (rc);
357: }
358:
359: /* this handles a bus interrupt acknowledge: */
360: static int
361: _tme_bus_intack(struct tme_bus_connection *conn_bus_acker, unsigned int signal, int *vector)
362: {
363: struct tme_bus *bus;
364: struct tme_bus_connection_int *conn_bus_int;
365: struct tme_bus_connection *conn_bus;
366: struct tme_bus_connection *conn_bus_other;
367: unsigned int signal_index;
368: tme_uint8_t signal_mask;
369: int rc;
370:
371: /* recover our bus: */
372: bus = conn_bus_acker->tme_bus_connection.tme_connection_element->tme_element_private;
373:
374: /* get rid of any level and edge: */
1.1.1.3 root 375: signal = TME_BUS_SIGNAL_WHICH(signal);
1.1 root 376:
377: /* this must be an interrupt signal: */
378: assert(TME_BUS_SIGNAL_IS_INT(signal));
379:
380: /* lock the bus for writing: */
381: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
382: if (TME_THREADS_ERRNO(rc) != TME_OK) {
383: return (TME_THREADS_ERRNO(rc));
384: }
385:
386: /* get the index and mask of this signal in signal byte arrays: */
387: signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal);
388: signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal);
389:
390: /* find the first connection to the bus that is asserting this
391: interrupt signal. if no connection is asserting the signal,
392: return ENOENT: */
393: rc = ENOENT;
394: for (conn_bus_int = bus->tme_bus_connections;
395: conn_bus_int != NULL;
396: conn_bus_int =
397: (struct tme_bus_connection_int *)
398: conn_bus_int->tme_bus_connection_int
399: .tme_bus_connection
400: .tme_connection_next) {
401: conn_bus = &conn_bus_int->tme_bus_connection_int;
402: conn_bus_other =
403: (struct tme_bus_connection *)
404: conn_bus->tme_bus_connection.tme_connection_other;
405:
406: /* if this device is asserting this interrupt signal: */
407: if (conn_bus_int->tme_bus_connection_int_signals[signal_index]
408: & signal_mask) {
409:
1.1.1.4 root 410: /* unlock the bus: */
411: tme_rwlock_unlock(&bus->tme_bus_rwlock);
412:
1.1.1.3 root 413: /* if this device doesn't acknowledge interrupts, return any
414: user-specified vector or TME_BUS_INTERRUPT_VECTOR_UNDEF: */
1.1 root 415: if (conn_bus_other->tme_bus_intack == NULL) {
1.1.1.3 root 416: *vector = conn_bus_int->tme_bus_connection_int_vector_int;
1.1 root 417: rc = TME_OK;
418: }
419:
420: /* otherwise, run the interrupt acknowledge with this connection: */
421: else {
422: rc = (*conn_bus_other->tme_bus_intack)(conn_bus_other, signal, vector);
423: }
424:
1.1.1.4 root 425: /* done: */
426: return (rc);
1.1 root 427: }
428: }
429:
430: /* unlock the bus: */
431: tme_rwlock_unlock(&bus->tme_bus_rwlock);
432:
433: /* done: */
434: return (rc);
435: }
436:
437: static int
438: _tme_bus_fault(void *junk0, struct tme_bus_cycle *junk1)
439: {
1.1.1.6 ! root 440: #if 0
! 441: {
! 442: extern int printf(const char *format, ...);
! 443: printf("_tme_bus_fault()\n");
! 444: }
! 445: #endif
1.1 root 446: return (ENOENT);
447: }
448:
449: /* this fills a TLB entry: */
450: static int
451: _tme_bus_tlb_fill(struct tme_bus_connection *conn_bus_asker,
452: struct tme_bus_tlb *tlb,
453: tme_bus_addr_t address,
454: unsigned int cycles)
455: {
456: struct tme_bus *bus;
457: struct tme_bus_connection_int *conn_int;
458: int rc;
459:
1.1.1.6 ! root 460: #if 0
! 461: if (bradshow)
! 462: {
! 463: extern int printf(const char *format, ...);
! 464: printf("_tme_bus_tlb_fill() address %x\n", (int)address);
! 465: }
! 466: #endif
! 467:
1.1 root 468: /* recover our bus and our connection to the asker: */
469: bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
470: conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
471:
472: /* put our fault handler in the TLB entry: */
473: tlb->tme_bus_tlb_cycle_private = NULL;
474: tlb->tme_bus_tlb_cycle = _tme_bus_fault;
475:
476: /* lock the bus for reading: */
477: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
478: if (TME_THREADS_ERRNO(rc) != TME_OK) {
479: return (TME_THREADS_ERRNO(rc));
480: }
481:
482: /* call the generic bus support function: */
483: rc = tme_bus_tlb_fill(bus,
484: conn_int,
485: tlb, address, cycles);
486:
1.1.1.6 ! root 487: #if 0
! 488: if (bradshow)
! 489: {
! 490: extern int printf(const char *format, ...);
! 491: printf("_tme_bus_tlb_fill() rc = %d\n", rc);
! 492: }
! 493: #endif
! 494:
! 495:
1.1 root 496: /* unlock the bus: */
497: tme_rwlock_unlock(&bus->tme_bus_rwlock);
498:
499: /* done: */
500: return (rc);
501: }
502:
1.1.1.5 root 503: /* this adds a new TLB set: */
1.1 root 504: static int
1.1.1.5 root 505: _tme_bus_tlb_set_add(struct tme_bus_connection *conn_bus_asker,
506: struct tme_bus_tlb_set_info *tlb_set_info)
1.1 root 507: {
508: struct tme_bus *bus;
509: struct tme_bus_connection_int *conn_int;
510: int rc;
511:
512: /* recover our bus and our connection to the asker: */
513: bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
514: conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
515:
516: /* lock the bus for reading: */
517: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
518: if (TME_THREADS_ERRNO(rc) != TME_OK) {
519: return (TME_THREADS_ERRNO(rc));
520: }
521:
522: /* call the generic bus support function: */
1.1.1.5 root 523: rc = tme_bus_tlb_set_add(bus,
524: conn_int,
525: tlb_set_info);
1.1 root 526:
527: /* unlock the bus: */
528: tme_rwlock_unlock(&bus->tme_bus_rwlock);
529:
530: /* done: */
531: return (rc);
532: }
533:
534: /* this scores a new connection: */
535: static int
536: _tme_bus_connection_score(struct tme_connection *conn, unsigned int *_score)
537: {
538: struct tme_bus *bus;
539: struct tme_bus_connection_int *conn_int;
540: int rc, ok;
541:
542: /* both sides must be generic bus connections: */
543: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
544: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
545:
546: /* recover our bus and our internal connection side: */
547: bus = conn->tme_connection_element->tme_element_private;
548: conn_int = (struct tme_bus_connection_int *) conn;
549:
550: /* lock the bus for reading: */
551: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
552: if (TME_THREADS_ERRNO(rc) != TME_OK) {
553: return (TME_THREADS_ERRNO(rc));
554: }
555:
556: /* call the generic bus support function: */
557: ok = tme_bus_connection_ok(bus,
558: conn_int);
559:
560: /* unlock the bus: */
561: tme_rwlock_unlock(&bus->tme_bus_rwlock);
562:
563: /* return the score: */
564: *_score = (ok ? 1 : 0);
565: return (TME_OK);
566: }
567:
568: /* this makes a new connection: */
569: static int
570: _tme_bus_connection_make(struct tme_connection *conn, unsigned int state)
571: {
572: struct tme_bus *bus;
573: struct tme_bus_connection_int *conn_int;
1.1.1.3 root 574: const struct tme_bus_signals *bus_signals;
1.1 root 575: int rc;
576:
577: /* both sides must be generic bus connections: */
578: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
579: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
580:
581: /* recover our bus and our internal connection side: */
582: bus = conn->tme_connection_element->tme_element_private;
583: conn_int = (struct tme_bus_connection_int *) conn;
584:
585: /* lock the bus for writing: */
586: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
587: if (TME_THREADS_ERRNO(rc) != TME_OK) {
588: return (TME_THREADS_ERRNO(rc));
589: }
590:
591: /* call the generic bus support function: */
592: rc = tme_bus_connection_make(bus,
593: conn_int,
594: state);
595:
1.1.1.3 root 596: /* XXX this is a perfect example of the poor division between
597: bus-el.c and bus.c. should the signal handling code be in bus.c? */
598: if (rc == TME_OK) {
599: bus_signals = &bus->tme_bus_signals[bus->tme_bus_signals_count - 1];
600: conn_int->tme_bus_connection_int_signals
601: = tme_new0(tme_uint8_t,
602: TME_BUS_SIGNAL_BIT_BYTES(TME_BUS_SIGNAL_INDEX(bus_signals->tme_bus_signals_first)
603: + bus_signals->tme_bus_signals_count));
604: }
605:
1.1 root 606: /* unlock the bus: */
607: tme_rwlock_unlock(&bus->tme_bus_rwlock);
608:
609: return (rc);
610: }
611:
612: /* this breaks a connection: */
613: static int
614: _tme_bus_connection_break(struct tme_connection *conn, unsigned int state)
615: {
616: abort();
617: }
618:
619: /* this returns the new connections possible: */
620: static int
621: _tme_bus_connections_new(struct tme_element *element,
622: const char * const *args,
623: struct tme_connection **_conns,
624: char **_output)
625: {
626: const struct tme_bus *bus;
627: struct tme_bus_connection_int *conn_int;
628: struct tme_bus_connection *conn_bus;
629: struct tme_connection *conn;
630: int ipl;
1.1.1.3 root 631: int vector;
1.1.1.4 root 632: const struct tme_bus_slot *bus_slot;
1.1 root 633: int arg_i;
634: int usage;
635:
636: /* recover our bus. we only read the address mask, so we don't lock
637: the rwlock: */
638: bus = element->tme_element_private;
639:
640: /* allocate the new connection side: */
641: conn_int = tme_new0(struct tme_bus_connection_int, 1);
642: conn_bus = &conn_int->tme_bus_connection_int;
643: conn = &conn_bus->tme_bus_connection;
644:
645: /* loop reading our arguments: */
646: usage = FALSE;
647: arg_i = 1;
1.1.1.3 root 648: conn_int->tme_bus_connection_int_vector_int = TME_BUS_INTERRUPT_VECTOR_UNDEF;
1.1.1.4 root 649: bus_slot = NULL;
1.1 root 650: for (;;) {
651:
652: /* the address of this connection: */
653: if (TME_ARG_IS(args[arg_i + 0], "addr")) {
1.1.1.4 root 654: conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE;
1.1 root 655: conn_int->tme_bus_connection_int_address = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
656: if (usage
657: || (conn_int->tme_bus_connection_int_address
658: > bus->tme_bus_address_mask)) {
659: usage = TRUE;
660: break;
661: }
662: arg_i += 2;
663: }
664:
665: /* the interrupt signal for this connection: */
666: else if (TME_ARG_IS(args[arg_i + 0], "ipl")
667: && args[arg_i + 1] != NULL
668: && (ipl = atoi(args[arg_i + 1])) > 0) {
669: conn_int->tme_bus_connection_int_signal_int = TME_BUS_SIGNAL_INT(ipl);
670: arg_i += 2;
671: }
672:
1.1.1.3 root 673: /* the interrupt vector for this connection: */
674: else if (TME_ARG_IS(args[arg_i + 0], "vector")
675: && args[arg_i + 1] != NULL
676: && (vector = atoi(args[arg_i + 1])) > 0) {
677: conn_int->tme_bus_connection_int_vector_int = vector;
678: arg_i += 2;
679: }
680:
1.1.1.4 root 681: /* the slot for this connection: */
682: else if (TME_ARG_IS(args[arg_i + 0], "slot")
683: && args[arg_i + 1] != NULL) {
684:
685: /* you can't give more than one slot for a connection: */
686: if (bus_slot != NULL) {
687: tme_output_append_error(_output,
688: "slot %s %s, ",
689: args[arg_i + 1],
690: _("redefined"));
691: usage = TRUE;
692: break;
693: }
694:
695: /* make sure this slot has been defined: */
696: for (bus_slot = bus->tme_bus_slots;
697: bus_slot != NULL;
698: bus_slot = bus_slot->tme_bus_slot_next) {
699: if (strcmp(bus_slot->tme_bus_slot_name,
700: args[arg_i + 1]) == 0) {
701: break;
702: }
703: }
704: if (bus_slot == NULL) {
705: tme_output_append_error(_output,
706: "slot %s %s, ",
707: args[arg_i + 1],
708: _("unknown"));
709: usage = TRUE;
710: break;
711: }
712: arg_i += 2;
713: }
714:
715: /* the slot offset for this connection: */
716: else if (TME_ARG_IS(args[arg_i + 0], "offset")) {
717: if (bus_slot == NULL) {
718: tme_output_append_error(_output,
719: "slot %s, ",
720: _("unknown"));
721: usage = TRUE;
722: break;
723: }
724: conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_ADDRESSABLE;
725: conn_int->tme_bus_connection_int_address
726: = (bus_slot->tme_bus_slot_address
727: + tme_bus_addr_parse_any(args[arg_i + 1], &usage));
728: if (usage
729: || (conn_int->tme_bus_connection_int_address
730: > bus->tme_bus_address_mask)) {
731: usage = TRUE;
732: break;
733: }
734: arg_i += 2;
735: }
736:
737: /* if this connection is for a slot controller: */
738: else if (TME_ARG_IS(args[arg_i + 0], "controller")) {
739: if (bus->tme_bus_controller != NULL) {
740: tme_free(conn_int);
741: return (EEXIST);
742: }
743: conn_int->tme_bus_connection_int_flags |= TME_BUS_CONNECTION_INT_FLAG_CONTROLLER;
744: arg_i++;
745: }
746:
747: /* if this connection has an automatic DMA offset: */
748: else if (TME_ARG_IS(args[arg_i + 0], "dma-offset")) {
749: conn_int->tme_bus_connection_int_sourced = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
750: if (usage
751: || (conn_int->tme_bus_connection_int_sourced
752: > bus->tme_bus_address_mask)) {
753: usage = TRUE;
754: break;
755: }
756: arg_i += 2;
757: }
758:
1.1 root 759: /* if we've run out of arguments: */
760: else if (args[arg_i + 0] == NULL) {
761: break;
762: }
763:
764: /* this is a bad argument: */
765: else {
766: tme_output_append_error(_output,
767: "%s %s, ",
768: args[arg_i],
769: _("unexpected"));
770: usage = TRUE;
771: break;
772: }
773: }
774:
775: if (usage) {
776: tme_output_append_error(_output,
1.1.1.4 root 777: "%s %s [ controller ] [ addr %s ] [ slot %s offset %s ] [ dma-offset %s ] [ ipl %s ] [ vector %s ]",
1.1 root 778: _("usage:"),
779: args[0],
780: _("BUS-ADDRESS"),
1.1.1.4 root 781: _("SLOT"),
782: _("OFFSET"),
783: _("OFFSET"),
1.1.1.3 root 784: _("INTERRUPT-LEVEL"),
785: _("INTERRUPT-VECTOR"));
1.1 root 786: tme_free(conn_int);
787: return (EINVAL);
788: }
789:
790: /* fill in the bus connection: */
1.1.1.2 root 791: conn_bus->tme_bus_subregions.tme_bus_subregion_address_first
792: = 0;
793: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last
794: = bus->tme_bus_address_mask;
795: conn_bus->tme_bus_subregions.tme_bus_subregion_next
796: = NULL;
1.1.1.3 root 797: conn_bus->tme_bus_signals_add = _tme_bus_signals_add;
1.1 root 798: conn_bus->tme_bus_signal = _tme_bus_signal;
799: conn_bus->tme_bus_intack = _tme_bus_intack;
1.1.1.5 root 800: conn_bus->tme_bus_tlb_set_add = _tme_bus_tlb_set_add;
1.1 root 801: conn_bus->tme_bus_tlb_fill = _tme_bus_tlb_fill;
802:
803: /* fill in the generic connection: */
804: conn->tme_connection_next = *_conns;
805: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
806: conn->tme_connection_score = _tme_bus_connection_score;
807: conn->tme_connection_make = _tme_bus_connection_make;
808: conn->tme_connection_break = _tme_bus_connection_break;
809:
810: /* return the new connection side: */
811: *_conns = conn;
812: return (TME_OK);
813: }
814:
815: /* this creates a new bus element: */
816: TME_ELEMENT_SUB_NEW_DECL(tme_generic,bus) {
817: struct tme_bus *bus;
1.1.1.4 root 818: tme_bus_addr_t bus_size_mask;
819: tme_bus_addr_t bus_slot_size;
820: tme_bus_addr_t bus_slot_addr;
821: int bus_slot_addr_defined;
822: struct tme_bus_slot *bus_slot;
823: struct tme_bus_slot *bus_slots;
824: int arg_i;
1.1 root 825: int failed;
826:
827: /* our arguments must include the bus size, and the
828: bus size must be a power of two: */
1.1.1.4 root 829: failed = FALSE;
830: arg_i = 1;
831: bus_size_mask = 0;
832: bus_slot_size = 0;
833: bus_slot_addr_defined = FALSE;
834: bus_slot_addr = 0;
835: bus_slots = NULL;
836: for (; !failed; ) {
837:
838: /* the bus size: */
839: if (TME_ARG_IS(args[arg_i + 0], "size")) {
840: /* XXX FIXME - this is a hack: */
841: if (sizeof(bus_size_mask) == sizeof(tme_uint32_t) &&
842: TME_ARG_IS(args[arg_i + 1], "4GB")) {
843: bus_size_mask = ((tme_bus_addr_t) 0) - 1;
844: }
845: else {
846: bus_size_mask = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
847: if (!failed
848: && bus_size_mask < 2) {
849: failed = TRUE;
850: }
851: else {
852: bus_size_mask -= 1;
853: }
854: }
855: if (bus_size_mask & (bus_size_mask + 1)) {
856: failed = TRUE;
857: }
858: arg_i += 2;
1.1.1.3 root 859: }
1.1.1.4 root 860:
861: /* the address for the next slots: */
862: else if (TME_ARG_IS(args[arg_i + 0], "slot-addr")) {
863: bus_slot_addr = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
864: bus_slot_addr_defined = TRUE;
865: arg_i += 2;
866: }
867:
868: /* the size for the next slots: */
869: else if (TME_ARG_IS(args[arg_i + 0], "slot-size")) {
870: bus_slot_size = tme_bus_addr_parse_any(args[arg_i + 1], &failed);
871: if (bus_slot_size < 1) {
872: failed = TRUE;
873: }
874: arg_i += 2;
1.1.1.3 root 875: }
1.1.1.4 root 876:
877: /* a slot definition: */
878: else if (TME_ARG_IS(args[arg_i + 0], "slot")) {
879: if (args[arg_i + 1] == NULL) {
880: failed = TRUE;
881: break;
882: }
883: if (!bus_slot_addr_defined) {
884: failed = TRUE;
885: break;
886: }
887: if (bus_slot_size == 0) {
888: failed = TRUE;
889: break;
890: }
891:
892: /* make sure this slot hasn't already been defined: */
893: for (bus_slot = bus_slots;
894: bus_slot != NULL;
895: bus_slot = bus_slot->tme_bus_slot_next) {
896: if (strcmp(bus_slot->tme_bus_slot_name,
897: args[arg_i + 1]) == 0) {
898: tme_output_append_error(_output,
899: "slot %s %s",
900: args[arg_i + 1],
901: _("redefined"));
902: failed = TRUE;
903: break;
904: }
905: }
906: if (failed) {
907: break;
908: }
909:
910: /* add this slot: */
911: bus_slot = tme_new0(struct tme_bus_slot, 1);
912: bus_slot->tme_bus_slot_next = bus_slots;
913: bus_slots = bus_slot;
914: bus_slot->tme_bus_slot_name = tme_strdup(args[arg_i + 1]);
915: bus_slot->tme_bus_slot_address = bus_slot_addr;
916: bus_slot->tme_bus_slot_size = bus_slot_size;
917:
918: /* advance for the next slot: */
919: bus_slot_addr += bus_slot_size;
920: arg_i += 2;
921: }
922:
923: /* if we've run out of arguments: */
924: else if (args[arg_i + 0] == NULL) {
925: break;
926: }
927:
928: /* an unknown argument: */
929: else {
930: tme_output_append_error(_output,
931: "%s %s, ",
932: args[arg_i],
933: _("unexpected"));
1.1 root 934: failed = TRUE;
935: }
936: }
937: if (failed) {
938: tme_output_append_error(_output,
1.1.1.4 root 939: "%s %s size %s [ slot-addr %s slot-size %s slot %s0 .. slot %sN ]",
1.1 root 940: _("usage:"),
941: args[0],
1.1.1.4 root 942: _("SIZE"),
943: _("ADDRESS"),
944: _("SIZE"),
945: _("SLOT-NAME"),
946: _("SLOT-NAME"));
947: for (; (bus_slot = bus_slots) != NULL; ) {
948: bus_slots = bus_slots->tme_bus_slot_next;
949: tme_free(bus_slot->tme_bus_slot_name);
950: tme_free(bus_slot);
951: }
1.1 root 952: return (EINVAL);
953: }
954:
955: /* allocate and initialize the new bus: */
956: bus = tme_new0(struct tme_bus, 1);
957: tme_rwlock_init(&bus->tme_bus_rwlock);
1.1.1.4 root 958: bus->tme_bus_address_mask = bus_size_mask;
1.1 root 959: bus->tme_bus_addressables_count = 0;
960: bus->tme_bus_addressables_size = 1;
1.1.1.2 root 961: bus->tme_bus_addressables = tme_new(struct tme_bus_addressable,
1.1 root 962: bus->tme_bus_addressables_size);
1.1.1.3 root 963: bus->tme_bus_signals_count = TME_ARRAY_ELS(_tme_bus_signals_default);
964: bus->tme_bus_signals = tme_dup(struct tme_bus_signals,
965: _tme_bus_signals_default,
966: TME_ARRAY_ELS(_tme_bus_signals_default));
967: bus->tme_bus_signal_asserts = tme_new0(unsigned int,
968: _tme_bus_signals_default[0].tme_bus_signals_count);
1.1.1.4 root 969: bus->tme_bus_slots = bus_slots;
1.1 root 970:
971: /* fill the element: */
972: element->tme_element_private = bus;
973: element->tme_element_connections_new = _tme_bus_connections_new;
974:
975: return (TME_OK);
976: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.