|
|
1.1 root 1: /* $Id: stp22xx.c,v 1.4 2009/09/07 15:03:19 fredette Exp $ */
2:
3: /* ic/stp22xx.c - common STP2200, STP2202, STP2220, and STP2222
4: emulation: */
5:
6: /*
7: * Copyright (c) 2009 Matt Fredette
8: * All rights reserved.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by Matt Fredette.
21: * 4. The name of the author may not be used to endorse or promote products
22: * derived from this software without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
28: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34: * POSSIBILITY OF SUCH DAMAGE.
35: */
36:
37: #include <tme/common.h>
38: _TME_RCSID("$Id: stp22xx.c,v 1.4 2009/09/07 15:03:19 fredette Exp $");
39:
40: /* includes: */
41: #include "stp22xx-impl.h"
42:
43: /* this busies a generic bus connection: */
44: struct tme_bus_connection *
45: tme_stp22xx_busy_bus(struct tme_stp22xx *stp22xx,
46: tme_uint32_t conn_index)
47: {
48: struct tme_bus_connection *conn_bus;
49:
50: /* if the connection index is valid: */
51: conn_bus = NULL;
52: if (__tme_predict_true(conn_index != stp22xx->tme_stp22xx_conn_index_null)) {
53:
54: /* if there is a connection at this index: */
55: conn_bus = stp22xx->tme_stp22xx_conns[conn_index].tme_stp22xx_conn_bus;
56: if (__tme_predict_true(conn_bus != NULL)) {
57:
58: }
59: }
60:
61: return (conn_bus);
62: }
63:
64: /* this unbusies a generic bus connection: */
65: void
66: tme_stp22xx_unbusy_bus(struct tme_stp22xx *stp22xx,
67: struct tme_bus_connection *conn_bus)
68: {
69:
70: /* the connection must be valid: */
71: assert (conn_bus != NULL);
72: }
73:
74: /* this busies a slave generic bus connection: */
75: struct tme_bus_connection *
76: tme_stp22xx_slave_busy_bus(struct tme_stp22xx *stp22xx,
77: tme_uint32_t slave_conn_index)
78: {
79: struct tme_bus_connection *slave_conn_bus;
80:
81: /* if the connection index is valid: */
82: slave_conn_bus = tme_stp22xx_busy_bus(stp22xx, slave_conn_index);
83: if (__tme_predict_true(slave_conn_bus != NULL)) {
84:
85: /* this is now the busy slave connection: */
86: assert (stp22xx->tme_stp22xx_slave_conn_bus == NULL);
87: stp22xx->tme_stp22xx_slave_conn_bus = slave_conn_bus;
88: }
89: return (slave_conn_bus);
90: }
91:
92: /* this unbusies a slave generic bus connection: */
93: void
94: tme_stp22xx_slave_unbusy(struct tme_stp22xx *stp22xx)
95: {
96:
97: /* unbusy the slave connection: */
98: tme_stp22xx_unbusy_bus(stp22xx, stp22xx->tme_stp22xx_slave_conn_bus);
99:
100: /* there is now no busy slave connection: */
101: stp22xx->tme_stp22xx_slave_conn_bus = NULL;
102: }
103:
104: /* this enters without locking the mutex: */
105: static struct tme_stp22xx *
106: _tme_stp22xx_enter_locked(struct tme_stp22xx *stp22xx)
107: {
108: signed long completion_i;
109: struct tme_completion *completion;
110: _tme_stp22xx_completion_handler_t handler;
111:
112: /* loop over the completions: */
113: completion_i = TME_STP22XX_COMPLETIONS_MAX - 1;
114: completion = &stp22xx->tme_stp22xx_completions[completion_i];
115: do {
116:
117: /* if this completion is valid: */
118: if (tme_completion_is_valid(completion)) {
119:
120: /* make a read-before-read barrier: */
121: tme_memory_barrier(stp22xx, stp22xx->tme_stp22xx_sizeof, TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
122:
123: /* invalidate the completion: */
124: tme_completion_invalidate(completion);
125:
126: /* call the completion handler: */
127: handler = stp22xx->tme_stp22xx_completion_handlers[completion_i];
128: assert (handler != NULL);
129: stp22xx->tme_stp22xx_completion_handlers[completion_i] = NULL;
130: (*handler)(stp22xx,
131: completion,
132: stp22xx->tme_stp22xx_completion_args[completion_i]);
133: }
134:
135: completion--;
136: } while (--completion_i >= 0);
137:
138: return (stp22xx);
139: }
140:
141: /* this enters: */
142: struct tme_stp22xx *
143: tme_stp22xx_enter(struct tme_stp22xx *stp22xx)
144: {
145:
146: /* lock the mutex: */
147: tme_mutex_lock(&stp22xx->tme_stp22xx_mutex);
148:
149: /* finish the enter: */
150: return (_tme_stp22xx_enter_locked(stp22xx));
151: }
152:
153: /* this enters as the bus master: */
154: struct tme_stp22xx *
155: tme_stp22xx_enter_master(struct tme_bus_connection *master_conn_bus)
156: {
157: struct tme_stp22xx *stp22xx;
158:
159: #if TME_STP22XX_BUS_TRANSITION
160: signed long completion_i;
161: struct tme_completion *completion;
162:
163: /* if the bus master was making a callout through the bus: */
164: #if !TME_THREADS_COOPERATIVE
165: #error "preemptive threads not supported yet"
166: #endif /* !TME_THREADS_COOPERATIVE */
167: stp22xx = master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
168: if (stp22xx->tme_stp22xx_master_completion != NULL) {
169:
170: /* find the completion for that callout and force it to be valid.
171: this is necessary since we may be reentered by a new master
172: before the original callout returns: */
173: completion_i = TME_STP22XX_COMPLETIONS_MAX - 1;
174: for (;;) {
175: if (stp22xx->tme_stp22xx_completion_handlers[completion_i]
176: == tme_stp22xx_complete_master) {
177: break;
178: }
179: --completion_i;
180: assert (completion_i >= 0);
181: }
182: assert (stp22xx->tme_stp22xx_completion_args[completion_i]
183: == stp22xx->tme_stp22xx_master_completion);
184: completion = &stp22xx->tme_stp22xx_completions[completion_i];
185: if (!tme_completion_is_valid(completion)) {
186: tme_completion_validate(completion);
187: }
188: }
189:
190: #endif /* TME_STP22XX_BUS_TRANSITION */
191:
192: /* enter: */
193: stp22xx = tme_stp22xx_enter(master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private);
194:
195: /* only the bus master can cause a callout through the bus, and the
196: bus master can only cause one such callout at a time: */
197: assert (stp22xx->tme_stp22xx_master_completion == NULL);
198:
199: return (stp22xx);
200: }
201:
202: /* this runs: */
203: static void
204: _tme_stp22xx_run(struct tme_stp22xx *stp22xx)
205: {
206:
207: /* if the run function is not running: */
208: if (!stp22xx->tme_stp22xx_running) {
209:
210: /* the run function is now running: */
211: stp22xx->tme_stp22xx_running = TRUE;
212:
213: /* call the run function: */
214: (*stp22xx->tme_stp22xx_run)(stp22xx);
215:
216: /* the run function is not running: */
217: stp22xx->tme_stp22xx_running = FALSE;
218: }
219: }
220:
221: /* this leaves: */
222: void
223: tme_stp22xx_leave(struct tme_stp22xx *stp22xx)
224: {
225: signed long completion_i;
226: struct tme_completion *completion;
227: struct tme_completion *completions_delayed[TME_STP22XX_COMPLETIONS_DELAYED_MAX];
228:
229: /* run: */
230: _tme_stp22xx_run(stp22xx);
231:
232: /* get any completions whose validations were delayed: */
233: for (completion_i = 0;; completion_i++) {
234: completion = stp22xx->tme_stp22xx_completions_delayed[completion_i];
235: if (completion == NULL) {
236: break;
237: }
238: stp22xx->tme_stp22xx_completions_delayed[completion_i] = NULL;
239: completions_delayed[completion_i] = completion;
240: }
241:
242: /* unlock the mutex: */
243: tme_mutex_unlock(&stp22xx->tme_stp22xx_mutex);
244:
245: /* validate any completions: */
246: for (; --completion_i >= 0; ) {
247: tme_completion_validate(completions_delayed[completion_i]);
248: }
249: }
250:
251: /* this waits on a condition, with an optional sleep time: */
252: void
253: tme_stp22xx_cond_sleep_yield(struct tme_stp22xx *stp22xx,
254: struct tme_stp22xx_cond *cond,
255: const struct timeval *sleep)
256: {
257: signed long completion_i;
258: struct tme_completion *completion;
259:
260: /* this condition must be idle: */
261: assert (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_IDLE);
262:
263: /* we are now running, before waiting on this condition: */
264: cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_RUNNING;
265:
266: /* run: */
267: _tme_stp22xx_run(stp22xx);
268:
269: /* if this condition was notified while we were running: */
270: if (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_NOTIFIED) {
271:
272: /* this condition is idle again: */
273: cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_IDLE;
274:
275: return;
276: }
277:
278: /* the condition must still be running: */
279: assert (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_RUNNING);
280:
281: /* make a total write-after-write barrier, to force writes to the
282: completion states to happen before validation: */
283: tme_memory_barrier(0, 0, TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
284:
285: /* validate any completions whose validations were delayed: */
286: for (completion_i = 0;; completion_i++) {
287: completion = stp22xx->tme_stp22xx_completions_delayed[completion_i];
288: if (completion == NULL) {
289: break;
290: }
291: stp22xx->tme_stp22xx_completions_delayed[completion_i] = NULL;
292: tme_completion_validate(completion);
293: }
294:
295: /* we are now waiting on this condition, unless threading is
296: cooperative, in which case the condition will be idle again the
297: next time this thread runs: */
298: cond->tme_stp22xx_cond_state
299: = (TME_THREADS_COOPERATIVE
300: ? TME_STP22XX_COND_STATE_IDLE
301: : TME_STP22XX_COND_STATE_WAITING);
302:
303: /* sleep or wait on the condition variable: */
304: if (sleep != NULL) {
305: tme_cond_sleep_yield(&cond->tme_stp22xx_cond_cond,
306: &stp22xx->tme_stp22xx_mutex,
307: sleep);
308: }
309: else {
310: tme_cond_wait_yield(&cond->tme_stp22xx_cond_cond,
311: &stp22xx->tme_stp22xx_mutex);
312: }
313:
314: /* this condition is idle again: */
315: cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_IDLE;
316:
317: /* reenter: */
318: _tme_stp22xx_enter_locked(stp22xx);
319: }
320:
321: /* this validates a completion: */
322: /* NB: completion may be NULL: */
323: void
324: tme_stp22xx_completion_validate(struct tme_stp22xx *stp22xx,
325: struct tme_completion *completion)
326: {
327: unsigned long completion_i;
328:
329: /* we delay validating completions: */
330: for (completion_i = 0;; completion_i++) {
331: assert (completion_i < TME_STP22XX_COMPLETIONS_DELAYED_MAX);
332: if (stp22xx->tme_stp22xx_completions_delayed[completion_i] == NULL) {
333: break;
334: }
335: }
336: stp22xx->tme_stp22xx_completions_delayed[completion_i] = completion;
337: }
338:
339: /* this allocates a completion: */
340: struct tme_completion *
341: tme_stp22xx_completion_alloc(struct tme_stp22xx *stp22xx,
342: _tme_stp22xx_completion_handler_t handler,
343: void *arg)
344: {
345: signed long completion_i;
346: struct tme_completion *completion;
347:
348: /* find a free completion: */
349: completion_i = TME_STP22XX_COMPLETIONS_MAX - 1;
350: for (; stp22xx->tme_stp22xx_completion_handlers[completion_i] != NULL; ) {
351: completion_i--;
352: assert (completion_i >= 0);
353: }
354:
355: /* allocate this completion: */
356: stp22xx->tme_stp22xx_completion_handlers[completion_i] = handler;
357: stp22xx->tme_stp22xx_completion_args[completion_i] = arg;
358:
359: /* the completion can't still (or already) be valid: */
360: completion = &stp22xx->tme_stp22xx_completions[completion_i];
361: assert (!tme_completion_is_valid(completion));
362:
363: /* return the completion: */
364: return (completion);
365: }
366:
367: /* this calls out a bus signal to a connection: */
368: void
369: tme_stp22xx_callout_signal(struct tme_stp22xx *stp22xx,
370: tme_uint32_t conn_index,
371: unsigned int signal,
372: _tme_stp22xx_completion_handler_t handler)
373: {
374: struct tme_bus_connection *conn_bus;
375: struct tme_completion completion_buffer;
376: struct tme_completion *completion;
377: struct tme_bus_connection *conn_bus_other;
378:
379: /* if there is a connection at this index: */
380: conn_bus = tme_stp22xx_busy_bus(stp22xx, conn_index);
381: if (conn_bus != NULL) {
382:
383: /* if the connection at this index doesn't care about bus
384: signals: */
385: conn_bus_other = (struct tme_bus_connection *) conn_bus->tme_bus_connection.tme_connection_other;
386: if (conn_bus_other->tme_bus_signal == NULL) {
387:
388: /* unbusy the bus connection: */
389: tme_stp22xx_unbusy_bus(stp22xx, conn_bus);
390:
391: /* behave as if there is no connection at this index: */
392: conn_bus = NULL;
393: }
394: }
395:
396: /* if there is no connection at this index: */
397: if (conn_bus == NULL) {
398:
399: /* call the completion handler directly: */
400: completion_buffer.tme_completion_error = TME_OK;
401: (*handler)(stp22xx, &completion_buffer, (void *) NULL);
402: return;
403: }
404:
405: /* allocate a completion: */
406: completion = tme_stp22xx_completion_alloc(stp22xx, handler, (void *) NULL);
407:
408: /* leave: */
409: tme_stp22xx_leave(stp22xx);
410:
411: /* call out the bus signal: */
412: conn_bus_other = (struct tme_bus_connection *) conn_bus->tme_bus_connection.tme_connection_other;
413: #if TME_STP22XX_BUS_TRANSITION
414: completion->tme_completion_error =
415: (*conn_bus_other->tme_bus_signal)
416: (conn_bus_other,
417: signal);
418: tme_completion_validate(completion);
419: #else /* !TME_STP22XX_BUS_TRANSITION */
420: #error WRITEME
421: #endif /* !TME_STP22XX_BUS_TRANSITION */
422:
423: /* reenter: */
424: tme_stp22xx_enter(stp22xx);
425:
426: /* unbusy the bus connection: */
427: tme_stp22xx_unbusy_bus(stp22xx, conn_bus);
428: }
429:
430: /* this completes a bus operation between master and slave: */
431: void
432: tme_stp22xx_complete_master(struct tme_stp22xx *stp22xx,
433: struct tme_completion *completion,
434: void *__master_completion)
435: {
436: struct tme_completion **_master_completion;
437: struct tme_completion *master_completion;
438:
439: /* unbusy the slave connection: */
440: tme_stp22xx_slave_unbusy(stp22xx);
441:
442: /* if this bus operation was not aborted: */
443: _master_completion = (struct tme_completion **) __master_completion;
444: if (stp22xx->tme_stp22xx_master_completion == _master_completion) {
445:
446: /* pass any slave error and scalar return value back to the master: */
447: master_completion = *_master_completion;
448: master_completion->tme_completion_error = completion->tme_completion_error;
449: master_completion->tme_completion_scalar = completion->tme_completion_scalar;
450:
451: /* this bus operation is completed: */
452: stp22xx->tme_stp22xx_master_completion = NULL;
453:
454: /* validate the completion: */
455: tme_stp22xx_completion_validate(stp22xx, master_completion);
456: }
457: }
458:
459: /* this completes a bus grant: */
460: void
461: tme_stp22xx_complete_bg(struct tme_stp22xx *stp22xx,
462: struct tme_completion *completion,
463: void *arg)
464: {
465: stp22xx->tme_stp22xx_master_conn_index
466: = stp22xx->tme_stp22xx_master_conn_index_pending;
467: stp22xx->tme_stp22xx_master_conn_index_pending = stp22xx->tme_stp22xx_conn_index_null;
468:
469: /* unused: */
470: completion = 0;
471: arg = 0;
472: }
473:
474: /* this is a no-op completion: */
475: void
476: tme_stp22xx_complete_nop(struct tme_stp22xx *stp22xx,
477: struct tme_completion *completion,
478: void *arg)
479: {
480: /* unused: */
481: stp22xx = 0;
482: completion = 0;
483: arg = 0;
484: }
485:
486: /* this runs a slave bus cycle: */
487: void
488: tme_stp22xx_slave_cycle(struct tme_bus_connection *master_conn_bus,
489: tme_uint32_t slave_conn_index,
490: struct tme_bus_cycle *master_cycle,
491: tme_uint32_t *_master_fast_cycle_types,
492: struct tme_completion **_master_completion)
493: {
494: struct tme_stp22xx *stp22xx;
495: struct tme_bus_connection *slave_conn_bus;
496: int completion_error;
497: #if TME_STP22XX_BUS_TRANSITION
498: struct tme_bus_tlb tlb_local;
499: int rc;
500: tme_uint8_t *memory;
501: tme_bus_addr_t tlb_cycle_address;
502: int shift;
503: #endif /* TME_STP22XX_BUS_TRANSITION */
504: struct tme_completion *completion;
505: struct tme_bus_connection *slave_conn_bus_other;
506: struct tme_completion *master_completion;
507:
508: /* recover our data structure: */
509: stp22xx = master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
510:
511: /* this cycle must not have been aborted: */
512: assert (stp22xx->tme_stp22xx_master_completion == _master_completion);
513:
514: /* busy the connection to any slave: */
515: slave_conn_bus = tme_stp22xx_slave_busy_bus(stp22xx, slave_conn_index);
516:
517: /* if the connection index is invalid, or if there is no slave at
518: this connection index: */
519: if (__tme_predict_false(slave_conn_bus == NULL)) {
520:
521: /* complete with an error: */
522: completion_error = ENOENT;
523: }
524:
525: /* otherwise, if the master is trying a cycle to itself: */
526: else if (__tme_predict_false(slave_conn_bus == master_conn_bus)) {
527:
528: /* unbusy the connection to the slave: */
529: tme_stp22xx_slave_unbusy(stp22xx);
530:
531: /* complete with an error: */
532: completion_error = EIO;
533: }
534:
535: /* otherwise, we can run this cycle: */
536: else {
537:
538: #if TME_STP22XX_BUS_TRANSITION
539:
540: /* fill a TLB entry for this address: */
541: tlb_local.tme_bus_tlb_token = &stp22xx->tme_stp22xx_slave_cycle_tlb_token;
542: slave_conn_bus_other = (struct tme_bus_connection *) slave_conn_bus->tme_bus_connection.tme_connection_other;
543: rc = ((*slave_conn_bus_other->tme_bus_tlb_fill)
544: (slave_conn_bus_other,
545: &tlb_local,
546: master_cycle->tme_bus_cycle_address,
547: master_cycle->tme_bus_cycle_type));
548: assert (rc == TME_OK);
549:
550: /* the master can't do any fast transfers that this TLB entry
551: doesn't allow: */
552: if (tlb_local.tme_bus_tlb_emulator_off_read == TME_EMULATOR_OFF_UNDEF) {
553: *_master_fast_cycle_types &= ~TME_BUS_CYCLE_READ;
554: }
555: if (tlb_local.tme_bus_tlb_emulator_off_write == TME_EMULATOR_OFF_UNDEF) {
556: *_master_fast_cycle_types &= ~TME_BUS_CYCLE_WRITE;
557: }
558:
559: /* if this cycle can be done fast: */
560: /* NB: this breaks tme_shared and const: */
561: memory
562: = (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ
563: ? (tme_uint8_t *) tlb_local.tme_bus_tlb_emulator_off_read
564: : (tme_uint8_t *) tlb_local.tme_bus_tlb_emulator_off_write);
565: if (memory != TME_EMULATOR_OFF_UNDEF) {
566:
567: /* do the fast transfer: */
568: tme_bus_cycle_xfer_memory(master_cycle, memory, tlb_local.tme_bus_tlb_addr_last);
569:
570: /* unbusy the connection to the slave: */
571: tme_stp22xx_slave_unbusy(stp22xx);
572:
573: /* complete with success: */
574: master_completion = *_master_completion;
575: master_completion->tme_completion_error = TME_OK;
576: tme_stp22xx_completion_validate(stp22xx, master_completion);
577: stp22xx->tme_stp22xx_master_completion = NULL;
578: return;
579: }
580:
581: #endif /* TME_STP22XX_BUS_TRANSITION */
582:
583: /* when we complete, we will will complete for the master: */
584: completion
585: = tme_stp22xx_completion_alloc(stp22xx,
586: tme_stp22xx_complete_master,
587: _master_completion);
588:
589: /* leave: */
590: tme_stp22xx_leave(stp22xx);
591:
592: /* run this cycle: */
593: #if TME_STP22XX_BUS_TRANSITION
594: tlb_cycle_address = tlb_local.tme_bus_tlb_addr_offset + master_cycle->tme_bus_cycle_address;
595: shift = tlb_local.tme_bus_tlb_addr_shift;
596: if (shift < 0) {
597: tlb_cycle_address <<= (0 - shift);
598: }
599: else if (shift > 0) {
600: tlb_cycle_address >>= shift;
601: }
602: master_cycle->tme_bus_cycle_address = tlb_cycle_address;
603: /* NB: we may be reentered before this cycle callout returns,
604: usually by this slave device immediately turning around to
605: become a master. unfortunately, this means that
606: tme_stp22xx_enter_master() will have to validate the first
607: master's completion itself, before we would normally do it
608: here. this means that we also have to predict how the cycle
609: will complete - and we assume that if the slave does turn
610: around to become a master, that the cycle completed
611: successfully: */
612: completion->tme_completion_error = TME_OK;
613: rc
614: = ((*tlb_local.tme_bus_tlb_cycle)
615: (tlb_local.tme_bus_tlb_cycle_private,
616: master_cycle));
617: if (stp22xx->tme_stp22xx_master_completion != _master_completion) {
618: assert (rc == TME_OK);
619: }
620: else {
621: completion->tme_completion_error = rc;
622: tme_completion_validate(completion);
623: }
624: #else /* !TME_STP22XX_BUS_TRANSITION */
625: #error WRITEME
626: #endif /* !TME_STP22XX_BUS_TRANSITION */
627:
628: /* reenter: */
629: tme_stp22xx_enter(stp22xx);
630:
631: return;
632: }
633:
634: /* complete with the error: */
635: master_completion = *_master_completion;
636: master_completion->tme_completion_error = completion_error;
637: tme_stp22xx_completion_validate(stp22xx, master_completion);
638: stp22xx->tme_stp22xx_master_completion = NULL;
639: *_master_fast_cycle_types = 0;
640: }
641:
642: /* this fills a TLB entry: */
643: void
644: tme_stp22xx_tlb_fill(struct tme_bus_connection *agent_conn_bus,
645: struct tme_bus_tlb *tlb,
646: tme_uint32_t slave_conn_index,
647: tme_bus_addr64_t slave_address,
648: unsigned int cycle_type)
649: {
650: struct tme_stp22xx *stp22xx;
651: struct tme_bus_connection *slave_conn_bus;
652: struct tme_bus_connection *slave_conn_bus_other;
653: #if TME_STP22XX_BUS_TRANSITION
654: int rc;
655: #endif /* TME_STP22XX_BUS_TRANSITION */
656:
657: /* recover our data structure: */
658: stp22xx = agent_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
659:
660: /* busy the connection to any slave: */
661: slave_conn_bus = tme_stp22xx_busy_bus(stp22xx, slave_conn_index);
662:
663: /* if the connection index is invalid, or if there is no slave at
664: this connection index, or if the agent is filling a TLB for an
665: address in itself: */
666: if (__tme_predict_false(slave_conn_bus == NULL
667: || slave_conn_bus == agent_conn_bus)) {
668:
669: /* unbusy any connection to the slave: */
670: if (slave_conn_bus != NULL) {
671: tme_stp22xx_unbusy_bus(stp22xx, slave_conn_bus);
672: }
673:
674: /* initialize the TLB entry: */
675: tme_bus_tlb_initialize(tlb);
676:
677: /* our caller will map this TLB entry from covering all addresses
678: to only covering a region's addresses: */
679: tlb->tme_bus_tlb_addr_first = 0;
680: tlb->tme_bus_tlb_addr_last = 0 - (tme_bus_addr_t) 1;
681: }
682:
683: /* otherwise, the slave can fill this TLB entry: */
684: else {
685:
686: /* leave: */
687: tme_stp22xx_leave(stp22xx);
688:
689: /* fill this TLB entry: */
690: slave_conn_bus_other = (struct tme_bus_connection *) slave_conn_bus->tme_bus_connection.tme_connection_other;
691: #if TME_STP22XX_BUS_TRANSITION
692: rc =
693: #endif /* TME_STP22XX_BUS_TRANSITION */
694: (*slave_conn_bus_other->tme_bus_tlb_fill)
695: (slave_conn_bus_other,
696: tlb,
697: slave_address,
698: cycle_type);
699: #if TME_STP22XX_BUS_TRANSITION
700: assert (rc == TME_OK);
701: #endif /* TME_STP22XX_BUS_TRANSITION */
702:
703: /* reenter: */
704: tme_stp22xx_enter(stp22xx);
705:
706: /* unbusy the connection to the slave: */
707: tme_stp22xx_unbusy_bus(stp22xx, slave_conn_bus);
708: }
709: }
710:
711: #if TME_STP22XX_BUS_TRANSITION
712:
713: /* this is the bus TLB set add transition glue: */
714: #undef tme_stp22xx_tlb_set_add
715: int
716: tme_stp22xx_tlb_set_add_transition(struct tme_bus_connection *agent_conn_bus,
717: struct tme_bus_tlb_set_info *tlb_set_info)
718: {
719: struct tme_completion completion_buffer;
720: tme_completion_init(&completion_buffer);
721: tme_stp22xx_tlb_set_add(agent_conn_bus,
722: tlb_set_info,
723: &completion_buffer);
724: return (completion_buffer.tme_completion_error);
725: }
726:
727: #endif /* TME_STP22XX_BUS_TRANSITION */
728:
729: /* this adds a TLB set: */
730: void
731: tme_stp22xx_tlb_set_add(struct tme_bus_connection *agent_conn_bus,
732: struct tme_bus_tlb_set_info *tlb_set_info,
733: struct tme_completion *agent_completion)
734: {
735: struct tme_stp22xx *stp22xx;
736:
737: /* enter: */
738: stp22xx = tme_stp22xx_enter((struct tme_stp22xx *) agent_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private);
739:
740: /* if this TLB set provides a bus context register: */
741: if (tlb_set_info->tme_bus_tlb_set_info_bus_context != NULL) {
742:
743: /* this bus only has one context: */
744: *tlb_set_info->tme_bus_tlb_set_info_bus_context = 0;
745: tlb_set_info->tme_bus_tlb_set_info_bus_context_max = 0;
746: }
747:
748: /* leave: */
749: agent_completion->tme_completion_error = TME_OK;
750: tme_stp22xx_completion_validate(stp22xx, agent_completion);
751: tme_stp22xx_leave(stp22xx);
752: }
753:
754: /* this notifies a condition: */
755: void
756: tme_stp22xx_cond_notify(struct tme_stp22xx_cond *cond)
757: {
758:
759: /* if threading is cooperative, and this condition is idle: */
760: if (TME_THREADS_COOPERATIVE
761: && cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_IDLE) {
762:
763: /* we have to assume that a thread has yielded waiting on this
764: condition, but because threading is cooperative, has already
765: set the condition back to idle. we can't mark the condition as
766: notified, since it would never get set back to idle: */
767: }
768:
769: /* otherwise, threading is not cooperative, or the condition is not
770: idle: */
771: else {
772:
773: /* this condition must be either running before waiting, or
774: waiting: */
775: assert (cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_RUNNING
776: || cond->tme_stp22xx_cond_state == TME_STP22XX_COND_STATE_WAITING);
777:
778: /* this condition has been notified: */
779: cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_NOTIFIED;
780: }
781:
782: /* notify the real condition: */
783: tme_cond_notify(&cond->tme_stp22xx_cond_cond, FALSE);
784: }
785:
786: /* this initializes a condition: */
787: void
788: tme_stp22xx_cond_init(struct tme_stp22xx_cond *cond)
789: {
790: /* this condition is idle: */
791: cond->tme_stp22xx_cond_state = TME_STP22XX_COND_STATE_IDLE;
792: tme_cond_init(&cond->tme_stp22xx_cond_cond);
793: }
794:
795: /* this initializes an stp22xx: */
796: void
797: tme_stp22xx_init(struct tme_stp22xx *stp22xx,
798: unsigned long _sizeof,
799: tme_uint32_t conn_index_null)
800: {
801: unsigned long completion_i;
802:
803: /* initialize the mutex: */
804: tme_mutex_init(&stp22xx->tme_stp22xx_mutex);
805:
806: /* set the size of the structure: */
807: stp22xx->tme_stp22xx_sizeof = _sizeof;
808:
809: /* set the undefined connection index: */
810: stp22xx->tme_stp22xx_conn_index_null = conn_index_null;
811:
812: /* initialize the completions: */
813: for (completion_i = 0; completion_i < TME_STP22XX_COMPLETIONS_MAX; completion_i++) {
814: tme_completion_init(&stp22xx->tme_stp22xx_completions[completion_i]);
815: stp22xx->tme_stp22xx_completion_handlers[completion_i] = NULL;
816: }
817:
818: /* initialize the delayed completions: */
819: for (completion_i = 0; completion_i < TME_STP22XX_COMPLETIONS_DELAYED_MAX; completion_i++) {
820: stp22xx->tme_stp22xx_completions_delayed[completion_i] = NULL;
821: }
822:
823: /* there is no current bus master: */
824: stp22xx->tme_stp22xx_master_conn_index = conn_index_null;
825:
826: #if TME_STP22XX_BUS_TRANSITION
827: /* initialize the token for filling TLB entries for slave cycles: */
828: tme_token_init(&stp22xx->tme_stp22xx_slave_cycle_tlb_token);
829: #endif /* TME_STP22XX_BUS_TRANSITION */
830: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.