1 /* $Id: sun-mie.c,v 1.4 2010/06/05 13:57:27 fredette Exp $ */
2 
3 /* bus/multibus/sun_mie.c - implementation of the Sun Intel Ethernet Multibus emulation: */
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: sun-mie.c,v 1.4 2010/06/05 13:57:27 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 
48 /* macros: */
49 
50 /* the amount of memory on the board: */
51 #define TME_SUN_MIE_MEMSIZE	(256 * 1024)
52 
53 /* the board page size: */
54 #define TME_SUN_MIE_PAGESIZE	(1024)
55 
56 /* the number of page map entries: */
57 #define TME_SUN_MIE_PGMAP_COUNT	(1024)
58 
59 /* the number of active TLB entries we can have per page map entry: */
60 #define TME_SUN_MIE_PGMAP_TLBS	(4)
61 
62 /* register offsets and sizes: */
63 #define TME_SUN_MIE_REG_PGMAP	(0)
64 #define TME_SUN_MIE_SIZ_PGMAP	(TME_SUN_MIE_PGMAP_COUNT * sizeof(tme_uint16_t))
65 #define TME_SUN_MIE_REG_PROM	(TME_SUN_MIE_REG_PGMAP + TME_SUN_MIE_SIZ_PGMAP)
66 #define TME_SUN_MIE_SIZ_PROM	(32 * sizeof(tme_uint16_t))
67 #define TME_SUN_MIE_REG_CSR	(TME_SUN_MIE_REG_PROM + TME_SUN_MIE_SIZ_PROM)
68 #define TME_SUN_MIE_SIZ_CSR	(sizeof(tme_uint16_t))
69 #define TME_SUN_MIE_REG_PCR	(TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR + sizeof(tme_uint16_t))
70 #define TME_SUN_MIE_SIZ_PCR	(sizeof(tme_uint16_t))
71 #define TME_SUN_MIE_REG_PE_ALO	(TME_SUN_MIE_REG_PCR + TME_SUN_MIE_SIZ_PCR)
72 #define TME_SUN_MIE_SIZ_PE_ALO	(sizeof(tme_uint16_t))
73 #define TME_SUN_MIE_SIZ_REGS	(TME_SUN_MIE_REG_PE_ALO + TME_SUN_MIE_SIZ_PE_ALO)
74 
75 /* the bits in a pagemap entry: */
76 #define TME_SUN_MIE_PGMAP_SWAB	(0x8000)
77 				/* 0x4000 unused */
78 #define TME_SUN_MIE_PGMAP_P2MEM	(0x2000)
79 				/* 0x1000 unused */
80 #define TME_SUN_MIE_PGMAP_PFNUM	(0x0fff)
81 
82 /* the bits in the Control/Status Register: */
83 #define TME_SUN_MIE_CSR_RESET	(0x8000)
84 #define TME_SUN_MIE_CSR_NOLOOP	(0x4000)
85 #define TME_SUN_MIE_CSR_CA	(0x2000)
86 #define TME_SUN_MIE_CSR_IE	(0x1000)
87 #define TME_SUN_MIE_CSR_PIE	(0x0800)
88 				/* 0x0400 unused */
89 #define TME_SUN_MIE_CSR_PE	(0x0200)
90 #define TME_SUN_MIE_CSR_INTR	(0x0100)
91 				/* 0x0080 unused */
92 				/* 0x0040 unused */
93 #define TME_SUN_MIE_CSR_P2MEM	(0x0020)
94 #define TME_SUN_MIE_CSR_BIGRAM	(0x0010)
95 #define TME_SUN_MIE_CSR_MPMHI	(0x000f)
96 #define TME_SUN_MIE_CSR_READONLY	(0x0400			\
97 					 | TME_SUN_MIE_CSR_PE	\
98 					 | TME_SUN_MIE_CSR_INTR	\
99 					 | 0x0080		\
100 					 | 0x0040		\
101 					 | TME_SUN_MIE_CSR_BIGRAM\
102 					 | TME_SUN_MIE_CSR_MPMHI)
103 
104 /* the bits in the Parity Control Register: */
105 #define TME_SUN_MIE_PCR_PEACK	(0x0100)
106 #define TME_SUN_MIE_PCR_PESRC	(0x0080)
107 #define TME_SUN_MIE_PCR_PEBYTE	(0x0040)
108 				/* 0x0020 unused */
109 				/* 0x0010 unused */
110 #define TME_SUN_MIE_PCR_PE_AHI	(0x000f)
111 #define TME_SUN_MIE_PCR_READONLY	(~TME_SUN_MIE_PCR_PEACK)
112 
113 /* the size of the memory port: */
114 #define TME_SUN_MIE_SIZ_MBM	(0x10000)
115 
116 /* these get and put the CSR: */
117 #define TME_SUN_MIE_CSR_GET(sun_mie)	\
118   tme_betoh_u16(*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_CSR]))
119 #define TME_SUN_MIE_CSR_PUT(sun_mie, csr)	\
120   (*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_CSR]) = tme_htobe_u16(csr))
121 
122 /* these get and put the PCR: */
123 #define TME_SUN_MIE_PCR_GET(sun_mie)	\
124   tme_betoh_u16(*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_PCR]))
125 #define TME_SUN_MIE_PCR_PUT(sun_mie, pcr)	\
126   (*((tme_uint16_t *) &(sun_mie)->tme_sun_mie_regs[TME_SUN_MIE_REG_PCR]) = tme_htobe_u16(pcr))
127 
128 /* the callout flags: */
129 #define TME_SUN_MIE_CALLOUT_CHECK	(0)
130 #define TME_SUN_MIE_CALLOUT_RUNNING	TME_BIT(0)
131 #define TME_SUN_MIE_CALLOUTS_MASK	(-2)
132 #define  TME_SUN_MIE_CALLOUT_SIGNALS	TME_BIT(1)
133 #define	 TME_SUN_MIE_CALLOUT_INT	TME_BIT(2)
134 
135 /* structures: */
136 
137 /* the card: */
138 struct tme_sun_mie {
139 
140   /* backpointer to our element: */
141   struct tme_element *tme_sun_mie_element;
142 
143   /* the mutex protecting the card: */
144   tme_mutex_t tme_sun_mie_mutex;
145 
146   /* the rwlock protecting the card: */
147   tme_rwlock_t tme_sun_mie_rwlock;
148 
149   /* the bus connection for the card's registers: */
150   struct tme_bus_connection *tme_sun_mie_conn_regs;
151 
152   /* the bus connection for the card's memory: */
153   struct tme_bus_connection *tme_sun_mie_conn_memory;
154 
155   /* the bus connection for the card's i825x6 chip: */
156   struct tme_bus_connection *tme_sun_mie_conn_i825x6;
157 
158   /* the callout flags: */
159   int tme_sun_mie_callout_flags;
160 
161   /* if our interrupt line is currently asserted: */
162   int tme_sun_mie_int_asserted;
163 
164   /* it's easiest to just model the board registers as a chunk of memory: */
165   tme_uint8_t tme_sun_mie_regs[TME_SUN_MIE_SIZ_REGS];
166 
167   /* the board memory really is a chunk of memory: */
168   tme_uint8_t tme_sun_mie_memory[TME_SUN_MIE_MEMSIZE];
169 
170   /* the active TLB entries for each page map entry on the board: */
171   struct tme_token *tme_sun_mie_tlb_tokens[TME_SUN_MIE_PGMAP_COUNT * TME_SUN_MIE_PGMAP_TLBS];
172   unsigned int tme_sun_mie_tlb_head[TME_SUN_MIE_PGMAP_COUNT];
173 
174   /* the i825x6 image of the CSR: */
175   tme_uint16_t tme_sun_mie_csr_i825x6;
176 
177 #ifndef TME_NO_LOG
178   tme_uint16_t tme_sun_mie_last_log_csr;
179 #endif /* !TME_NO_LOG */
180 };
181 
182 /* a sun_mie internal bus connection: */
183 struct tme_sun_mie_connection {
184 
185   /* the external bus connection: */
186   struct tme_bus_connection tme_sun_mie_connection;
187 
188   /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection
189      is for the registers: */
190   tme_uint8_t tme_sun_mie_connection_regs;
191 
192   /* if this connection is for the memory port, this is the high
193      nibble (A19..A16) of that port's connection: */
194   tme_uint8_t tme_sun_mie_connection_mpmhi;
195 };
196 
197 /* globals: */
198 
199 /* our bus signals sets: */
200 static const struct tme_bus_signals _tme_sun_mie_bus_signals_generic = TME_BUS_SIGNALS_GENERIC;
201 static const struct tme_bus_signals _tme_sun_mie_bus_signals_i825x6 = TME_BUS_SIGNALS_I825X6;
202 
203 /* the sun_mie callout function.  it must be called with the mutex locked: */
204 static void
_tme_sun_mie_callout(struct tme_sun_mie * sun_mie,int new_callouts)205 _tme_sun_mie_callout(struct tme_sun_mie *sun_mie, int new_callouts)
206 {
207   struct tme_bus_connection *conn_i825x6;
208   struct tme_bus_connection *conn_bus;
209   tme_uint16_t csr, csr_diff;
210   unsigned int signal, level;
211   int callouts, later_callouts;
212   int rc;
213   int int_asserted;
214 
215   /* add in any new callouts: */
216   sun_mie->tme_sun_mie_callout_flags |= new_callouts;
217 
218   /* if this function is already running in another thread, simply
219      return now.  the other thread will do our work: */
220   if (sun_mie->tme_sun_mie_callout_flags & TME_SUN_MIE_CALLOUT_RUNNING) {
221     return;
222   }
223 
224   /* callouts are now running: */
225   sun_mie->tme_sun_mie_callout_flags |= TME_SUN_MIE_CALLOUT_RUNNING;
226 
227   /* assume that we won't need any later callouts: */
228   later_callouts = 0;
229 
230   /* loop while callouts are needed: */
231   for (; (callouts = sun_mie->tme_sun_mie_callout_flags) & TME_SUN_MIE_CALLOUTS_MASK; ) {
232 
233     /* clear the needed callouts: */
234     sun_mie->tme_sun_mie_callout_flags = callouts & ~TME_SUN_MIE_CALLOUTS_MASK;
235     callouts &= TME_SUN_MIE_CALLOUTS_MASK;
236 
237     /* if we need to call out one or more signals to the i825x6: */
238     if (callouts & TME_SUN_MIE_CALLOUT_SIGNALS) {
239 
240       /* get the current CSR value: */
241       csr = TME_SUN_MIE_CSR_GET(sun_mie);
242 
243       /* get the next signal to call out to the i825x6: */
244       csr_diff = ((csr
245 		   ^ sun_mie->tme_sun_mie_csr_i825x6)
246 		  & (TME_SUN_MIE_CSR_RESET
247 		     | TME_SUN_MIE_CSR_NOLOOP
248 		     | TME_SUN_MIE_CSR_CA));
249       csr_diff = (csr_diff ^ (csr_diff - 1)) & csr_diff;
250 
251       /* if there is a signal to call out: */
252       if (csr_diff != 0) {
253 
254 	/* assume that if the signal's bit is set in the CSR, it will
255 	   be asserted: */
256 	level = csr & csr_diff;
257 
258 	/* assume that we're calling out an i825x6 signal: */
259 	signal = (_tme_sun_mie_bus_signals_generic.tme_bus_signals_first
260 		  + TME_BUS_SIGNAL_X(_tme_sun_mie_bus_signals_generic.tme_bus_signals_count));
261 
262 	/* dispatch on the CSR bit: */
263 	switch (csr_diff) {
264 	default:
265 	  assert (FALSE);
266 	case TME_SUN_MIE_CSR_RESET:
267 	  signal = TME_BUS_SIGNAL_RESET;
268 	  break;
269 	case TME_SUN_MIE_CSR_NOLOOP:
270 	  signal += TME_I825X6_SIGNAL_LOOP;
271 	  level = !level;
272 	  break;
273 	case TME_SUN_MIE_CSR_CA:
274 	  signal += TME_I825X6_SIGNAL_CA;
275 	  break;
276 	}
277 
278 	/* create a real signal level value: */
279 	level = (level
280 		 ? TME_BUS_SIGNAL_LEVEL_ASSERTED
281 		 : TME_BUS_SIGNAL_LEVEL_NEGATED);
282 
283 	/* get this card's i825x6 connection: */
284 	conn_i825x6 = sun_mie->tme_sun_mie_conn_i825x6;
285 
286 	/* unlock the mutex: */
287 	tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex);
288 
289 	/* do the callout: */
290 	rc = (conn_i825x6 != NULL
291 	      ? ((*conn_i825x6->tme_bus_signal)
292 		 (conn_i825x6,
293 		  signal | level))
294 	      : TME_OK);
295 
296 	/* lock the mutex: */
297 	tme_mutex_lock(&sun_mie->tme_sun_mie_mutex);
298 
299 	/* if the callout was unsuccessful, remember that at some later
300 	   time this callout should be attempted again: */
301 	if (rc != TME_OK) {
302 	  later_callouts |= TME_SUN_MIE_CALLOUT_SIGNALS;
303 	}
304 
305 	/* otherwise, the callout was successful: */
306 	else {
307 
308 	  /* update the i825x6 image of the CSR: */
309 	  sun_mie->tme_sun_mie_csr_i825x6 =
310 	    ((sun_mie->tme_sun_mie_csr_i825x6 & ~csr_diff)
311 	     | (csr & csr_diff));
312 
313 	  /* there may be more signals to call out, so attempt this
314              callout again now: */
315 	  sun_mie->tme_sun_mie_callout_flags |= TME_SUN_MIE_CALLOUT_SIGNALS;
316 	}
317       }
318     }
319 
320     /* if we need to call out a possible change to our interrupt
321        signal: */
322     if (callouts & TME_SUN_MIE_CALLOUT_INT) {
323 
324       /* get the current CSR value: */
325       csr = TME_SUN_MIE_CSR_GET(sun_mie);
326 
327       /* see if the interrupt signal should be asserted or negated: */
328       int_asserted = ((csr & (TME_SUN_MIE_CSR_IE
329 			      | TME_SUN_MIE_CSR_INTR))
330 		      == (TME_SUN_MIE_CSR_IE
331 			  | TME_SUN_MIE_CSR_INTR));
332 
333       /* if the interrupt signal doesn't already have the right state: */
334       if (!int_asserted != !sun_mie->tme_sun_mie_int_asserted) {
335 
336 	/* get our bus connection: */
337 	conn_bus = sun_mie->tme_sun_mie_conn_regs;
338 
339 	/* unlock our mutex: */
340 	tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex);
341 
342 	/* call out the bus interrupt signal edge: */
343 	rc = (conn_bus != NULL
344 	      ? ((*conn_bus->tme_bus_signal)
345 		 (conn_bus,
346 		  TME_BUS_SIGNAL_INT_UNSPEC
347 		  | (int_asserted
348 		     ? TME_BUS_SIGNAL_LEVEL_ASSERTED
349 		     : TME_BUS_SIGNAL_LEVEL_NEGATED)))
350 	      : TME_OK);
351 
352 	/* lock our mutex: */
353 	tme_mutex_lock(&sun_mie->tme_sun_mie_mutex);
354 
355 	/* if this callout was successful, note the new state of the
356 	   interrupt signal: */
357 	if (rc == TME_OK) {
358 	  sun_mie->tme_sun_mie_int_asserted = int_asserted;
359 	}
360 
361 	/* otherwise, remember that at some later time this callout
362 	   should be attempted again: */
363 	else {
364 	  later_callouts |= TME_SUN_MIE_CALLOUT_INT;
365 	}
366       }
367     }
368   }
369 
370   /* put in any later callouts, and clear that callouts are running: */
371   sun_mie->tme_sun_mie_callout_flags = later_callouts;
372 }
373 
374 /* the sun_mie bus cycle handler for the board memory: */
375 static int
_tme_sun_mie_bus_cycle(void * _sun_mie,struct tme_bus_cycle * cycle_init)376 _tme_sun_mie_bus_cycle(void *_sun_mie,
377 		       struct tme_bus_cycle *cycle_init)
378 {
379   struct tme_sun_mie *sun_mie;
380 
381   /* recover our data structure: */
382   sun_mie = (struct tme_sun_mie *) _sun_mie;
383 
384   /* run the cycle: */
385   tme_bus_cycle_xfer_memory(cycle_init,
386 			    sun_mie->tme_sun_mie_memory,
387 			    TME_SUN_MIE_MEMSIZE - 1);
388 
389   /* no faults: */
390   return (TME_OK);
391 }
392 
393 /* the sun_mie bus cycle handler for the board registers: */
394 static int
_tme_sun_mie_bus_cycle_regs(void * _sun_mie,struct tme_bus_cycle * cycle_init)395 _tme_sun_mie_bus_cycle_regs(void *_sun_mie,
396 			    struct tme_bus_cycle *cycle_init)
397 {
398   struct tme_sun_mie *sun_mie;
399   unsigned int pgmap_i;
400   unsigned int pgmap_j;
401   unsigned int tlb_i;
402   unsigned int tlb_j;
403   tme_uint16_t csr_old, csr_new, csr_diff;
404   tme_uint16_t pcr_old, pcr_new, pcr_diff;
405   int new_callouts;
406 
407   /* recover our data structure: */
408   sun_mie = (struct tme_sun_mie *) _sun_mie;
409 
410   /* assume we won't need any new callouts: */
411   new_callouts = 0;
412 
413   /* lock the mutex: */
414   tme_mutex_lock(&sun_mie->tme_sun_mie_mutex);
415 
416   /* if this is a write cycle and the address falls within one or more
417      page map entries, invalidate the TLBs associated with those
418      entries: */
419   if ((cycle_init->tme_bus_cycle_type
420        & TME_BUS_CYCLE_WRITE)
421       && (TME_SUN_MIE_REG_PGMAP
422 	  <= cycle_init->tme_bus_cycle_address)
423       && (cycle_init->tme_bus_cycle_address
424 	  < (TME_SUN_MIE_REG_PGMAP
425 	     + TME_SUN_MIE_SIZ_PGMAP))) {
426 
427     /* get the range of page map entries: */
428     pgmap_i
429       = (cycle_init->tme_bus_cycle_address
430 	 / sizeof(tme_uint16_t));
431     pgmap_j
432       = ((cycle_init->tme_bus_cycle_address
433 	  + cycle_init->tme_bus_cycle_size
434 	  + sizeof(tme_uint16_t)
435 	  - 1)
436 	 / sizeof(tme_uint16_t));
437     pgmap_j = TME_MIN(pgmap_j, TME_SUN_MIE_PGMAP_COUNT);
438 
439     /* get the range of TLB handles: */
440     tlb_i = pgmap_i * TME_SUN_MIE_PGMAP_TLBS;
441     tlb_j = pgmap_j * TME_SUN_MIE_PGMAP_TLBS;
442 
443     /* invalidate the TLB entries: */
444     for (; tlb_i < tlb_j; tlb_i++) {
445       if (sun_mie->tme_sun_mie_tlb_tokens[tlb_i] != NULL) {
446 	tme_token_invalidate(sun_mie->tme_sun_mie_tlb_tokens[tlb_i]);
447 	sun_mie->tme_sun_mie_tlb_tokens[tlb_i] = NULL;
448       }
449     }
450   }
451 
452   /* get the previous CSR and PCR values: */
453   csr_old = TME_SUN_MIE_CSR_GET(sun_mie);
454   pcr_old = TME_SUN_MIE_PCR_GET(sun_mie);
455 
456   /* unless this address falls within the PROM, run the cycle: */
457   if ((cycle_init->tme_bus_cycle_address
458        < TME_SUN_MIE_REG_PROM)
459       || (cycle_init->tme_bus_cycle_address
460 	  >= (TME_SUN_MIE_REG_PROM
461 	      + TME_SUN_MIE_SIZ_PROM))) {
462     tme_bus_cycle_xfer_memory(cycle_init,
463 			      sun_mie->tme_sun_mie_regs,
464 			      TME_SUN_MIE_SIZ_REGS - 1);
465   }
466 
467   /* get the current CSR and PCR values, and put back any bits that
468      software can't change: */
469   csr_new = ((TME_SUN_MIE_CSR_GET(sun_mie)
470 	      & ~TME_SUN_MIE_CSR_READONLY)
471 	     | (csr_old
472 		& TME_SUN_MIE_CSR_READONLY));
473   TME_SUN_MIE_CSR_PUT(sun_mie, csr_new);
474   pcr_new = ((TME_SUN_MIE_PCR_GET(sun_mie)
475 	      & ~TME_SUN_MIE_PCR_READONLY)
476 	     | (pcr_old
477 		& TME_SUN_MIE_PCR_READONLY));
478   TME_SUN_MIE_PCR_PUT(sun_mie, pcr_new);
479 
480   /* get the sets of CSR and PCR bits that have changed: */
481   csr_diff = (csr_old ^ csr_new);
482   pcr_diff = (pcr_old ^ pcr_new);
483 
484   /* if this is a RESET, NOLOOP or CA change, possibly call out the
485      appropriate signal change to the i825x6: */
486   if (csr_diff & (TME_SUN_MIE_CSR_RESET
487 		  | TME_SUN_MIE_CSR_NOLOOP
488 		  | TME_SUN_MIE_CSR_CA)) {
489     new_callouts |= TME_SUN_MIE_CALLOUT_SIGNALS;
490   }
491 
492   /* if this is an interrupt mask change, possibly call out an
493      interrupt signal change to the bus: */
494   if (csr_diff & TME_SUN_MIE_CSR_IE) {
495     new_callouts |= TME_SUN_MIE_CALLOUT_INT;
496   }
497 
498   /* abort on any attempt to enable the P2 bus: */
499   if (csr_new & TME_SUN_MIE_CSR_P2MEM) {
500     abort ();
501   }
502 
503   /* if this is acknowledging a parity error: */
504   if (pcr_diff & TME_SUN_MIE_PCR_PEACK) {
505     /* nothing to do */
506   }
507 
508 #ifndef TME_NO_LOG
509   if (csr_new != sun_mie->tme_sun_mie_last_log_csr) {
510     sun_mie->tme_sun_mie_last_log_csr = csr_new;
511     tme_log(&sun_mie->tme_sun_mie_element->tme_element_log_handle,
512 	    1000, TME_OK,
513 	    (&sun_mie->tme_sun_mie_element->tme_element_log_handle,
514 	     "csr now 0x%04x",
515 	     csr_new));
516   }
517 #endif /* !TME_NO_LOG */
518 
519   /* make any new callouts: */
520   _tme_sun_mie_callout(sun_mie, new_callouts);
521 
522   /* unlock the mutex: */
523   tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex);
524 
525   /* no faults: */
526   return (TME_OK);
527 }
528 
529 /* the sun_mie bus signal handler: */
530 static int
_tme_sun_mie_bus_signal(struct tme_bus_connection * conn_bus,unsigned int signal)531 _tme_sun_mie_bus_signal(struct tme_bus_connection *conn_bus,
532 			unsigned int signal)
533 {
534   struct tme_sun_mie *sun_mie;
535 
536   /* return now if this is not a generic bus signal: */
537   if (TME_BUS_SIGNAL_INDEX(signal)
538       > _tme_sun_mie_bus_signals_generic.tme_bus_signals_count) {
539     return (TME_OK);
540   }
541 
542   /* recover our data structures: */
543   sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
544 
545   /* since this function is currently only given to the i825x6,
546      just copy its signal through to the Multibus: */
547   conn_bus = sun_mie->tme_sun_mie_conn_regs;
548   return ((*conn_bus->tme_bus_signal)(conn_bus, signal));
549 }
550 
551 /* the sun_mie bus signals adder for the i825x6: */
552 static int
_tme_sun_mie_bus_signals_add(struct tme_bus_connection * conn_bus,struct tme_bus_signals * bus_signals_caller)553 _tme_sun_mie_bus_signals_add(struct tme_bus_connection *conn_bus,
554 			     struct tme_bus_signals *bus_signals_caller)
555 {
556   const struct tme_bus_signals *bus_signals;
557   tme_uint32_t signal_first;
558 
559   /* we only support the generic and i825x6 bus signals: */
560   switch (bus_signals_caller->tme_bus_signals_id) {
561   case TME_BUS_SIGNALS_ID_GENERIC:
562     bus_signals = &_tme_sun_mie_bus_signals_generic;
563     signal_first = _tme_sun_mie_bus_signals_generic.tme_bus_signals_first;
564     break;
565   case TME_BUS_SIGNALS_ID_I825X6:
566     bus_signals = &_tme_sun_mie_bus_signals_i825x6;
567     signal_first = (_tme_sun_mie_bus_signals_generic.tme_bus_signals_first
568 		    + TME_BUS_SIGNAL_X(_tme_sun_mie_bus_signals_generic.tme_bus_signals_count));
569     break;
570   default:
571     return (ENOENT);
572   }
573 
574   /* XXX we should check versions here: */
575   *bus_signals_caller = *bus_signals;
576   bus_signals_caller->tme_bus_signals_first = signal_first;
577   return (TME_OK);
578 }
579 
580 /* the sun_mie TLB adder for the i825x6: */
581 static int
_tme_sun_mie_tlb_set_add(struct tme_bus_connection * conn_bus,struct tme_bus_tlb_set_info * tlb_set_info)582 _tme_sun_mie_tlb_set_add(struct tme_bus_connection *conn_bus,
583 			 struct tme_bus_tlb_set_info *tlb_set_info)
584 {
585 
586   /* if this TLB set provides a bus context register: */
587   if (tlb_set_info->tme_bus_tlb_set_info_bus_context != NULL) {
588 
589     /* this bus only has one context: */
590     (*tlb_set_info->tme_bus_tlb_set_info_bus_context) = 0;
591     tlb_set_info->tme_bus_tlb_set_info_bus_context_max = 0;
592   }
593 
594   return (TME_OK);
595 }
596 
597 /* the sun_mie TLB filler for the board memory: */
598 static int
_tme_sun_mie_tlb_fill(struct tme_bus_connection * conn_bus,struct tme_bus_tlb * tlb,tme_bus_addr_t address_wider,unsigned int cycles)599 _tme_sun_mie_tlb_fill(struct tme_bus_connection *conn_bus,
600 		      struct tme_bus_tlb *tlb,
601 		      tme_bus_addr_t address_wider,
602 		      unsigned int cycles)
603 {
604   struct tme_sun_mie *sun_mie;
605   tme_bus_addr32_t address;
606   unsigned int pgmap_i;
607   unsigned int tlb_i;
608   tme_uint16_t pgmap;
609 
610   /* recover our data structures: */
611   sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
612 
613   /* get the normal-width address: */
614   address = address_wider;
615   assert (address == address_wider);
616 
617   /* the address must be within range: */
618   assert(address <= 0xffffff);
619 
620   /* mask the address with the board page size: */
621   address &= -TME_SUN_MIE_PAGESIZE;
622 
623   /* lock our mutex: */
624   tme_mutex_lock(&sun_mie->tme_sun_mie_mutex);
625 
626   /* get the pagemap entry: */
627   pgmap_i = (address / TME_SUN_MIE_PAGESIZE) & (TME_SUN_MIE_PGMAP_COUNT - 1);
628   pgmap = tme_betoh_u16(((tme_uint16_t *) &sun_mie->tme_sun_mie_regs[TME_SUN_MIE_REG_PGMAP])[pgmap_i]);
629 
630   /* update the head pointer for this page map entry's active TLB
631      entry list: */
632   tlb_i = sun_mie->tme_sun_mie_tlb_head[pgmap_i];
633   if (++tlb_i == TME_SUN_MIE_PGMAP_TLBS) {
634     tlb_i = 0;
635   }
636   sun_mie->tme_sun_mie_tlb_head[pgmap_i] = tlb_i;
637   tlb_i += pgmap_i * TME_SUN_MIE_PGMAP_TLBS;
638 
639   /* if the new head pointer already has a TLB entry, and it doesn't
640      happen to be the same one that we're filling now, invalidate it: */
641   if (sun_mie->tme_sun_mie_tlb_tokens[tlb_i] != NULL
642       && sun_mie->tme_sun_mie_tlb_tokens[tlb_i] != tlb->tme_bus_tlb_token) {
643     tme_token_invalidate(sun_mie->tme_sun_mie_tlb_tokens[tlb_i]);
644   }
645 
646   /* initialize the TLB entry: */
647   tme_bus_tlb_initialize(tlb);
648 
649   /* this TLB entry covers this range: */
650   tlb->tme_bus_tlb_addr_first = address;
651   tlb->tme_bus_tlb_addr_last = address | (TME_SUN_MIE_PAGESIZE - 1);
652 
653   /* allow reading and writing: */
654   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
655 
656   /* our bus cycle handler: */
657   tlb->tme_bus_tlb_cycle_private = sun_mie;
658   tlb->tme_bus_tlb_cycle = _tme_sun_mie_bus_cycle;
659 
660   /* this TLB entry allows fast reading and writing: */
661   tlb->tme_bus_tlb_emulator_off_write =
662     (&sun_mie->tme_sun_mie_memory[((pgmap & TME_SUN_MIE_PGMAP_PFNUM)
663 				   * TME_SUN_MIE_PAGESIZE)]
664      - address);
665   tlb->tme_bus_tlb_emulator_off_read =
666     tlb->tme_bus_tlb_emulator_off_write;
667 
668   /* add this TLB entry to the active list: */
669   sun_mie->tme_sun_mie_tlb_tokens[tlb_i] =
670     tlb->tme_bus_tlb_token;
671 
672   /* unlock our mutex: */
673   tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex);
674 
675   return (TME_OK);
676 }
677 
678 /* the sun_mie TLB filler for the board registers: */
679 static int
_tme_sun_mie_tlb_fill_regs(struct tme_bus_connection * conn_bus,struct tme_bus_tlb * tlb,tme_bus_addr_t address_wider,unsigned int cycles)680 _tme_sun_mie_tlb_fill_regs(struct tme_bus_connection *conn_bus,
681 			   struct tme_bus_tlb *tlb,
682 			   tme_bus_addr_t address_wider,
683 			   unsigned int cycles)
684 {
685   struct tme_sun_mie *sun_mie;
686   tme_bus_addr32_t address;
687 
688   /* recover our data structures: */
689   sun_mie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
690 
691   /* get the normal-width address: */
692   address = address_wider;
693   assert (address == address_wider);
694 
695   /* the address must be within range: */
696   assert(address < TME_SUN_MIE_SIZ_REGS);
697 
698   /* initialize the TLB entry: */
699   tme_bus_tlb_initialize(tlb);
700 
701   /* if the address falls in the page map: */
702   if (TME_SUN_MIE_REG_PGMAP <= address
703       && address < (TME_SUN_MIE_REG_PGMAP
704 		    + TME_SUN_MIE_SIZ_PGMAP)) {
705 
706     /* this TLB entry covers this range: */
707     tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_PGMAP;
708     tlb->tme_bus_tlb_addr_last = (TME_SUN_MIE_REG_PGMAP + TME_SUN_MIE_SIZ_PGMAP - 1);
709   }
710 
711   /* if this address falls in the PROM: */
712   else if (TME_SUN_MIE_REG_PROM <= address
713 	   && address < (TME_SUN_MIE_REG_PROM
714 			 + TME_SUN_MIE_SIZ_PROM)) {
715 
716 
717     /* this TLB entry covers this range: */
718     tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_PROM;
719     tlb->tme_bus_tlb_addr_last = TME_SUN_MIE_REG_PROM + TME_SUN_MIE_SIZ_PROM - 1;
720   }
721 
722   /* if this address falls in the CSR: */
723   else if (TME_SUN_MIE_REG_CSR <= address
724 	   && address < (TME_SUN_MIE_REG_CSR
725 			 + TME_SUN_MIE_SIZ_CSR)) {
726 
727 
728     /* this TLB entry covers this range: */
729     tlb->tme_bus_tlb_addr_first = TME_SUN_MIE_REG_CSR;
730     tlb->tme_bus_tlb_addr_last = TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR - 1;
731   }
732 
733   /* otherwise, this address must fall in the unused hole or in the
734      parity registers: */
735   else {
736     assert (address >= (TME_SUN_MIE_REG_CSR
737 			+ TME_SUN_MIE_SIZ_CSR));
738 
739     /* this TLB entry covers this range: */
740     tlb->tme_bus_tlb_addr_first = (TME_SUN_MIE_REG_CSR + TME_SUN_MIE_SIZ_CSR);
741     tlb->tme_bus_tlb_addr_last = (TME_SUN_MIE_REG_PE_ALO + TME_SUN_MIE_SIZ_PE_ALO - 1);
742   }
743 
744   /* all address ranges allow fast reading: */
745   tlb->tme_bus_tlb_emulator_off_read = &sun_mie->tme_sun_mie_regs[0];
746   tlb->tme_bus_tlb_rwlock = &sun_mie->tme_sun_mie_rwlock;
747 
748   /* allow reading and writing: */
749   tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
750 
751   /* our bus cycle handler: */
752   tlb->tme_bus_tlb_cycle_private = sun_mie;
753   tlb->tme_bus_tlb_cycle = _tme_sun_mie_bus_cycle_regs;
754 
755   return (TME_OK);
756 }
757 
758 /* this scores a new connection: */
759 static int
_tme_sun_mie_connection_score(struct tme_connection * conn,unsigned int * _score)760 _tme_sun_mie_connection_score(struct tme_connection *conn, unsigned int *_score)
761 {
762   struct tme_sun_mie *sun_mie;
763   struct tme_sun_mie_connection *conn_sun_mie;
764 
765   /* both sides must be generic bus connections: */
766   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
767   assert(conn->tme_connection_other->tme_connection_type
768 	 == conn->tme_connection_type);
769 
770   /* recover our data structures: */
771   sun_mie = conn->tme_connection_element->tme_element_private;
772   conn_sun_mie = (struct tme_sun_mie_connection *)conn;
773 
774   /* this is a generic bus connection, so just score it nonzero and
775      return.  note that there's no good way to differentiate a
776      connection to a bus from a connection to just another chip, so we
777      always return a nonzero score here: */
778   *_score = 1;
779   return (TME_OK);
780 }
781 
782 /* this makes a new connection: */
783 static int
_tme_sun_mie_connection_make(struct tme_connection * conn,unsigned int state)784 _tme_sun_mie_connection_make(struct tme_connection *conn, unsigned int state)
785 {
786   struct tme_sun_mie *sun_mie;
787   struct tme_sun_mie_connection *conn_sun_mie;
788   struct tme_bus_connection *conn_bus;
789   tme_uint16_t csr;
790 
791   /* both sides must be generic bus connections: */
792   assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
793   assert(conn->tme_connection_other->tme_connection_type
794 	 == conn->tme_connection_type);
795 
796   /* recover our data structures: */
797   sun_mie = conn->tme_connection_element->tme_element_private;
798   conn_sun_mie = (struct tme_sun_mie_connection *)conn;
799   conn_bus = &conn_sun_mie->tme_sun_mie_connection;
800 
801   /* we're always set up to answer calls across the connection, so we
802      only have to do work when the connection has gone full, namely
803      taking the other side of the connection: */
804   if (state == TME_CONNECTION_FULL) {
805 
806     /* lock our mutex: */
807     tme_mutex_lock(&sun_mie->tme_sun_mie_mutex);
808 
809     /* save our connection: */
810     if (conn_bus->tme_bus_signals_add != NULL) {
811       sun_mie->tme_sun_mie_conn_i825x6 = (struct tme_bus_connection *) conn->tme_connection_other;
812     }
813     else if (conn_sun_mie->tme_sun_mie_connection_regs) {
814       sun_mie->tme_sun_mie_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other;
815     }
816     else {
817       sun_mie->tme_sun_mie_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other;
818       csr = TME_SUN_MIE_CSR_GET(sun_mie);
819       csr &= ~TME_SUN_MIE_CSR_MPMHI;
820       csr |= conn_sun_mie->tme_sun_mie_connection_mpmhi;
821       TME_SUN_MIE_CSR_PUT(sun_mie, csr);
822     }
823 
824     /* unlock our mutex: */
825     tme_mutex_unlock(&sun_mie->tme_sun_mie_mutex);
826   }
827 
828   return (TME_OK);
829 }
830 
831 /* this breaks a connection: */
832 static int
_tme_sun_mie_connection_break(struct tme_connection * conn,unsigned int state)833 _tme_sun_mie_connection_break(struct tme_connection *conn, unsigned int state)
834 {
835   abort();
836 }
837 
838 /* this makes a new connection side for a sun_mie: */
839 static int
_tme_sun_mie_connections_new(struct tme_element * element,const char * const * args,struct tme_connection ** _conns,char ** _output)840 _tme_sun_mie_connections_new(struct tme_element *element,
841 			     const char * const *args,
842 			     struct tme_connection **_conns,
843 			     char **_output)
844 {
845   struct tme_sun_mie *sun_mie;
846   struct tme_sun_mie_connection *conn_sun_mie;
847   struct tme_bus_connection *conn_bus;
848   struct tme_connection *conn;
849   unsigned int i825x6;
850   tme_uint8_t regs;
851   tme_bus_addr_t mpmhi;
852   int usage;
853   int rc;
854 
855   /* recover our data structure: */
856   sun_mie = (struct tme_sun_mie *) element->tme_element_private;
857 
858   /* we don't bother locking the mutex simply to check if connections
859      already exist: */
860 
861   /* check our arguments: */
862   usage = FALSE;
863   rc = 0;
864   i825x6 = FALSE;
865   regs = FALSE;
866   mpmhi = 0;
867 
868   /* if this connection is for the registers: */
869   if (TME_ARG_IS(args[1], "csr")) {
870 
871     /* if we already have a register connection, complain: */
872     if (sun_mie->tme_sun_mie_conn_regs != NULL) {
873       rc = EEXIST;
874     }
875 
876     /* otherwise, make the new connection: */
877     else {
878       regs = TRUE;
879     }
880   }
881 
882   /* else, if this connection is for the memory: */
883   else if (TME_ARG_IS(args[1], "memory")) {
884 
885     /* if we already have a memory connection, complain: */
886     if (sun_mie->tme_sun_mie_conn_memory != NULL) {
887       rc = EEXIST;
888     }
889 
890     /* otherwise, check the value after "memory".  it must be the low
891        20 bits of the bus address of the board's memory; in our csr we
892        have to report the most significant nibble (A19-A16, as A15..A0
893        are expected to be zero) to software so it can find that
894        memory: */
895     else {
896       mpmhi = tme_bus_addr_parse_any(args[2], &usage);
897       if (!usage
898 	  && ((mpmhi > 0xfffff)
899 	      || (mpmhi & (TME_SUN_MIE_SIZ_MBM - 1)))) {
900 	tme_output_append_error(_output,
901 				"%s %s, ",
902 				args[2],
903 				_(" is not a 20-bit address with A15..A0 zero"));
904 	usage = TRUE;
905       }
906     }
907   }
908 
909   /* else, the connection must be for the i825x6: */
910   else if (args[1] == NULL) {
911 
912     /* if we already have an i825x6 connection, complain: */
913     if (sun_mie->tme_sun_mie_conn_i825x6 != NULL) {
914       rc = EEXIST;
915     }
916 
917     /* otherwise, make the new conection: */
918     else {
919       i825x6 = TRUE;
920     }
921   }
922 
923   /* otherwise, this is a bad argument: */
924   else {
925     tme_output_append_error(_output,
926 			    "%s %s, ",
927 			    args[1],
928 			    _("unexpected"));
929     usage = TRUE;
930   }
931 
932   if (usage) {
933     tme_output_append_error(_output,
934 			    "%s %s [ csr | memory %s ]",
935 			    _("usage:"),
936 			    args[0],
937 			    _("BUS-ADDRESS"));
938     rc = EINVAL;
939   }
940 
941   if (rc) {
942     return (rc);
943   }
944 
945   /* make a new connection: */
946   conn_sun_mie = tme_new0(struct tme_sun_mie_connection, 1);
947   conn_bus = &conn_sun_mie->tme_sun_mie_connection;
948   conn = &conn_bus->tme_bus_connection;
949 
950   /* fill in the generic connection: */
951   conn->tme_connection_next = *_conns;
952   conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
953   conn->tme_connection_score = _tme_sun_mie_connection_score;
954   conn->tme_connection_make = _tme_sun_mie_connection_make;
955   conn->tme_connection_break = _tme_sun_mie_connection_break;
956 
957   /* fill in the generic bus connection: */
958   conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0;
959   conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL;
960   if (i825x6) {
961     conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0xffffff;
962     conn_bus->tme_bus_signals_add = _tme_sun_mie_bus_signals_add;
963     conn_bus->tme_bus_signal = _tme_sun_mie_bus_signal;
964     conn_bus->tme_bus_tlb_set_add = _tme_sun_mie_tlb_set_add;
965     conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill;
966   }
967   else if (regs) {
968     conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_MIE_SIZ_REGS - 1;
969     conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill_regs;
970   }
971   else {
972     conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_MIE_SIZ_MBM - 1;
973     conn_bus->tme_bus_tlb_fill = _tme_sun_mie_tlb_fill;
974   }
975 
976   /* fill in the internal information: */
977   conn_sun_mie->tme_sun_mie_connection_regs = regs;
978   conn_sun_mie->tme_sun_mie_connection_mpmhi = (mpmhi >> 16);
979 
980   /* return the connection side possibility: */
981   *_conns = conn;
982   return (TME_OK);
983 }
984 
985 /* the new sun_mie function: */
TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,sun_mie)986 TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,sun_mie) {
987   struct tme_sun_mie *sun_mie;
988   int arg_i;
989   int usage;
990 
991   /* check our arguments: */
992   usage = 0;
993   arg_i = 1;
994   for (;;) {
995 
996     if (0) {
997     }
998 
999     /* if we ran out of arguments: */
1000     else if (args[arg_i] == NULL) {
1001 
1002       break;
1003     }
1004 
1005     /* otherwise this is a bad argument: */
1006     else {
1007       tme_output_append_error(_output,
1008 			      "%s %s, ",
1009 			      args[arg_i],
1010 			      _("unexpected"));
1011       usage = TRUE;
1012       break;
1013     }
1014   }
1015 
1016   if (usage) {
1017     tme_output_append_error(_output,
1018 			    "%s %s",
1019 			    _("usage:"),
1020 			    args[0]);
1021     return (EINVAL);
1022   }
1023 
1024   /* start the sun_mie structure: */
1025   sun_mie = tme_new0(struct tme_sun_mie, 1);
1026   sun_mie->tme_sun_mie_element = element;
1027   TME_SUN_MIE_CSR_PUT(sun_mie,
1028 		      (TME_SUN_MIE_CSR_NOLOOP
1029 		       | TME_SUN_MIE_CSR_BIGRAM));
1030   tme_mutex_init(&sun_mie->tme_sun_mie_mutex);
1031   tme_rwlock_init(&sun_mie->tme_sun_mie_rwlock);
1032 
1033   /* fill the element: */
1034   element->tme_element_private = sun_mie;
1035   element->tme_element_connections_new = _tme_sun_mie_connections_new;
1036 
1037   return (TME_OK);
1038 }
1039