1 /* $Id: sun44c-memerr.c,v 1.3 2010/06/05 19:29:11 fredette Exp $ */
2 
3 /* machine/sun4/sun44c-memerr.c - implementation of Sun 4/4c memory error emulation: */
4 
5 /*
6  * Copyright (c) 2006 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: sun44c-memerr.c,v 1.3 2010/06/05 19:29:11 fredette Exp $");
38 
39 /* includes: */
40 #include "sun4-impl.h"
41 
42 /* this calls out a memory error interrupt change: */
43 static void
_tme_sun44c_memerr_callout(struct tme_sun4 * sun4)44 _tme_sun44c_memerr_callout(struct tme_sun4 *sun4)
45 {
46   unsigned int int_asserted;
47   struct tme_bus_connection *conn_bus;
48   int rc;
49 
50   /* on a sun4c, asynchronous memory errors can't really be tested, so
51      we never need to assert the memory error interrupt: */
52   if (TME_SUN4_IS_SUN4C(sun4)) {
53     return;
54   }
55 
56   /* see if the memory error interrupt should be asserted: */
57   int_asserted
58     = ((sun4->tme_sun44c_memerr_csr[0]
59 	& (TME_SUN4_MEMERR_X_INT_ACTIVE
60 	   | TME_SUN4_MEMERR_X_ENABLE_INT))
61        == (TME_SUN4_MEMERR_X_INT_ACTIVE
62 	   | TME_SUN4_MEMERR_X_ENABLE_INT));
63 
64   /* if we need to call out an interrupt change: */
65   if (!int_asserted != !sun4->tme_sun4_memerr_int_asserted) {
66 
67     /* get our bus connection: */
68     conn_bus = sun4->tme_sun4_buses[TME_SUN4_32_CONN_REG_MEMERR];
69 
70     /* call out the bus interrupt signal edge: */
71     rc = (*conn_bus->tme_bus_signal)
72       (conn_bus,
73        TME_BUS_SIGNAL_INT(TME_SPARC_IPL_NMI)
74        | (int_asserted
75 	  ? TME_BUS_SIGNAL_LEVEL_ASSERTED
76 	  : TME_BUS_SIGNAL_LEVEL_NEGATED));
77 
78     /* if this callout was successful, note the new state of the
79        interrupt signal: */
80     if (rc == TME_OK) {
81       sun4->tme_sun4_memerr_int_asserted = int_asserted;
82     }
83 
84     /* otherwise, abort: */
85     else {
86       abort();
87     }
88   }
89 }
90 
91 /* this updates bad memory: */
92 void
_tme_sun44c_memerr_update(struct tme_sun4 * sun4,tme_uint32_t pte,const tme_shared tme_uint8_t * memory,unsigned int cycle_size)93 _tme_sun44c_memerr_update(struct tme_sun4 *sun4,
94 			  tme_uint32_t pte,
95 			  const tme_shared tme_uint8_t *memory,
96 			  unsigned int cycle_size)
97 {
98   unsigned int address_i;
99   unsigned int address_i_free;
100   int which_csr;
101   int memory_bad;
102   int visible_before;
103 
104   /* on the SS2, code name "Calvin", the second 64MB of memory is on
105      an expansion board, which uses the second memory error register: */
106   which_csr = (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)
107 	       && (pte & TME_SUN4C_PTE_PGFRAME) >= ((64 * 1024 * 1024) / TME_SUN4C_PAGE_SIZE));
108 
109   /* if the memory is being written with bad parity: */
110   memory_bad = (sun4->tme_sun44c_memerr_csr[which_csr] & TME_SUN44C_MEMERR_PAR_TEST) != 0;
111 
112   /* see if the memory error registers are visible before: */
113   visible_before = TME_SUN44C_MEMERR_VISIBLE(sun4);
114 
115   /* this is obviously a poor implementation, but this is not used
116      during normal operation: */
117 
118   /* loop over all of the written memory: */
119   for (; cycle_size > 0; memory++, cycle_size--) {
120 
121     /* search the bad memory list for this memory, and for a free
122        entry in the list: */
123     address_i = 0;
124     address_i_free = TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory);
125     do {
126       if (sun4->tme_sun4_memerr_bad_memory[address_i] == NULL) {
127 	address_i_free = address_i;
128       }
129       else if (sun4->tme_sun4_memerr_bad_memory[address_i] == memory) {
130 	address_i_free = address_i;
131 	break;
132       }
133     } while (++address_i < TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory));
134 
135     /* if the memory is being written with bad parity: */
136     if (memory_bad) {
137 
138       /* if the bad memory list is full: */
139       if (address_i_free == TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory)) {
140 	abort();
141       }
142 
143       /* if this bad memory isn't already on the list: */
144       if (sun4->tme_sun4_memerr_bad_memory[address_i_free] == NULL) {
145 
146 	/* this memory is now bad: */
147 	sun4->tme_sun4_memerr_bad_memory[address_i_free] = memory;
148 	sun4->tme_sun4_memerr_bad_memory_count++;
149       }
150     }
151 
152     /* otherwise, the memory is being written with good parity: */
153     else {
154 
155       /* if this memory was previously written with bad parity: */
156       if (address_i_free < TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory)
157 	  && sun4->tme_sun4_memerr_bad_memory[address_i] == memory) {
158 
159 	/* this memory is good again: */
160 	sun4->tme_sun4_memerr_bad_memory[address_i] = NULL;
161 	sun4->tme_sun4_memerr_bad_memory_count--;
162       }
163     }
164   }
165 
166   /* if the memory error registers were visible before, and are no
167      longer visible: */
168   if (visible_before
169       && !TME_SUN44C_MEMERR_VISIBLE(sun4)) {
170 
171     /* unless the cache is visible, update the TLB fill function: */
172     if (!sun4->tme_sun4_cache_visible) {
173       sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_mmu;
174     }
175   }
176 }
177 
178 /* this checks for bad memory during a read: */
179 int
_tme_sun44c_memerr_check(const struct tme_bus_connection * conn_bus_init,tme_uint32_t address,tme_uint32_t pte,const tme_shared tme_uint8_t * memory,unsigned int cycle_size)180 _tme_sun44c_memerr_check(const struct tme_bus_connection *conn_bus_init,
181 			 tme_uint32_t address,
182 			 tme_uint32_t pte,
183 			 const tme_shared tme_uint8_t *memory,
184 			 unsigned int cycle_size)
185 {
186   struct tme_sun4 *sun4;
187   unsigned int address_i;
188   tme_uint32_t csr;
189   int write_csr;
190 
191   /* recover our sun4: */
192   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
193 
194   /* this is obviously a poor implementation, but this is not used
195      during normal operation: */
196 
197   /* loop over all of the bad memory: */
198   csr = 0;
199   for (; cycle_size > 0; address++, memory++, cycle_size--) {
200 
201     /* see if this byte is bad: */
202     address_i = 0;
203     do {
204       if (sun4->tme_sun4_memerr_bad_memory[address_i] == memory) {
205 	csr
206 	  |= (TME_SUN4_IS_SUN4C(sun4)
207 	      ? TME_SUN44C_MEMERR_PAR_ERR_BL0 << (address % sizeof(tme_uint32_t))
208 	      : TME_SUN44C_MEMERR_PAR_ERR_BL3 >> (address % sizeof(tme_uint32_t)));
209 	break;
210       }
211     } while (++address_i < TME_ARRAY_ELS(sun4->tme_sun4_memerr_bad_memory));
212   }
213 
214   /* if no bad memory was accessed, return now: */
215   if (csr == 0) {
216     return (FALSE);
217   }
218 
219   /* if this is a sun4c: */
220   if (TME_SUN4_IS_SUN4C(sun4)) {
221 
222     /* on the SS2, code name "Calvin", the second 64MB of memory is on
223        an expansion board, which uses the second memory error
224        register: */
225     write_csr = (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)
226 		 && (pte & TME_SUN4C_PTE_PGFRAME) >= ((64 * 1024 * 1024) / TME_SUN4C_PAGE_SIZE));
227 
228     sun4->tme_sun44c_memerr_csr[write_csr]
229       |= (csr
230 	  | TME_SUN4C_MEMERR_PAR_ERROR
231 	  | ((sun4->tme_sun44c_memerr_csr[write_csr] & TME_SUN4C_MEMERR_PAR_ERROR)
232 	     ? TME_SUN4C_MEMERR_PAR_MULTI
233 	     : 0));
234   }
235 
236   /* otherwise, this is a sun4: */
237   else {
238     abort();
239   }
240 
241   /* call out an interrupt: */
242   _tme_sun44c_memerr_callout(sun4);
243 
244   /* a memory error has happened: */
245   return (TRUE);
246 }
247 
248 /* the bus cycle handler for the memory error register: */
249 int
_tme_sun44c_memerr_cycle_control(void * _sun4,struct tme_bus_cycle * cycle_init)250 _tme_sun44c_memerr_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init)
251 {
252   struct tme_sun4 *sun4;
253   tme_uint32_t memerr_reg[2][TME_SUN44C_MEMERR_SIZ_REG / sizeof(tme_uint32_t)];
254   int write_csr, unlatch;
255   int write_parctl;
256   tme_uint32_t csr_old;
257   tme_uint32_t csr_new;
258   tme_uint32_t csr_ro;
259   int visible_before;
260 
261   /* recover our sun4: */
262   sun4 = (struct tme_sun4 *) _sun4;
263 
264   /* start filling the memory error register(s): */
265   memerr_reg[0][TME_SUN44C_MEMERR_REG_CSR / sizeof(tme_uint32_t)]
266     = tme_htobe_u32(sun4->tme_sun44c_memerr_csr[0]);
267 
268   /* assume this cycle won't write or unlatch a memory error register: */
269   write_csr = -1;
270   unlatch = -1;
271   write_parctl = -1;
272 
273   /* we only tolerate aligned 32-bit accesses: */
274   if (!((cycle_init->tme_bus_cycle_address % sizeof(tme_uint32_t)) == 0
275 	&& cycle_init->tme_bus_cycle_size == sizeof(tme_uint32_t))) {
276     abort();
277   }
278 
279   /* if this is a sun4c: */
280   if (TME_SUN4_IS_SUN4C(sun4)) {
281 
282     /* finish filling the memory error registers: */
283     memerr_reg[0][TME_SUN4C_MEMERR_REG_PARCTL / sizeof(tme_uint32_t)]
284       = tme_htobe_u32(sun4->tme_sun4c_memerr_parctl[0]);
285     memerr_reg[1][TME_SUN44C_MEMERR_REG_CSR / sizeof(tme_uint32_t)]
286       = tme_htobe_u32(sun4->tme_sun44c_memerr_csr[1]);
287     memerr_reg[1][TME_SUN4C_MEMERR_REG_PARCTL / sizeof(tme_uint32_t)]
288       = tme_htobe_u32(sun4->tme_sun4c_memerr_parctl[1]);
289 
290     assert ((cycle_init->tme_bus_cycle_address
291 	     + cycle_init->tme_bus_cycle_size
292 	     - 1) < sizeof(memerr_reg));
293 
294     /* if this access is to a parity control register: */
295     if (cycle_init->tme_bus_cycle_address & TME_SUN4C_MEMERR_REG_PARCTL) {
296 
297       /* if this is a write: */
298       if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
299 	write_parctl = (cycle_init->tme_bus_cycle_address / TME_SUN44C_MEMERR_SIZ_REG);
300       }
301     }
302 
303     /* otherwise, this access is to a CSR: */
304     else {
305 
306       /* "The information bits in the memory error register are
307          cleared by reading it." */
308 
309       /* any write writes either of the CSRs, and any read reads one
310          of the CSRs: */
311       if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
312 	unlatch = (cycle_init->tme_bus_cycle_address / TME_SUN44C_MEMERR_SIZ_REG);
313       }
314       else {
315 	write_csr = (cycle_init->tme_bus_cycle_address / TME_SUN44C_MEMERR_SIZ_REG);
316       }
317     }
318   }
319 
320   /* otherwise, this is a sun4: */
321   else {
322 
323     /* finish filling the memory error register: */
324     memerr_reg[0][TME_SUN4_MEMERR_REG_VADDR / sizeof(tme_uint32_t)]
325       = tme_htobe_u32(sun4->tme_sun4_memerr_vaddr);
326 
327     assert ((cycle_init->tme_bus_cycle_address
328 	     + cycle_init->tme_bus_cycle_size
329 	     - 1) < TME_SUN44C_MEMERR_SIZ_REG);
330 
331     /* if this is a write: */
332     if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
333 
334       /* "The interrupt is held pending and the error information in
335 	 the memory error register is latched (frozen) until it is
336 	 cleared (unfrozen) by a write to bits <31..24> of the memory
337 	 error address register." */
338 
339       /* see if this writes the vaddr or the CSR: */
340       if (cycle_init->tme_bus_cycle_address & TME_SUN4_MEMERR_REG_VADDR) {
341 	unlatch = 0;
342       }
343       else {
344 	write_csr = 0;
345       }
346     }
347   }
348 
349   /* do the transfer: */
350   tme_bus_cycle_xfer_memory(cycle_init,
351 			    (tme_uint8_t *) memerr_reg,
352 			    sizeof(memerr_reg) - 1);
353 
354   /* if this is a write: */
355   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
356 
357     /* if the sun4c parity control register has been written: */
358     if (write_parctl >= 0) {
359       sun4->tme_sun4c_memerr_parctl[write_parctl]
360 	= tme_betoh_u32(memerr_reg[write_parctl][TME_SUN4C_MEMERR_REG_PARCTL / sizeof(tme_uint32_t)]);
361     }
362 
363     /* if the sun4 vaddr register has been written: */
364     if (TME_SUN4_IS_SUN4(sun4)
365 	&& unlatch) {
366       sun4->tme_sun4c_memerr_parctl[0]
367 	= tme_betoh_u32(memerr_reg[0][TME_SUN4_MEMERR_REG_VADDR / sizeof(tme_uint32_t)]);
368     }
369   }
370 
371   /* assume that there are no CSR changes: */
372   csr_old = csr_new = 0;
373   csr_ro = ~(TME_SUN44C_MEMERR_PAR_TEST
374 	     | TME_SUN44C_MEMERR_PAR_ENABLE
375 	     | (TME_SUN4_IS_SUN4C(sun4)
376 		? 0
377 		: TME_SUN4_MEMERR_X_ENABLE_INT));
378 
379   /* if a CSR register has been written: */
380   if (write_csr >= 0) {
381 
382     /* get the new and old CSR values, preserving the read-only bits: */
383     csr_old = sun4->tme_sun44c_memerr_csr[write_csr];
384     csr_new = tme_betoh_u32(memerr_reg[write_csr][TME_SUN44C_MEMERR_REG_CSR / sizeof(tme_uint32_t)]);
385     csr_new = ((csr_old & csr_ro)
386 	       | (csr_new & ~csr_ro));
387   }
388 
389   /* otherwise, if a CSR register has been unlatched: */
390   else if (unlatch >= 0) {
391 
392     /* get the old and new CSR values, clearing the read-only bits: */
393     csr_old = sun4->tme_sun44c_memerr_csr[unlatch];
394     csr_new &= ~csr_ro;
395     write_csr = unlatch;
396   }
397 
398   /* if a CSR register has changed: */
399   if (csr_new != csr_old) {
400 
401     /* see if the memory error registers were visible before: */
402     visible_before = TME_SUN44C_MEMERR_VISIBLE(sun4);
403 
404     /* set the new CSR value and call out an interrupt change: */
405     sun4->tme_sun44c_memerr_csr[write_csr] = csr_new;
406     _tme_sun44c_memerr_callout(sun4);
407 
408     /* if the write-inverse-parity testing feature is being enabled or
409        disabled: */
410     if ((csr_new ^ csr_old) & TME_SUN44C_MEMERR_PAR_TEST) {
411 
412       /* if this feature is being enabled: */
413       if (csr_new & TME_SUN44C_MEMERR_PAR_TEST) {
414 
415 	/* if the memory error registers weren't visible before: */
416 	if (!visible_before) {
417 
418 	  /* the memory error registers are now visible: */
419 	  assert (sun4->tme_sun4_memerr_bad_memory_count == 0);
420 
421 	  /* unless the cache is visible, update the TLB fill function: */
422 	  if (!sun4->tme_sun4_cache_visible) {
423 	    sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_memerr;
424 	  }
425 
426 	  /* invalidate all TLBs: */
427 	  tme_sun_mmu_tlbs_invalidate(sun4->tme_sun44c_mmu);
428 	}
429       }
430 
431       /* otherwise, this feature is being disabled: */
432       else {
433 
434 	assert (visible_before);
435 
436 	/* if the memory error registers are no longer visible: */
437 	if (!TME_SUN44C_MEMERR_VISIBLE(sun4)) {
438 
439 	  /* unless the cache is visible, update the TLB fill function: */
440 	  if (!sun4->tme_sun4_cache_visible) {
441 	    sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_mmu;
442 	  }
443 
444 	  /* invalidate all TLBs: */
445 	  tme_sun_mmu_tlbs_invalidate(sun4->tme_sun44c_mmu);
446 	}
447       }
448     }
449   }
450 
451   return (TME_OK);
452 }
453 
454 /* the bus cycle handler for memory error testing: */
455 int
_tme_sun44c_memerr_cycle_bus(void * _conn_bus_init,struct tme_bus_cycle * cycle_init)456 _tme_sun44c_memerr_cycle_bus(void *_conn_bus_init,
457 			     struct tme_bus_cycle *cycle_init)
458 {
459   const struct tme_bus_connection *conn_bus_init;
460   struct tme_sun4 *sun4;
461   struct tme_bus_tlb *tlb;
462   tme_uint32_t address;
463   unsigned int cycle_size;
464   union {
465     tme_uint8_t memory_buffer_8s[sizeof(tme_uint32_t) / sizeof(tme_uint8_t)];
466     tme_uint16_t memory_buffer_16s[sizeof(tme_uint32_t) / sizeof(tme_uint16_t)];
467     tme_uint32_t memory_buffer_32s[sizeof(tme_uint32_t) / sizeof(tme_uint32_t)];
468   } memory_buffer;
469   struct tme_sun_mmu_pte pte_mmu;
470   const tme_shared tme_uint8_t *memory_data_read;
471   tme_shared tme_uint8_t *memory_data_write;
472   int rc;
473 
474   /* recover our initiator's bus connection and sun4: */
475   conn_bus_init = (struct tme_bus_connection *) _conn_bus_init;
476   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
477 
478   /* get the address and size for this cycle: */
479   address = cycle_init->tme_bus_cycle_address;
480   cycle_size = cycle_init->tme_bus_cycle_size;
481 
482   /* recover the TLB entry for this cycle: */
483   tlb = sun4->tme_sun4_memtest_tlb;
484   assert (tlb != NULL);
485 
486   /* busy the TLB entry that triggered this cycle: */
487   tme_bus_tlb_busy(tlb);
488 
489   /* if the TLB entry is invalid, return now: */
490   if (tme_bus_tlb_is_invalid(tlb)) {
491 
492     /* unbusy the TLB entry and return now: */
493     tme_bus_tlb_unbusy(tlb);
494     return (EBADF);
495   }
496 
497   /* get the PTE for this address and context from the MMU: */
498   rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu,
499 			   TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init),
500 			   address,
501 			   &pte_mmu);
502   assert (rc == TME_OK);
503 
504   /* if this cycle is a read: */
505   if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
506 
507     /* get a pointer to the data to read: */
508     memory_data_read
509       = (sun4->tme_sun4_memerr_tlb_emulator_off_read
510 	 + address);
511 
512     /* dispatch on the cycle size, to transfer the data from memory
513        into the memory buffer: */
514     switch (cycle_size) {
515     default:
516       assert (FALSE);
517       /* FALLTHROUGH */
518     case sizeof(tme_uint8_t):
519       memory_buffer.memory_buffer_8s[0]
520 	= tme_memory_bus_read8(memory_data_read,
521 			       tlb->tme_bus_tlb_rwlock,
522 			       sizeof(tme_uint8_t),
523 			       sizeof(tme_uint32_t));
524       break;
525     case sizeof(tme_uint16_t):
526       memory_buffer.memory_buffer_16s[0]
527 	= tme_memory_bus_read16((const tme_shared tme_uint16_t *) memory_data_read,
528 				tlb->tme_bus_tlb_rwlock,
529 				sizeof(tme_uint16_t),
530 				sizeof(tme_uint32_t));
531       break;
532     case sizeof(tme_uint32_t):
533       memory_buffer.memory_buffer_32s[0]
534 	= tme_memory_bus_read32((const tme_shared tme_uint32_t *) memory_data_read,
535 				tlb->tme_bus_tlb_rwlock,
536 				sizeof(tme_uint32_t),
537 				sizeof(tme_uint32_t));
538       break;
539     }
540 
541     /* run the bus cycle against the memory buffer: */
542     tme_bus_cycle_xfer_memory(cycle_init,
543 			      &memory_buffer.memory_buffer_8s[0] - address,
544 			      address + cycle_size - 1);
545     assert (cycle_init->tme_bus_cycle_size == cycle_size);
546 
547     /* check for memory errors on this cache line fill: */
548     rc = (_tme_sun44c_memerr_check(conn_bus_init,
549 				   address,
550 				   pte_mmu.tme_sun_mmu_pte_raw,
551 				   memory_data_read,
552 				   cycle_size)
553 	  ? EIO
554 	  : TME_OK);
555   }
556 
557   /* otherwise, this cycle must be a write: */
558   else {
559     assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
560 
561     /* run the bus cycle against the memory buffer: */
562     tme_bus_cycle_xfer_memory(cycle_init,
563 			      &memory_buffer.memory_buffer_8s[0] - address,
564 			      address + cycle_size - 1);
565     assert (cycle_init->tme_bus_cycle_size == cycle_size);
566 
567     /* get a pointer to the data to write: */
568     memory_data_write
569       = (sun4->tme_sun4_memerr_tlb_emulator_off_write
570 	 + address);
571 
572     /* dispatch on the cycle size, to transfer the data from the
573        memory buffer to memory: */
574     switch (cycle_size) {
575     default:
576       assert (FALSE);
577       /* FALLTHROUGH */
578     case sizeof(tme_uint8_t):
579       tme_memory_bus_write8(memory_data_write,
580 			    memory_buffer.memory_buffer_8s[0],
581 			    tlb->tme_bus_tlb_rwlock,
582 			    sizeof(tme_uint8_t),
583 			    sizeof(tme_uint32_t));
584       break;
585     case sizeof(tme_uint16_t):
586       tme_memory_bus_write16((tme_shared tme_uint16_t *) memory_data_write,
587 			     memory_buffer.memory_buffer_16s[0],
588 			     tlb->tme_bus_tlb_rwlock,
589 			     sizeof(tme_uint16_t),
590 			     sizeof(tme_uint32_t));
591       break;
592     case sizeof(tme_uint32_t):
593       tme_memory_bus_write32((tme_shared tme_uint32_t *) memory_data_write,
594 			     memory_buffer.memory_buffer_32s[0],
595 			     tlb->tme_bus_tlb_rwlock,
596 			     sizeof(tme_uint32_t),
597 			     sizeof(tme_uint32_t));
598       break;
599     }
600 
601     /* add any memory errors caused by this write: */
602     _tme_sun44c_memerr_update(sun4,
603 			      pte_mmu.tme_sun_mmu_pte_raw,
604 			      memory_data_write,
605 			      cycle_size);
606     rc = TME_OK;
607   }
608 
609   /* unbusy the TLB entry and invalidate it.  this hurts performance,
610      since it keeps TLB entries valid only for one cycle at a time,
611      but it's simple and handles the problem of memory error testing
612      in the presence of virtual address aliases (addresses that have
613      never been written to can suddenly have read errors): */
614   tme_bus_tlb_unbusy(tlb);
615   tme_token_invalidate(tlb->tme_bus_tlb_token);
616   sun4->tme_sun4_memtest_tlb = NULL;
617 
618   return (rc);
619 }
620 
621 /* this fills TLBs when memory error testing is visible: */
622 int
_tme_sun44c_tlb_fill_memerr(const struct tme_bus_connection * conn_bus_init,struct tme_bus_tlb * tlb,tme_uint32_t * _asi_mask,tme_uint32_t address,unsigned int cycle_type)623 _tme_sun44c_tlb_fill_memerr(const struct tme_bus_connection *conn_bus_init,
624 			    struct tme_bus_tlb *tlb,
625 			    tme_uint32_t *_asi_mask,
626 			    tme_uint32_t address,
627 			    unsigned int cycle_type)
628 {
629   struct tme_sun4 *sun4;
630   tme_uint32_t asi_mask;
631   struct tme_sun_mmu_pte pte_mmu;
632   int rc;
633 
634   /* recover our sun4: */
635   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
636 
637   /* recover the ASI mask: */
638   asi_mask = *_asi_mask;
639 
640   /* this ASI mask must be a single ASI, for user or supervisor
641      instruction or data: */
642   assert (asi_mask == TME_SPARC32_ASI_MASK_UD
643 	  || asi_mask == TME_SPARC32_ASI_MASK_UI
644 	  || asi_mask == TME_SPARC32_ASI_MASK_SD
645 	  || asi_mask == TME_SPARC32_ASI_MASK_SI);
646 
647   /* invalidate any other memory test TLB entry: */
648   if (sun4->tme_sun4_memtest_tlb != NULL
649       && sun4->tme_sun4_memtest_tlb != tlb) {
650     tme_token_invalidate(sun4->tme_sun4_memtest_tlb->tme_bus_tlb_token);
651   }
652   sun4->tme_sun4_memtest_tlb = NULL;
653 #ifndef NDEBUG
654   sun4->tme_sun4_memerr_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
655   sun4->tme_sun4_memerr_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
656 #endif /* !NDEBUG */
657 
658   /* memory error testing must be active: */
659   assert (TME_SUN44C_MEMERR_VISIBLE(sun4));
660 
661   /* fill this TLB entry from the MMU: */
662   rc = _tme_sun44c_tlb_fill_mmu(conn_bus_init,
663 				tlb,
664 				_asi_mask,
665 				address,
666 				cycle_type);
667   assert (rc == TME_OK);
668 
669   /* get the PTE for this address and context from the MMU: */
670   rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu,
671 			   TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init),
672 			   address,
673 			   &pte_mmu);
674   assert (rc == TME_OK);
675 
676   /* if this PTE is valid and for onboard memory: */
677   if ((pte_mmu.tme_sun_mmu_pte_raw
678        & (TME_SUN44C_PTE_VALID
679 	  | TME_SUN44C_PTE_PGTYPE))
680       == (TME_SUN44C_PTE_VALID
681 	  | 0 /* TME_SUN44C_PGTYPE_OBMEM */)) {
682 
683     /* this TLB entry should have no shift: */
684     if (tlb->tme_bus_tlb_addr_shift != 0) {
685       abort();
686     }
687 
688     /* if this is a read: */
689     if (cycle_type == TME_BUS_CYCLE_READ) {
690 
691       /* invalidate this TLB entry for writes: */
692       tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
693 
694       /* if this TLB entry allows fast reading, and there are bad
695 	 memory addresses: */
696       if (tlb->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF
697 	  && sun4->tme_sun4_memerr_bad_memory_count > 0) {
698 
699 	/* we will handle this read: */
700 	sun4->tme_sun4_memerr_tlb_emulator_off_read = tlb->tme_bus_tlb_emulator_off_read;
701 	tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
702 	tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init;
703 	tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus;
704       }
705     }
706 
707     /* otherwise, this must be a write: */
708     else {
709       if (cycle_type != TME_BUS_CYCLE_WRITE) {
710 	abort();
711       }
712 
713       /* invalidate this TLB entry for reads: */
714       tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
715 
716       /* if this TLB entry allows fast writing: */
717       if (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
718 
719 	/* we will handle this write: */
720 	sun4->tme_sun4_memerr_tlb_emulator_off_write = tlb->tme_bus_tlb_emulator_off_write;
721 	tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
722 	tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init;
723 	tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus;
724       }
725     }
726 
727     /* finish invalidating this TLB entry for the other cycle type: */
728     assert (tlb->tme_bus_tlb_cycles_ok & cycle_type);
729     tlb->tme_bus_tlb_cycles_ok = cycle_type;
730     tlb->tme_bus_tlb_addr_offset = 0;
731   }
732 
733   /* remember this TLB entry: */
734   sun4->tme_sun4_memtest_tlb = tlb;
735 
736   /* return success: */
737   return (TME_OK);
738 }
739