|
|
1.1 root 1: /* $Id: bus-el.c,v 1.7 2003/05/16 21:48:08 fredette Exp $ */
2:
3: /* generic/gen-bus-el.c - a real generic bus element: */
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>
37: _TME_RCSID("$Id: bus-el.c,v 1.7 2003/05/16 21:48:08 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/bus.h>
41: #include <stdlib.h>
42: #include <string.h>
43:
44: /* macros: */
45:
46: /* structures: */
47:
48: /* this handles a bus connection signal edge: */
49: static int
50: _tme_bus_signal(struct tme_bus_connection *conn_bus_edger, unsigned int signal)
51: {
52: struct tme_bus *bus;
53: struct tme_bus_connection_int *conn_bus_int_edger;
54: struct tme_bus_connection_int *conn_bus_int;
55: unsigned int level_edge;
56: struct tme_bus_connection *conn_bus;
57: struct tme_bus_connection *conn_bus_other;
58: int signal_asserted, need_propagate;
59: unsigned int signal_index;
60: tme_uint8_t signal_mask;
61: int rc;
62: int deadlocked;
63:
64: /* recover our bus: */
65: bus = conn_bus_edger->tme_bus_connection.tme_connection_element->tme_element_private;
66: conn_bus_int_edger = (struct tme_bus_connection_int *) conn_bus_edger;
67:
68: /* take out the level and edge: */
69: level_edge = signal & (TME_BUS_SIGNAL_LEVEL_MASK
70: | TME_BUS_SIGNAL_EDGE);
71: signal &= ~(TME_BUS_SIGNAL_LEVEL_MASK
72: | TME_BUS_SIGNAL_EDGE);
73:
74: /* lock the bus for writing: */
75: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
76: if (TME_THREADS_ERRNO(rc) != TME_OK) {
77: return (TME_THREADS_ERRNO(rc));
78: }
79:
80: /* if this device doesn't know its interrupt signal, fix it: */
81: if (signal == TME_BUS_SIGNAL_INT_UNSPEC) {
82: signal = conn_bus_int_edger->tme_bus_connection_int_signal_int;
83: if (signal == TME_BUS_SIGNAL_INT_UNSPEC) {
84: /* this bus connection is misconfigured: */
85: if (!conn_bus_int_edger->tme_bus_connection_int_logged_int) {
86: conn_bus_int_edger->tme_bus_connection_int_logged_int = TRUE;
87: /* XXX diagnostic */
88: abort();
89: }
90: tme_rwlock_unlock(&bus->tme_bus_rwlock);
91: return (TME_OK);
92: }
93: }
94:
95: /* assume we don't need to propagate this signal across the bus: */
96: need_propagate = FALSE;
97:
98: /* if this is a random bus-specific signal, just propagate it: */
99: if (TME_BUS_SIGNAL_IS_X(signal)) {
100: need_propagate = TRUE;
101: }
102:
103: /* otherwise, this is a generic bus signal: */
104: else {
105:
106: /* decide whether the device is asserting or negating this signal: */
107: /* XXX we currently assume that for all bus signals handled by this
108: function, low implies assertion, and signals are always ORed
109: together. this could be configurable, possibly even per-signal: */
110: signal_asserted = TRUE;
111: switch (level_edge & TME_BUS_SIGNAL_LEVEL_MASK) {
112: case TME_BUS_SIGNAL_LEVEL_LOW:
113: case TME_BUS_SIGNAL_LEVEL_ASSERTED:
114: break;
115: case TME_BUS_SIGNAL_LEVEL_HIGH:
116: case TME_BUS_SIGNAL_LEVEL_NEGATED:
117: signal_asserted = FALSE;
118: break;
119: }
120: level_edge = ((level_edge & TME_BUS_SIGNAL_EDGE)
121: | (signal_asserted
122: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
123: : TME_BUS_SIGNAL_LEVEL_NEGATED));
124:
125: /* get the index and mask of this signal in signal byte arrays: */
126: signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal);
127: signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal);
128:
129: /* if this signal is being asserted: */
130: if (signal_asserted) {
131:
132: /* if this device wasn't already asserting this signal: */
133: if (!(conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
134: & signal_mask)) {
135:
136: /* it is now asserting this signal: */
137: conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
138: |= signal_mask;
139: bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)]++;
140:
141: /* if this is the only device asserting this signal,
142: propagate the change across the bus: */
143: if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] == 1) {
144: need_propagate = TRUE;
145: }
146: }
147:
148: /* otherwise, this device was already asserting this signal: */
149: else {
150: assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] > 0);
151: }
152: }
153:
154: /* otherwise, this signal is being negated: */
155: else {
156:
157: /* if this device was asserting this signal: */
158: if (conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
159: & signal_mask) {
160:
161: /* it is no longer asserting this signal: */
162: conn_bus_int_edger->tme_bus_connection_int_signals[signal_index]
163: &= ~signal_mask;
164: assert(bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] > 0);
165: bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)]--;
166: }
167:
168: /* we always propagate across the bus a signal that some device
169: has negated, because often code will lazily only send
170: negating edges, or other devices might still be asserting it,
171: we assume these signals are always ORed together, and it
172: kicks (even though this signal isn't edging) emulated
173: circuitry that is meant to do things like interrupt
174: arbitration, etc.: */
175: if (bus->tme_bus_signal_asserts[TME_BUS_SIGNAL_WHICH(signal)] > 0) {
176: level_edge = TME_BUS_SIGNAL_LEVEL_ASSERTED;
177: }
178: need_propagate = TRUE;
179: }
180: }
181:
182: /* if we're propagating this signal across the bus: */
183: rc = TME_OK;
184: if (need_propagate) {
185:
186: /* put the level and edge back in: */
187: signal |= level_edge;
188:
189: /* assume that we won't deadlock: */
190: deadlocked = FALSE;
191:
192: /* propagate the signal to each connection to the bus: */
193: for (conn_bus_int = bus->tme_bus_connections;
194: conn_bus_int != NULL;
195: conn_bus_int =
196: (struct tme_bus_connection_int *)
197: conn_bus_int->tme_bus_connection_int
198: .tme_bus_connection
199: .tme_connection_next) {
200: conn_bus = &conn_bus_int->tme_bus_connection_int;
201: conn_bus_other =
202: (struct tme_bus_connection *)
203: conn_bus->tme_bus_connection.tme_connection_other;
204:
205: /* skip this device if it edged the line to begin with: */
206: if (conn_bus == conn_bus_edger) {
207: continue;
208: }
209:
210: /* skip this device if it doesn't care about bus signals: */
211: if (conn_bus_other->tme_bus_signal == NULL) {
212: continue;
213: }
214:
215: /* give the edge to this connection: */
216: rc = (*conn_bus_other->tme_bus_signal)(conn_bus_other, signal);
217:
218: /* if we deadlocked, remember to tell the caller: */
219: if (rc == TME_EDEADLK) {
220: deadlocked = TRUE;
221: }
222: }
223: rc = (deadlocked ? TME_EDEADLK : TME_OK);
224: }
225:
226: /* unlock the bus: */
227: tme_rwlock_unlock(&bus->tme_bus_rwlock);
228:
229: /* done: */
230: return (rc);
231: }
232:
233: /* this handles a bus interrupt acknowledge: */
234: static int
235: _tme_bus_intack(struct tme_bus_connection *conn_bus_acker, unsigned int signal, int *vector)
236: {
237: struct tme_bus *bus;
238: struct tme_bus_connection_int *conn_bus_int;
239: struct tme_bus_connection *conn_bus;
240: struct tme_bus_connection *conn_bus_other;
241: unsigned int signal_index;
242: tme_uint8_t signal_mask;
243: int rc;
244:
245: /* recover our bus: */
246: bus = conn_bus_acker->tme_bus_connection.tme_connection_element->tme_element_private;
247:
248: /* get rid of any level and edge: */
249: signal &= ~(TME_BUS_SIGNAL_LEVEL_MASK
250: | TME_BUS_SIGNAL_EDGE);
251:
252: /* this must be an interrupt signal: */
253: assert(TME_BUS_SIGNAL_IS_INT(signal));
254:
255: /* lock the bus for writing: */
256: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
257: if (TME_THREADS_ERRNO(rc) != TME_OK) {
258: return (TME_THREADS_ERRNO(rc));
259: }
260:
261: /* get the index and mask of this signal in signal byte arrays: */
262: signal_index = TME_BUS_SIGNAL_BIT_INDEX(signal);
263: signal_mask = TME_BUS_SIGNAL_BIT_MASK(signal);
264:
265: /* find the first connection to the bus that is asserting this
266: interrupt signal. if no connection is asserting the signal,
267: return ENOENT: */
268: rc = ENOENT;
269: for (conn_bus_int = bus->tme_bus_connections;
270: conn_bus_int != NULL;
271: conn_bus_int =
272: (struct tme_bus_connection_int *)
273: conn_bus_int->tme_bus_connection_int
274: .tme_bus_connection
275: .tme_connection_next) {
276: conn_bus = &conn_bus_int->tme_bus_connection_int;
277: conn_bus_other =
278: (struct tme_bus_connection *)
279: conn_bus->tme_bus_connection.tme_connection_other;
280:
281: /* if this device is asserting this interrupt signal: */
282: if (conn_bus_int->tme_bus_connection_int_signals[signal_index]
283: & signal_mask) {
284:
285: /* if this device doesn't acknowledge interrupts,
286: return an undefined vector: */
287: if (conn_bus_other->tme_bus_intack == NULL) {
288: *vector = TME_BUS_INTERRUPT_VECTOR_UNDEF;
289: rc = TME_OK;
290: }
291:
292: /* otherwise, run the interrupt acknowledge with this connection: */
293: else {
294: rc = (*conn_bus_other->tme_bus_intack)(conn_bus_other, signal, vector);
295: }
296:
297: /* stop: */
298: break;
299: }
300: }
301:
302: /* unlock the bus: */
303: tme_rwlock_unlock(&bus->tme_bus_rwlock);
304:
305: /* done: */
306: return (rc);
307: }
308:
309: static int
310: _tme_bus_fault(void *junk0, struct tme_bus_cycle *junk1)
311: {
312: return (ENOENT);
313: }
314:
315: /* this fills a TLB entry: */
316: static int
317: _tme_bus_tlb_fill(struct tme_bus_connection *conn_bus_asker,
318: struct tme_bus_tlb *tlb,
319: tme_bus_addr_t address,
320: unsigned int cycles)
321: {
322: struct tme_bus *bus;
323: struct tme_bus_connection_int *conn_int;
324: int rc;
325:
326: /* recover our bus and our connection to the asker: */
327: bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
328: conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
329:
330: /* put our fault handler in the TLB entry: */
331: tlb->tme_bus_tlb_cycle_private = NULL;
332: tlb->tme_bus_tlb_cycle = _tme_bus_fault;
333:
334: /* lock the bus for reading: */
335: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
336: if (TME_THREADS_ERRNO(rc) != TME_OK) {
337: return (TME_THREADS_ERRNO(rc));
338: }
339:
340: /* call the generic bus support function: */
341: rc = tme_bus_tlb_fill(bus,
342: conn_int,
343: tlb, address, cycles);
344:
345: /* unlock the bus: */
346: tme_rwlock_unlock(&bus->tme_bus_rwlock);
347:
348: /* done: */
349: return (rc);
350: }
351:
352: /* this allocates a new TLB set: */
353: static int
354: _tme_bus_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
355: unsigned int count, unsigned int sizeof_one,
356: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb **) _tlbs)
357: {
358: struct tme_bus *bus;
359: struct tme_bus_connection_int *conn_int;
360: int rc;
361:
362: /* recover our bus and our connection to the asker: */
363: bus = conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
364: conn_int = (struct tme_bus_connection_int *) conn_bus_asker;
365:
366: /* lock the bus for reading: */
367: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
368: if (TME_THREADS_ERRNO(rc) != TME_OK) {
369: return (TME_THREADS_ERRNO(rc));
370: }
371:
372: /* call the generic bus support function: */
373: rc = tme_bus_tlb_set_allocate(bus,
374: conn_int,
375: count, sizeof_one,
376: _tlbs);
377:
378: /* unlock the bus: */
379: tme_rwlock_unlock(&bus->tme_bus_rwlock);
380:
381: /* done: */
382: return (rc);
383: }
384:
385: /* this scores a new connection: */
386: static int
387: _tme_bus_connection_score(struct tme_connection *conn, unsigned int *_score)
388: {
389: struct tme_bus *bus;
390: struct tme_bus_connection_int *conn_int;
391: int rc, ok;
392:
393: /* both sides must be generic bus connections: */
394: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
395: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
396:
397: /* recover our bus and our internal connection side: */
398: bus = conn->tme_connection_element->tme_element_private;
399: conn_int = (struct tme_bus_connection_int *) conn;
400:
401: /* get the address mask from the other side: */
402: conn_int->tme_bus_connection_int_address_last =
403: ((struct tme_bus_connection *) conn->tme_connection_other)->tme_bus_address_last;
404:
405: /* lock the bus for reading: */
406: rc = tme_rwlock_timedrdlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
407: if (TME_THREADS_ERRNO(rc) != TME_OK) {
408: return (TME_THREADS_ERRNO(rc));
409: }
410:
411: /* call the generic bus support function: */
412: ok = tme_bus_connection_ok(bus,
413: conn_int);
414:
415: /* unlock the bus: */
416: tme_rwlock_unlock(&bus->tme_bus_rwlock);
417:
418: /* return the score: */
419: *_score = (ok ? 1 : 0);
420: return (TME_OK);
421: }
422:
423: /* this makes a new connection: */
424: static int
425: _tme_bus_connection_make(struct tme_connection *conn, unsigned int state)
426: {
427: struct tme_bus *bus;
428: struct tme_bus_connection_int *conn_int;
429: int rc;
430:
431: /* both sides must be generic bus connections: */
432: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
433: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
434:
435: /* recover our bus and our internal connection side: */
436: bus = conn->tme_connection_element->tme_element_private;
437: conn_int = (struct tme_bus_connection_int *) conn;
438:
439: /* lock the bus for writing: */
440: rc = tme_rwlock_timedwrlock(&bus->tme_bus_rwlock, TME_THREAD_TIMEDLOCK);
441: if (TME_THREADS_ERRNO(rc) != TME_OK) {
442: return (TME_THREADS_ERRNO(rc));
443: }
444:
445: /* call the generic bus support function: */
446: rc = tme_bus_connection_make(bus,
447: conn_int,
448: state);
449:
450: /* unlock the bus: */
451: tme_rwlock_unlock(&bus->tme_bus_rwlock);
452:
453: return (rc);
454: }
455:
456: /* this breaks a connection: */
457: static int
458: _tme_bus_connection_break(struct tme_connection *conn, unsigned int state)
459: {
460: abort();
461: }
462:
463: /* this returns the new connections possible: */
464: static int
465: _tme_bus_connections_new(struct tme_element *element,
466: const char * const *args,
467: struct tme_connection **_conns,
468: char **_output)
469: {
470: const struct tme_bus *bus;
471: struct tme_bus_connection_int *conn_int;
472: struct tme_bus_connection *conn_bus;
473: struct tme_connection *conn;
474: int ipl;
475: int arg_i;
476: int usage;
477:
478: /* recover our bus. we only read the address mask, so we don't lock
479: the rwlock: */
480: bus = element->tme_element_private;
481:
482: /* allocate the new connection side: */
483: conn_int = tme_new0(struct tme_bus_connection_int, 1);
484: conn_bus = &conn_int->tme_bus_connection_int;
485: conn = &conn_bus->tme_bus_connection;
486:
487: /* loop reading our arguments: */
488: usage = FALSE;
489: arg_i = 1;
490: for (;;) {
491:
492: /* the address of this connection: */
493: if (TME_ARG_IS(args[arg_i + 0], "addr")) {
494: conn_int->tme_bus_connection_int_addressable = TRUE;
495: conn_int->tme_bus_connection_int_address = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
496: if (usage
497: || (conn_int->tme_bus_connection_int_address
498: > bus->tme_bus_address_mask)) {
499: usage = TRUE;
500: break;
501: }
502: arg_i += 2;
503: }
504:
505: /* the interrupt signal for this connection: */
506: else if (TME_ARG_IS(args[arg_i + 0], "ipl")
507: && args[arg_i + 1] != NULL
508: && (ipl = atoi(args[arg_i + 1])) > 0) {
509: conn_int->tme_bus_connection_int_signal_int = TME_BUS_SIGNAL_INT(ipl);
510: arg_i += 2;
511: }
512:
513: /* if we've run out of arguments: */
514: else if (args[arg_i + 0] == NULL) {
515: break;
516: }
517:
518: /* this is a bad argument: */
519: else {
520: tme_output_append_error(_output,
521: "%s %s, ",
522: args[arg_i],
523: _("unexpected"));
524: usage = TRUE;
525: break;
526: }
527: }
528:
529: if (usage) {
530: tme_output_append_error(_output,
531: "%s %s [ addr %s ] [ ipl %s ]",
532: _("usage:"),
533: args[0],
534: _("BUS-ADDRESS"),
535: _("INTERRUPT-LEVEL"));
536: tme_free(conn_int);
537: return (EINVAL);
538: }
539:
540: /* fill in the bus connection: */
541: conn_bus->tme_bus_address_last = bus->tme_bus_address_mask;
542: conn_bus->tme_bus_signal = _tme_bus_signal;
543: conn_bus->tme_bus_intack = _tme_bus_intack;
544: conn_bus->tme_bus_tlb_set_allocate = _tme_bus_tlb_set_allocate;
545: conn_bus->tme_bus_tlb_fill = _tme_bus_tlb_fill;
546:
547: /* fill in the generic connection: */
548: conn->tme_connection_next = *_conns;
549: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
550: conn->tme_connection_score = _tme_bus_connection_score;
551: conn->tme_connection_make = _tme_bus_connection_make;
552: conn->tme_connection_break = _tme_bus_connection_break;
553:
554: /* return the new connection side: */
555: *_conns = conn;
556: return (TME_OK);
557: }
558:
559: /* this creates a new bus element: */
560: TME_ELEMENT_SUB_NEW_DECL(tme_generic,bus) {
561: struct tme_bus *bus;
562: tme_bus_addr_t bus_size;
563: int failed;
564:
565: /* our arguments must include the bus size, and the
566: bus size must be a power of two: */
567: failed = TRUE;
568: bus_size = 0;
569: if (TME_ARG_IS(args[1], "size")) {
570: bus_size = tme_bus_addr_parse_any(args[2], &failed);
571: if (bus_size & (bus_size - 1)) {
572: failed = TRUE;
573: }
574: }
575: if (failed) {
576: tme_output_append_error(_output,
577: "%s %s size %s",
578: _("usage:"),
579: args[0],
580: _("SIZE"));
581: return (EINVAL);
582: }
583:
584: /* allocate and initialize the new bus: */
585: bus = tme_new0(struct tme_bus, 1);
586: tme_rwlock_init(&bus->tme_bus_rwlock);
587: bus->tme_bus_address_mask = bus_size - 1;
588: bus->tme_bus_addressables_count = 0;
589: bus->tme_bus_addressables_size = 1;
590: bus->tme_bus_addressables = tme_new(struct tme_bus_connection_int *,
591: bus->tme_bus_addressables_size);
592:
593: /* fill the element: */
594: element->tme_element_private = bus;
595: element->tme_element_connections_new = _tme_bus_connections_new;
596:
597: return (TME_OK);
598: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.