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