1 /* $Id: sun-obie.c,v 1.5 2010/06/05 19:20:30 fredette Exp $ */
2
3 /* machine/sun/sun-obie.c - classic Sun onboard Intel Ethernet implementation: */
4
5 /*
6 * Copyright (c) 2004 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: sun-obie.c,v 1.5 2010/06/05 19:20:30 fredette Exp $");
38
39 /* includes: */
40 #include <tme/element.h>
41 #undef TME_BUS_VERSION
42 #define TME_BUS_VERSION TME_X_VERSION(0, 0)
43 #include <tme/generic/bus.h>
44 #undef TME_I825X6_VERSION
45 #define TME_I825X6_VERSION TME_X_VERSION(0, 0)
46 #include <tme/ic/i825x6.h>
47 #include <tme/machine/sun.h>
48
49 /* macros: */
50
51 /* register offsets and sizes: */
52 #define TME_SUN_OBIE_REG_CSR (0)
53 #define TME_SUN_OBIE_SIZ_CSR (sizeof(tme_uint16_t))
54 #define TME_SUN_OBIE_SIZ_REGS (TME_SUN_OBIE_REG_CSR + TME_SUN_OBIE_SIZ_CSR)
55
56 /* the bits in the Control/Status Register: */
57 #define TME_SUN_OBIE_CSR_NORESET (0x8000)
58 #define TME_SUN_OBIE_CSR_NOLOOP (0x4000)
59 #define TME_SUN_OBIE_CSR_CA (0x2000)
60 #define TME_SUN_OBIE_CSR_IE (0x1000)
61 /* 0x0800 unused */
62 #define TME_SUN_OBIE_CSR_LEVEL2 (0x0400)
63 #define TME_SUN_OBIE_CSR_BUSERR (0x0200)
64 #define TME_SUN_OBIE_CSR_INTR (0x0100)
65 #define TME_SUN_OBIE_CSR_READONLY (0x0800 \
66 | TME_SUN_OBIE_CSR_LEVEL2 \
67 | TME_SUN_OBIE_CSR_BUSERR \
68 | TME_SUN_OBIE_CSR_INTR)
69
70 /* these get and put the CSR: */
71 #define TME_SUN_OBIE_CSR_GET(sun_obie) \
72 ((((tme_uint16_t) (sun_obie)->tme_sun_obie_regs[TME_SUN_OBIE_REG_CSR + 0]) << 8) \
73 + (sun_obie)->tme_sun_obie_regs[TME_SUN_OBIE_REG_CSR + 1])
74 #define TME_SUN_OBIE_CSR_PUT(sun_obie, csr) \
75 do { \
76 (sun_obie)->tme_sun_obie_regs[TME_SUN_OBIE_REG_CSR + 0] = (csr) >> 8; \
77 (sun_obie)->tme_sun_obie_regs[TME_SUN_OBIE_REG_CSR + 1] = (tme_uint8_t) (csr); \
78 } while (/* CONSTCOND */ 0)
79
80 /* the callout flags: */
81 #define TME_SUN_OBIE_CALLOUT_CHECK (0)
82 #define TME_SUN_OBIE_CALLOUT_RUNNING TME_BIT(0)
83 #define TME_SUN_OBIE_CALLOUTS_MASK (-2)
84 #define TME_SUN_OBIE_CALLOUT_SIGNALS TME_BIT(1)
85 #define TME_SUN_OBIE_CALLOUT_INT TME_BIT(2)
86
87 /* structures: */
88
89 /* the card: */
90 struct tme_sun_obie {
91
92 /* backpointer to our element: */
93 struct tme_element *tme_sun_obie_element;
94
95 /* the mutex protecting the card: */
96 tme_mutex_t tme_sun_obie_mutex;
97
98 /* the rwlock protecting the card: */
99 tme_rwlock_t tme_sun_obie_rwlock;
100
101 /* the bus connection for the card's registers: */
102 struct tme_bus_connection *tme_sun_obie_conn_regs;
103
104 /* the bus connection for the card's memory: */
105 struct tme_bus_connection *tme_sun_obie_conn_memory;
106
107 /* the bus connection for the card's i825x6 chip: */
108 struct tme_bus_connection *tme_sun_obie_conn_i825x6;
109
110 /* the callout flags: */
111 int tme_sun_obie_callout_flags;
112
113 /* if our interrupt line is currently asserted: */
114 int tme_sun_obie_int_asserted;
115
116 /* it's easiest to just model the board registers as a chunk of memory: */
117 tme_uint8_t tme_sun_obie_regs[TME_SUN_OBIE_SIZ_REGS];
118
119 /* the i825x6 image of the CSR: */
120 tme_uint16_t tme_sun_obie_csr_i825x6;
121
122 #ifndef TME_NO_LOG
123 tme_uint16_t tme_sun_obie_last_log_csr;
124 #endif /* !TME_NO_LOG */
125 };
126
127 /* a sun_obie internal bus connection: */
128 struct tme_sun_obie_connection {
129
130 /* the external bus connection: */
131 struct tme_bus_connection tme_sun_obie_connection;
132
133 /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection
134 is for the registers: */
135 tme_uint8_t tme_sun_obie_connection_regs;
136 };
137
138 /* globals: */
139
140 /* our bus signals sets: */
141 static const struct tme_bus_signals _tme_sun_obie_bus_signals_generic = TME_BUS_SIGNALS_GENERIC;
142 static const struct tme_bus_signals _tme_sun_obie_bus_signals_i825x6 = TME_BUS_SIGNALS_I825X6;
143
144 /* the sun_obie callout function. it must be called with the mutex locked: */
145 static void
_tme_sun_obie_callout(struct tme_sun_obie * sun_obie,int new_callouts)146 _tme_sun_obie_callout(struct tme_sun_obie *sun_obie, int new_callouts)
147 {
148 struct tme_bus_connection *conn_i825x6;
149 struct tme_bus_connection *conn_bus;
150 tme_uint16_t csr, csr_diff;
151 unsigned int signal, level;
152 int callouts, later_callouts;
153 int rc;
154 int int_asserted;
155
156 /* add in any new callouts: */
157 sun_obie->tme_sun_obie_callout_flags |= new_callouts;
158
159 /* if this function is already running in another thread, simply
160 return now. the other thread will do our work: */
161 if (sun_obie->tme_sun_obie_callout_flags & TME_SUN_OBIE_CALLOUT_RUNNING) {
162 return;
163 }
164
165 /* callouts are now running: */
166 sun_obie->tme_sun_obie_callout_flags |= TME_SUN_OBIE_CALLOUT_RUNNING;
167
168 /* assume that we won't need any later callouts: */
169 later_callouts = 0;
170
171 /* loop while callouts are needed: */
172 for (; (callouts = sun_obie->tme_sun_obie_callout_flags) & TME_SUN_OBIE_CALLOUTS_MASK; ) {
173
174 /* clear the needed callouts: */
175 sun_obie->tme_sun_obie_callout_flags = callouts & ~TME_SUN_OBIE_CALLOUTS_MASK;
176 callouts &= TME_SUN_OBIE_CALLOUTS_MASK;
177
178 /* if we need to call out one or more signals to the i825x6: */
179 if (callouts & TME_SUN_OBIE_CALLOUT_SIGNALS) {
180
181 /* get the current CSR value: */
182 csr = TME_SUN_OBIE_CSR_GET(sun_obie);
183
184 /* get the next signal to call out to the i825x6: */
185 csr_diff = ((csr
186 ^ sun_obie->tme_sun_obie_csr_i825x6)
187 & (TME_SUN_OBIE_CSR_NORESET
188 | TME_SUN_OBIE_CSR_NOLOOP
189 | TME_SUN_OBIE_CSR_CA));
190 csr_diff = (csr_diff ^ (csr_diff - 1)) & csr_diff;
191
192 /* if there is a signal to call out: */
193 if (csr_diff != 0) {
194
195 /* assume that if the signal's bit is set in the CSR, it will
196 be asserted: */
197 level = csr & csr_diff;
198
199 /* assume that we're calling out an i825x6 signal: */
200 signal = (_tme_sun_obie_bus_signals_generic.tme_bus_signals_first
201 + TME_BUS_SIGNAL_X(_tme_sun_obie_bus_signals_generic.tme_bus_signals_count));
202
203 /* dispatch on the CSR bit: */
204 switch (csr_diff) {
205 default:
206 assert (FALSE);
207 case TME_SUN_OBIE_CSR_NORESET:
208 signal = TME_BUS_SIGNAL_RESET;
209 level = !level;
210 break;
211 case TME_SUN_OBIE_CSR_NOLOOP:
212 signal += TME_I825X6_SIGNAL_LOOP;
213 level = !level;
214 break;
215 case TME_SUN_OBIE_CSR_CA:
216 signal += TME_I825X6_SIGNAL_CA;
217 break;
218 }
219
220 /* create a real signal level value: */
221 level = (level
222 ? TME_BUS_SIGNAL_LEVEL_ASSERTED
223 : TME_BUS_SIGNAL_LEVEL_NEGATED);
224
225 /* get this card's i825x6 connection: */
226 conn_i825x6 = sun_obie->tme_sun_obie_conn_i825x6;
227
228 /* unlock the mutex: */
229 tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
230
231 /* do the callout: */
232 rc = (conn_i825x6 != NULL
233 ? ((*conn_i825x6->tme_bus_signal)
234 (conn_i825x6,
235 signal | level))
236 : TME_OK);
237
238 /* lock the mutex: */
239 tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
240
241 /* if the callout was unsuccessful, remember that at some later
242 time this callout should be attempted again: */
243 if (rc != TME_OK) {
244 later_callouts |= TME_SUN_OBIE_CALLOUT_SIGNALS;
245 }
246
247 /* otherwise, the callout was successful: */
248 else {
249
250 /* update the i825x6 image of the CSR: */
251 sun_obie->tme_sun_obie_csr_i825x6 =
252 ((sun_obie->tme_sun_obie_csr_i825x6 & ~csr_diff)
253 | (csr & csr_diff));
254
255 /* there may be more signals to call out, so attempt this
256 callout again now: */
257 sun_obie->tme_sun_obie_callout_flags |= TME_SUN_OBIE_CALLOUT_SIGNALS;
258 }
259 }
260 }
261
262 /* if we need to call out a possible change to our interrupt
263 signal: */
264 if (callouts & TME_SUN_OBIE_CALLOUT_INT) {
265
266 /* get the current CSR value: */
267 csr = TME_SUN_OBIE_CSR_GET(sun_obie);
268
269 /* see if the interrupt signal should be asserted or negated: */
270 int_asserted = ((csr & (TME_SUN_OBIE_CSR_IE
271 | TME_SUN_OBIE_CSR_INTR))
272 == (TME_SUN_OBIE_CSR_IE
273 | TME_SUN_OBIE_CSR_INTR));
274
275 /* if the interrupt signal doesn't already have the right state: */
276 if (!int_asserted != !sun_obie->tme_sun_obie_int_asserted) {
277
278 /* get our bus connection: */
279 conn_bus = sun_obie->tme_sun_obie_conn_regs;
280
281 /* unlock our mutex: */
282 tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
283
284 /* call out the bus interrupt signal edge: */
285 rc = (conn_bus != NULL
286 ? ((*conn_bus->tme_bus_signal)
287 (conn_bus,
288 TME_BUS_SIGNAL_INT_UNSPEC
289 | (int_asserted
290 ? TME_BUS_SIGNAL_LEVEL_ASSERTED
291 : TME_BUS_SIGNAL_LEVEL_NEGATED)))
292 : TME_OK);
293
294 /* lock our mutex: */
295 tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
296
297 /* if this callout was successful, note the new state of the
298 interrupt signal: */
299 if (rc == TME_OK) {
300 sun_obie->tme_sun_obie_int_asserted = int_asserted;
301 }
302
303 /* otherwise, remember that at some later time this callout
304 should be attempted again: */
305 else {
306 later_callouts |= TME_SUN_OBIE_CALLOUT_INT;
307 }
308 }
309 }
310 }
311
312 /* put in any later callouts, and clear that callouts are running: */
313 sun_obie->tme_sun_obie_callout_flags = later_callouts;
314 }
315
316 /* the sun_obie bus cycle handler for the board registers: */
317 static int
_tme_sun_obie_bus_cycle_regs(void * _sun_obie,struct tme_bus_cycle * cycle_init)318 _tme_sun_obie_bus_cycle_regs(void *_sun_obie,
319 struct tme_bus_cycle *cycle_init)
320 {
321 struct tme_sun_obie *sun_obie;
322 tme_uint16_t csr_old, csr_new, csr_diff;
323 int new_callouts;
324
325 /* recover our data structure: */
326 sun_obie = (struct tme_sun_obie *) _sun_obie;
327
328 /* assume we won't need any new callouts: */
329 new_callouts = 0;
330
331 /* lock the mutex: */
332 tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
333
334 /* get the previous CSR value: */
335 csr_old = TME_SUN_OBIE_CSR_GET(sun_obie);
336
337 /* run the cycle: */
338 tme_bus_cycle_xfer_memory(cycle_init,
339 sun_obie->tme_sun_obie_regs,
340 TME_SUN_OBIE_SIZ_REGS - 1);
341
342 /* get the current CSR value, and put back any bits that
343 software can't change: */
344 csr_new = ((TME_SUN_OBIE_CSR_GET(sun_obie)
345 & ~TME_SUN_OBIE_CSR_READONLY)
346 | (csr_old
347 & TME_SUN_OBIE_CSR_READONLY));
348 TME_SUN_OBIE_CSR_PUT(sun_obie, csr_new);
349
350 /* get the sets of CSR bits that have changed: */
351 csr_diff = (csr_old ^ csr_new);
352
353 /* if this is a NORESET, NOLOOP or CA change, possibly call out the
354 appropriate signal change to the i825x6: */
355 if (csr_diff & (TME_SUN_OBIE_CSR_NORESET
356 | TME_SUN_OBIE_CSR_NOLOOP
357 | TME_SUN_OBIE_CSR_CA)) {
358 new_callouts |= TME_SUN_OBIE_CALLOUT_SIGNALS;
359 }
360
361 /* if this is an interrupt mask change, possibly call out an
362 interrupt signal change to the bus: */
363 if (csr_diff & TME_SUN_OBIE_CSR_IE) {
364 new_callouts |= TME_SUN_OBIE_CALLOUT_INT;
365 }
366
367 #ifndef TME_NO_LOG
368 if (csr_new != sun_obie->tme_sun_obie_last_log_csr) {
369 sun_obie->tme_sun_obie_last_log_csr = csr_new;
370 tme_log(&sun_obie->tme_sun_obie_element->tme_element_log_handle,
371 1000, TME_OK,
372 (&sun_obie->tme_sun_obie_element->tme_element_log_handle,
373 "csr now 0x%04x",
374 csr_new));
375 }
376 #endif /* !TME_NO_LOG */
377
378 /* make any new callouts: */
379 _tme_sun_obie_callout(sun_obie, new_callouts);
380
381 /* unlock the mutex: */
382 tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
383
384 /* no faults: */
385 return (TME_OK);
386 }
387
388 /* the sun_obie bus signal handler: */
389 static int
_tme_sun_obie_bus_signal(struct tme_bus_connection * conn_bus,unsigned int signal)390 _tme_sun_obie_bus_signal(struct tme_bus_connection *conn_bus,
391 unsigned int signal)
392 {
393 struct tme_sun_obie *sun_obie;
394 tme_uint16_t csr;
395 int new_callouts;
396
397 /* return now if this is not a generic bus signal: */
398 if (TME_BUS_SIGNAL_INDEX(signal)
399 > _tme_sun_obie_bus_signals_generic.tme_bus_signals_count) {
400 return (TME_OK);
401 }
402
403 /* recover our data structures: */
404 sun_obie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
405
406 /* assume that we won't need any new callouts: */
407 new_callouts = TME_SUN_OBIE_CALLOUT_CHECK;
408
409 /* lock the mutex: */
410 tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
411
412 /* get the current CSR value: */
413 csr = TME_SUN_OBIE_CSR_GET(sun_obie);
414
415 /* if this bus signal is from the i825x6: */
416 if (conn_bus->tme_bus_connection.tme_connection_other
417 == &sun_obie->tme_sun_obie_conn_i825x6->tme_bus_connection) {
418
419 /* this must be the unspecified interrupt signal: */
420 assert (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_INT_UNSPEC);
421
422 /* update the CSR value: */
423 csr
424 = ((csr
425 & ~TME_SUN_OBIE_CSR_INTR)
426 | (((signal & TME_BUS_SIGNAL_LEVEL_MASK)
427 == TME_BUS_SIGNAL_LEVEL_ASSERTED)
428 ? TME_SUN_OBIE_CSR_INTR
429 : 0));
430
431 /* possibly call out an interrupt change to obio: */
432 new_callouts = TME_SUN_OBIE_CALLOUT_INT;
433 }
434
435 /* otherwise, this bus signal must be from obio: */
436 else {
437 assert (conn_bus->tme_bus_connection.tme_connection_other
438 == &sun_obie->tme_sun_obie_conn_regs->tme_bus_connection);
439
440 /* if this is the negating edge of the reset signal: */
441 if (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_RESET
442 && (signal & TME_BUS_SIGNAL_LEVEL_MASK) == TME_BUS_SIGNAL_LEVEL_NEGATED) {
443
444 /* update the CSR value: */
445 csr &= TME_SUN_OBIE_CSR_NOLOOP;
446
447 /* possibly call out bus signal changes to the i825x6: */
448 new_callouts = TME_SUN_OBIE_CALLOUT_SIGNALS;
449 }
450 }
451
452 /* put the new CSR value: */
453 TME_SUN_OBIE_CSR_PUT(sun_obie, csr);
454
455 /* make any new callouts: */
456 if (new_callouts != TME_SUN_OBIE_CALLOUT_CHECK) {
457 _tme_sun_obie_callout(sun_obie, new_callouts);
458 }
459
460 /* unlock the mutex: */
461 tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
462
463 return (TME_OK);
464 }
465
466 /* the sun_obie bus signals adder for the i825x6: */
467 static int
_tme_sun_obie_bus_signals_add(struct tme_bus_connection * conn_bus,struct tme_bus_signals * bus_signals_caller)468 _tme_sun_obie_bus_signals_add(struct tme_bus_connection *conn_bus,
469 struct tme_bus_signals *bus_signals_caller)
470 {
471 const struct tme_bus_signals *bus_signals;
472 tme_uint32_t signal_first;
473
474 /* we only support the generic and i825x6 bus signals: */
475 switch (bus_signals_caller->tme_bus_signals_id) {
476 case TME_BUS_SIGNALS_ID_GENERIC:
477 bus_signals = &_tme_sun_obie_bus_signals_generic;
478 signal_first = _tme_sun_obie_bus_signals_generic.tme_bus_signals_first;
479 break;
480 case TME_BUS_SIGNALS_ID_I825X6:
481 bus_signals = &_tme_sun_obie_bus_signals_i825x6;
482 signal_first = (_tme_sun_obie_bus_signals_generic.tme_bus_signals_first
483 + TME_BUS_SIGNAL_X(_tme_sun_obie_bus_signals_generic.tme_bus_signals_count));
484 break;
485 default:
486 return (ENOENT);
487 }
488
489 /* XXX we should check versions here: */
490 *bus_signals_caller = *bus_signals;
491 bus_signals_caller->tme_bus_signals_first = signal_first;
492 return (TME_OK);
493 }
494
495 /* the sun_obie TLB adder for the i825x6: */
496 static int
_tme_sun_obie_tlb_set_add(struct tme_bus_connection * conn_bus,struct tme_bus_tlb_set_info * tlb_set_info)497 _tme_sun_obie_tlb_set_add(struct tme_bus_connection *conn_bus,
498 struct tme_bus_tlb_set_info *tlb_set_info)
499 {
500 struct tme_sun_obie *sun_obie;
501
502 /* recover our data structures: */
503 sun_obie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
504
505 /* pass the i825x6's request through to the mainbus: */
506 conn_bus = sun_obie->tme_sun_obie_conn_memory;
507 return (conn_bus != NULL
508 ? (*conn_bus->tme_bus_tlb_set_add)(conn_bus,
509 tlb_set_info)
510 : ENXIO);
511 }
512
513 /* the sun_obie TLB filler for the memory: */
514 static int
_tme_sun_obie_tlb_fill(struct tme_bus_connection * conn_bus,struct tme_bus_tlb * tlb,tme_bus_addr_t address,unsigned int cycles)515 _tme_sun_obie_tlb_fill(struct tme_bus_connection *conn_bus,
516 struct tme_bus_tlb *tlb,
517 tme_bus_addr_t address,
518 unsigned int cycles)
519 {
520 struct tme_sun_obie *sun_obie;
521
522 /* the address must be within range: */
523 assert(address <= 0xffffff);
524
525 /* recover our data structures: */
526 sun_obie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
527
528 /* pass the i825x6's request through to the mainbus: */
529 conn_bus = sun_obie->tme_sun_obie_conn_memory;
530 return (conn_bus != NULL
531 ? (*conn_bus->tme_bus_tlb_fill)(conn_bus,
532 tlb,
533 address,
534 cycles)
535 : ENXIO);
536 }
537
538 /* the sun_obie TLB filler for the board registers: */
539 static int
_tme_sun_obie_tlb_fill_regs(struct tme_bus_connection * conn_bus,struct tme_bus_tlb * tlb,tme_bus_addr_t address,unsigned int cycles)540 _tme_sun_obie_tlb_fill_regs(struct tme_bus_connection *conn_bus,
541 struct tme_bus_tlb *tlb,
542 tme_bus_addr_t address, unsigned int cycles)
543 {
544 struct tme_sun_obie *sun_obie;
545
546 /* recover our data structures: */
547 sun_obie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
548
549 /* the address must be within range: */
550 assert(address < TME_SUN_OBIE_SIZ_CSR);
551
552 /* initialize the TLB entry: */
553 tme_bus_tlb_initialize(tlb);
554
555 /* this address falls in the CSR: */
556
557 /* this TLB entry covers this range: */
558 tlb->tme_bus_tlb_addr_first = TME_SUN_OBIE_REG_CSR;
559 tlb->tme_bus_tlb_addr_last = TME_SUN_OBIE_REG_CSR + TME_SUN_OBIE_SIZ_CSR - 1;
560
561 /* this TLB entry allows fast reading: */
562 tlb->tme_bus_tlb_emulator_off_read = sun_obie->tme_sun_obie_regs;
563
564 /* allow reading and writing: */
565 tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
566
567 /* our bus cycle handler: */
568 tlb->tme_bus_tlb_cycle_private = sun_obie;
569 tlb->tme_bus_tlb_cycle = _tme_sun_obie_bus_cycle_regs;
570
571 return (TME_OK);
572 }
573
574 /* this scores a new connection: */
575 static int
_tme_sun_obie_connection_score(struct tme_connection * conn,unsigned int * _score)576 _tme_sun_obie_connection_score(struct tme_connection *conn, unsigned int *_score)
577 {
578 struct tme_sun_obie *sun_obie;
579 struct tme_sun_obie_connection *conn_sun_obie;
580
581 /* both sides must be generic bus connections: */
582 assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
583 assert(conn->tme_connection_other->tme_connection_type
584 == conn->tme_connection_type);
585
586 /* recover our data structures: */
587 sun_obie = conn->tme_connection_element->tme_element_private;
588 conn_sun_obie = (struct tme_sun_obie_connection *)conn;
589
590 /* this is a generic bus connection, so just score it nonzero and
591 return. note that there's no good way to differentiate a
592 connection to a bus from a connection to just another chip, so we
593 always return a nonzero score here: */
594 *_score = 1;
595 return (TME_OK);
596 }
597
598 /* this makes a new connection: */
599 static int
_tme_sun_obie_connection_make(struct tme_connection * conn,unsigned int state)600 _tme_sun_obie_connection_make(struct tme_connection *conn, unsigned int state)
601 {
602 struct tme_sun_obie *sun_obie;
603 struct tme_sun_obie_connection *conn_sun_obie;
604 struct tme_bus_connection *conn_bus;
605
606 /* both sides must be generic bus connections: */
607 assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
608 assert(conn->tme_connection_other->tme_connection_type
609 == conn->tme_connection_type);
610
611 /* recover our data structures: */
612 sun_obie = conn->tme_connection_element->tme_element_private;
613 conn_sun_obie = (struct tme_sun_obie_connection *)conn;
614 conn_bus = &conn_sun_obie->tme_sun_obie_connection;
615
616 /* we're always set up to answer calls across the connection, so we
617 only have to do work when the connection has gone full, namely
618 taking the other side of the connection: */
619 if (state == TME_CONNECTION_FULL) {
620
621 /* lock our mutex: */
622 tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
623
624 /* save our connection: */
625 if (conn_bus->tme_bus_signals_add != NULL) {
626 sun_obie->tme_sun_obie_conn_i825x6 = (struct tme_bus_connection *) conn->tme_connection_other;
627 }
628 else if (conn_sun_obie->tme_sun_obie_connection_regs) {
629 sun_obie->tme_sun_obie_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other;
630 }
631 else {
632 sun_obie->tme_sun_obie_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other;
633 }
634
635 /* unlock our mutex: */
636 tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
637 }
638
639 return (TME_OK);
640 }
641
642 /* this breaks a connection: */
643 static int
_tme_sun_obie_connection_break(struct tme_connection * conn,unsigned int state)644 _tme_sun_obie_connection_break(struct tme_connection *conn, unsigned int state)
645 {
646 abort();
647 }
648
649 /* this makes a new connection side for a sun_obie: */
650 static int
_tme_sun_obie_connections_new(struct tme_element * element,const char * const * args,struct tme_connection ** _conns,char ** _output)651 _tme_sun_obie_connections_new(struct tme_element *element,
652 const char * const *args,
653 struct tme_connection **_conns,
654 char **_output)
655 {
656 struct tme_sun_obie *sun_obie;
657 struct tme_sun_obie_connection *conn_sun_obie;
658 struct tme_bus_connection *conn_bus;
659 struct tme_connection *conn;
660 unsigned int i825x6;
661 tme_uint8_t regs;
662 int usage;
663 int rc;
664
665 /* recover our data structure: */
666 sun_obie = (struct tme_sun_obie *) element->tme_element_private;
667
668 /* we don't bother locking the mutex simply to check if connections
669 already exist: */
670
671 /* check our arguments: */
672 usage = FALSE;
673 rc = 0;
674 i825x6 = FALSE;
675 regs = FALSE;
676
677 /* if this connection is for the registers: */
678 if (TME_ARG_IS(args[1], "csr")) {
679
680 /* if we already have a register connection, complain: */
681 if (sun_obie->tme_sun_obie_conn_regs != NULL) {
682 rc = EEXIST;
683 }
684
685 /* otherwise, make the new connection: */
686 else {
687 regs = TRUE;
688 }
689 }
690
691 /* else, if this connection is for the memory: */
692 else if (TME_ARG_IS(args[1], "memory")) {
693
694 /* if we already have a memory connection, complain: */
695 if (sun_obie->tme_sun_obie_conn_memory != NULL) {
696 rc = EEXIST;
697 }
698 }
699
700 /* else, the connection must be for the i825x6: */
701 else if (args[1] == NULL) {
702
703 /* if we already have an i825x6 connection, complain: */
704 if (sun_obie->tme_sun_obie_conn_i825x6 != NULL) {
705 rc = EEXIST;
706 }
707
708 /* otherwise, make the new conection: */
709 else {
710 i825x6 = TRUE;
711 }
712 }
713
714 /* otherwise, this is a bad argument: */
715 else {
716 tme_output_append_error(_output,
717 "%s %s, ",
718 args[1],
719 _("unexpected"));
720 usage = TRUE;
721 }
722
723 if (usage) {
724 tme_output_append_error(_output,
725 "%s %s [ csr | memory ]",
726 _("usage:"),
727 args[0]);
728 rc = EINVAL;
729 }
730
731 if (rc) {
732 return (rc);
733 }
734
735 /* make a new connection: */
736 conn_sun_obie = tme_new0(struct tme_sun_obie_connection, 1);
737 conn_bus = &conn_sun_obie->tme_sun_obie_connection;
738 conn = &conn_bus->tme_bus_connection;
739
740 /* fill in the generic connection: */
741 conn->tme_connection_next = *_conns;
742 conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
743 conn->tme_connection_score = _tme_sun_obie_connection_score;
744 conn->tme_connection_make = _tme_sun_obie_connection_make;
745 conn->tme_connection_break = _tme_sun_obie_connection_break;
746
747 /* fill in the generic bus connection: */
748 conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0;
749 conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL;
750 if (i825x6) {
751 conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0xffffff;
752 conn_bus->tme_bus_signals_add = _tme_sun_obie_bus_signals_add;
753 conn_bus->tme_bus_signal = _tme_sun_obie_bus_signal;
754 conn_bus->tme_bus_tlb_set_add = _tme_sun_obie_tlb_set_add;
755 conn_bus->tme_bus_tlb_fill = _tme_sun_obie_tlb_fill;
756 }
757 else if (regs) {
758 conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_OBIE_SIZ_REGS - 1;
759 conn_bus->tme_bus_signal = _tme_sun_obie_bus_signal;
760 conn_bus->tme_bus_tlb_fill = _tme_sun_obie_tlb_fill_regs;
761 }
762 else {
763 conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0;
764 }
765
766 /* fill in the internal information: */
767 conn_sun_obie->tme_sun_obie_connection_regs = regs;
768
769 /* return the connection side possibility: */
770 *_conns = conn;
771 return (TME_OK);
772 }
773
774 /* the new sun_obie function: */
775 int
tme_sun_obie(struct tme_element * element,const char * const * args,char ** _output)776 tme_sun_obie(struct tme_element *element, const char * const *args, char **_output)
777 {
778 struct tme_sun_obie *sun_obie;
779 int arg_i;
780 int usage;
781
782 /* check our arguments: */
783 usage = 0;
784 arg_i = 1;
785 for (;;) {
786
787 if (0) {
788 }
789
790 /* if we ran out of arguments: */
791 else if (args[arg_i] == NULL) {
792
793 break;
794 }
795
796 /* otherwise this is a bad argument: */
797 else {
798 tme_output_append_error(_output,
799 "%s %s, ",
800 args[arg_i],
801 _("unexpected"));
802 usage = TRUE;
803 break;
804 }
805 }
806
807 if (usage) {
808 tme_output_append_error(_output,
809 "%s %s",
810 _("usage:"),
811 args[0]);
812 return (EINVAL);
813 }
814
815 /* start the sun_obie structure: */
816 sun_obie = tme_new0(struct tme_sun_obie, 1);
817 sun_obie->tme_sun_obie_element = element;
818 TME_SUN_OBIE_CSR_PUT(sun_obie,
819 (TME_SUN_OBIE_CSR_NORESET
820 | TME_SUN_OBIE_CSR_NOLOOP));
821 tme_mutex_init(&sun_obie->tme_sun_obie_mutex);
822 tme_rwlock_init(&sun_obie->tme_sun_obie_rwlock);
823
824 /* fill the element: */
825 element->tme_element_private = sun_obie;
826 element->tme_element_connections_new = _tme_sun_obie_connections_new;
827
828 return (TME_OK);
829 }
830