|
|
1.1 root 1: /* $Id: sun44c-memerr.c,v 1.1 2006/09/30 12:56:00 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.1 2006/09/30 12:56:00 fredette Exp $");
38:
39: /* includes: */
40: #include "sun4-impl.h"
41:
42: /* this calls out a memory error interrupt change: */
43: static void
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
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
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
250: _tme_sun44c_memerr_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init)
251: {
252: struct tme_sun4 *sun4;
253: tme_uint8_t memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 2];
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: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN44C_MEMERR_REG_CSR])
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: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN4C_MEMERR_REG_PARCTL])
284: = tme_htobe_u32(sun4->tme_sun4c_memerr_parctl[0]);
285: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 1 + TME_SUN44C_MEMERR_REG_CSR])
286: = tme_htobe_u32(sun4->tme_sun44c_memerr_csr[1]);
287: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 1 + TME_SUN4C_MEMERR_REG_PARCTL])
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: *((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN4_MEMERR_REG_VADDR])
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: 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(*((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * write_parctl + TME_SUN4C_MEMERR_REG_PARCTL]));
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(*((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * 0 + TME_SUN4_MEMERR_REG_VADDR]));
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(*((tme_uint32_t *) &memerr_reg[TME_SUN44C_MEMERR_SIZ_REG * write_csr + TME_SUN44C_MEMERR_REG_CSR]));
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
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: tme_uint8_t memory_buffer[sizeof(tme_uint32_t)];
465: struct tme_sun_mmu_pte pte_mmu;
466: const tme_shared tme_uint8_t *memory_data_read;
467: tme_shared tme_uint8_t *memory_data_write;
468: int rc;
469:
470: /* recover our initiator's bus connection and sun4: */
471: conn_bus_init = (struct tme_bus_connection *) _conn_bus_init;
472: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
473:
474: /* get the address and size for this cycle: */
475: address = cycle_init->tme_bus_cycle_address;
476: cycle_size = cycle_init->tme_bus_cycle_size;
477:
478: /* recover the TLB entry for this cycle: */
479: tlb = sun4->tme_sun4_memtest_tlb;
480: assert (tlb != NULL);
481:
482: /* busy the TLB entry that triggered this cycle: */
483: tme_bus_tlb_busy(tlb);
484:
485: /* if the TLB entry is invalid, return now: */
486: if (tme_bus_tlb_is_invalid(tlb)) {
487:
488: /* unbusy the TLB entry and return now: */
489: tme_bus_tlb_unbusy(tlb);
490: return (EBADF);
491: }
492:
493: /* get the PTE for this address and context from the MMU: */
494: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu,
495: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init),
496: address,
497: &pte_mmu);
498: assert (rc == TME_OK);
499:
500: /* if this cycle is a read: */
501: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
502:
503: /* get a pointer to the data to read: */
504: memory_data_read
505: = (sun4->tme_sun4_memerr_tlb_emulator_off_read
506: + address);
507:
508: /* dispatch on the cycle size, to transfer the data from memory
509: into the memory buffer: */
510: switch (cycle_size) {
511: default:
512: assert (FALSE);
513: /* FALLTHROUGH */
514: case sizeof(tme_uint8_t):
515: tme_memory_write8(&memory_buffer[0],
516: tme_memory_bus_read8(memory_data_read,
517: tlb->tme_bus_tlb_rwlock,
518: sizeof(tme_uint8_t),
519: sizeof(tme_uint32_t)),
520: sizeof(tme_uint32_t));
521: break;
522: case sizeof(tme_uint16_t):
523: tme_memory_write16((tme_uint16_t *) &memory_buffer[0],
524: tme_memory_bus_read16((const tme_shared tme_uint16_t *) memory_data_read,
525: tlb->tme_bus_tlb_rwlock,
526: sizeof(tme_uint16_t),
527: sizeof(tme_uint32_t)),
528: sizeof(tme_uint32_t));
529: break;
530: case sizeof(tme_uint32_t):
531: tme_memory_write32((tme_uint32_t *) &memory_buffer[0],
532: tme_memory_bus_read32((const tme_shared tme_uint32_t *) memory_data_read,
533: tlb->tme_bus_tlb_rwlock,
534: sizeof(tme_uint32_t),
535: sizeof(tme_uint32_t)),
536: sizeof(tme_uint32_t));
537: break;
538: }
539:
540: /* run the bus cycle against the memory buffer: */
541: tme_bus_cycle_xfer_memory(cycle_init,
542: &memory_buffer[0] - address,
543: address + cycle_size - 1);
544: assert (cycle_init->tme_bus_cycle_size == cycle_size);
545:
546: /* check for memory errors on this cache line fill: */
547: rc = (_tme_sun44c_memerr_check(conn_bus_init,
548: address,
549: pte_mmu.tme_sun_mmu_pte_raw,
550: memory_data_read,
551: cycle_size)
552: ? EIO
553: : TME_OK);
554: }
555:
556: /* otherwise, this cycle must be a write: */
557: else {
558: assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE);
559:
560: /* run the bus cycle against the memory buffer: */
561: tme_bus_cycle_xfer_memory(cycle_init,
562: &memory_buffer[0] - address,
563: address + cycle_size - 1);
564: assert (cycle_init->tme_bus_cycle_size == cycle_size);
565:
566: /* get a pointer to the data to write: */
567: memory_data_write
568: = (sun4->tme_sun4_memerr_tlb_emulator_off_write
569: + address);
570:
571: /* dispatch on the cycle size, to transfer the data from the
572: memory buffer to memory: */
573: switch (cycle_size) {
574: default:
575: assert (FALSE);
576: /* FALLTHROUGH */
577: case sizeof(tme_uint8_t):
578: tme_memory_bus_write8(memory_data_write,
579: tme_memory_read8(&memory_buffer[0],
580: sizeof(tme_uint8_t)),
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: tme_memory_read16((tme_uint16_t *) &memory_buffer[0],
588: sizeof(tme_uint16_t)),
589: tlb->tme_bus_tlb_rwlock,
590: sizeof(tme_uint16_t),
591: sizeof(tme_uint32_t));
592: break;
593: case sizeof(tme_uint32_t):
594: tme_memory_bus_write32((tme_shared tme_uint32_t *) memory_data_write,
595: tme_memory_read32((tme_uint32_t *) &memory_buffer[0],
596: sizeof(tme_uint32_t)),
597: tlb->tme_bus_tlb_rwlock,
598: sizeof(tme_uint32_t),
599: sizeof(tme_uint32_t));
600: break;
601: }
602:
603: /* add any memory errors caused by this write: */
604: _tme_sun44c_memerr_update(sun4,
605: pte_mmu.tme_sun_mmu_pte_raw,
606: memory_data_write,
607: cycle_size);
608: rc = TME_OK;
609: }
610:
611: /* unbusy the TLB entry and invalidate it. this hurts performance,
612: since it keeps TLB entries valid only for one cycle at a time,
613: but it's simple and handles the problem of memory error testing
614: in the presence of virtual address aliases (addresses that have
615: never been written to can suddenly have read errors): */
616: tme_bus_tlb_unbusy(tlb);
617: tme_bus_tlb_invalidate(tlb);
618: sun4->tme_sun4_memtest_tlb = NULL;
619:
620: return (rc);
621: }
622:
623: /* this fills TLBs when memory error testing is visible: */
624: int
625: _tme_sun44c_tlb_fill_memerr(const struct tme_bus_connection *conn_bus_init,
626: struct tme_bus_tlb *tlb,
627: tme_uint32_t *_asi_mask,
628: tme_uint32_t address,
629: unsigned int cycle_type)
630: {
631: struct tme_sun4 *sun4;
632: tme_uint32_t asi_mask;
633: struct tme_sun_mmu_pte pte_mmu;
634: int rc;
635:
636: /* recover our sun4: */
637: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
638:
639: /* recover the ASI mask: */
640: asi_mask = *_asi_mask;
641:
642: /* this ASI mask must be a single ASI, for user or supervisor
643: instruction or data: */
644: assert (asi_mask == TME_SPARC32_ASI_MASK_UD
645: || asi_mask == TME_SPARC32_ASI_MASK_UI
646: || asi_mask == TME_SPARC32_ASI_MASK_SD
647: || asi_mask == TME_SPARC32_ASI_MASK_SI);
648:
649: /* invalidate any other memory test TLB entry: */
650: if (sun4->tme_sun4_memtest_tlb != NULL
651: && sun4->tme_sun4_memtest_tlb != tlb) {
652: tme_bus_tlb_invalidate(sun4->tme_sun4_memtest_tlb);
653: }
654: sun4->tme_sun4_memtest_tlb = NULL;
655: #ifndef NDEBUG
656: sun4->tme_sun4_memerr_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
657: sun4->tme_sun4_memerr_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
658: #endif /* !NDEBUG */
659:
660: /* memory error testing must be active: */
661: assert (TME_SUN44C_MEMERR_VISIBLE(sun4));
662:
663: /* fill this TLB entry from the MMU: */
664: rc = _tme_sun44c_tlb_fill_mmu(conn_bus_init,
665: tlb,
666: _asi_mask,
667: address,
668: cycle_type);
669: assert (rc == TME_OK);
670:
671: /* get the PTE for this address and context from the MMU: */
672: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu,
673: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init),
674: address,
675: &pte_mmu);
676: assert (rc == TME_OK);
677:
678: /* if this PTE is valid and for onboard memory: */
679: if ((pte_mmu.tme_sun_mmu_pte_raw
680: & (TME_SUN44C_PTE_VALID
681: | TME_SUN44C_PTE_PGTYPE))
682: == (TME_SUN44C_PTE_VALID
683: | 0 /* TME_SUN44C_PGTYPE_OBMEM */)) {
684:
685: /* this TLB entry should have no shift: */
686: if (tlb->tme_bus_tlb_addr_shift != 0) {
687: abort();
688: }
689:
690: /* if this is a read: */
691: if (cycle_type == TME_BUS_CYCLE_READ) {
692:
693: /* invalidate this TLB entry for writes: */
694: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
695:
696: /* if this TLB entry allows fast reading, and there are bad
697: memory addresses: */
698: if (tlb->tme_bus_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF
699: && sun4->tme_sun4_memerr_bad_memory_count > 0) {
700:
701: /* we will handle this read: */
702: sun4->tme_sun4_memerr_tlb_emulator_off_read = tlb->tme_bus_tlb_emulator_off_read;
703: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
704: tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init;
705: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus;
706: }
707: }
708:
709: /* otherwise, this must be a write: */
710: else {
711: if (cycle_type != TME_BUS_CYCLE_WRITE) {
712: abort();
713: }
714:
715: /* invalidate this TLB entry for reads: */
716: tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
717:
718: /* if this TLB entry allows fast writing: */
719: if (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
720:
721: /* we will handle this write: */
722: sun4->tme_sun4_memerr_tlb_emulator_off_write = tlb->tme_bus_tlb_emulator_off_write;
723: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
724: tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init;
725: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_bus;
726: }
727: }
728:
729: /* finish invalidating this TLB entry for the other cycle type: */
730: assert (tlb->tme_bus_tlb_cycles_ok & cycle_type);
731: tlb->tme_bus_tlb_cycles_ok = cycle_type;
732: tlb->tme_bus_tlb_addr_offset = 0;
733: }
734:
735: /* remember this TLB entry: */
736: sun4->tme_sun4_memtest_tlb = tlb;
737:
738: /* return success: */
739: return (TME_OK);
740: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.