|
|
1.1 root 1: /* $Id: sun44c-mmu.c,v 1.3 2007/09/06 23:25:20 fredette Exp $ */
2:
3: /* machine/sun4/sun44c-mmu.c - implementation of Sun 4/4c MMU emulation: */
4:
5: /*
6: * Copyright (c) 2005, 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-mmu.c,v 1.3 2007/09/06 23:25:20 fredette Exp $");
38:
39: /* includes: */
40: #include "sun4-impl.h"
41:
42: /* macros: */
43:
44: /* real sun4/4c PTE page types: */
45: #define TME_SUN44C_PGTYPE_OBMEM (0)
46: #define TME_SUN44C_PGTYPE_OBIO (1)
47: #define TME_SUN4_PGTYPE_VME_D16 (2)
48: #define TME_SUN4_PGTYPE_VME_D32 (3)
49:
50: /* real sun4 bus error register bits: */
51: #define TME_SUN4_BUSERR_WATCHDOG TME_BIT(0) /* watchdog or user reset */
52: #define TME_SUN4_BUSERR_SIZE TME_BIT(1) /* size error */
53: /* bit 2 unused */
54: /* bit 3 unused */
55: #define TME_SUN4_BUSERR_VMEBUSERR TME_BIT(4) /* VME bus error */
56: #define TME_SUN4_BUSERR_TIMEOUT TME_BIT(5) /* timeout error */
57: #define TME_SUN4_BUSERR_PROTERR TME_BIT(6) /* MMU protection error */
58: #define TME_SUN4_BUSERR_INVALID TME_BIT(7) /* MMU page invalid error */
59:
60: /* real sun4c synchronous error register bits: */
61: #define TME_SUN4C_SYNC_ERR_WATCHDOG TME_BIT(0) /* watchdog or user reset */
62: #define TME_SUN4C_SYNC_ERR_SIZE TME_BIT(1) /* size error */
63: /* bit 2 unused */
64: #define TME_SUN4C_SYNC_ERR_MEMORY TME_BIT(3) /* memory error */
65: #define TME_SUN4C_SYNC_ERR_SBUS TME_BIT(4) /* SBus error */
66: #define TME_SUN4C_SYNC_ERR_TIMEOUT TME_BIT(5) /* timeout error */
67: #define TME_SUN4C_SYNC_ERR_PROTERR TME_BIT(6) /* MMU protection error */
68: #define TME_SUN4C_SYNC_ERR_INVALID TME_BIT(7) /* MMU page invalid error */
69: #define TME_SUN4C_SYNC_ERR_WRITE TME_BIT(15) /* error happened on write */
70:
71: /* real sun4c asynchronous error register bits: */
72: #define TME_SUN4C_ASYNC_ERR_MULTIPLE TME_BIT(0) /* multiple errors detected */
73: #define TME_SUN4C_ASYNC_ERR_SBUS TME_BIT(1) /* SBus error */
74: /* bit 2 unused */
75: #define TME_SUN4C_ASYNC_ERR_MEMORY TME_BIT(3) /* memory error */
76: #define TME_SUN4C_ASYNC_ERR_DVMA TME_BIT(4) /* DVMA error */
77: #define TME_SUN4C_ASYNC_ERR_TIMEOUT TME_BIT(5) /* timeout error */
78: #define TME_SUN4C_ASYNC_ERR_PROTERR TME_BIT(6) /* MMU protection error */
79: #define TME_SUN4C_ASYNC_ERR_INVALID TME_BIT(7) /* MMU page invalid error (not 4/60?) */
80: #define TME_SUN4C_ASYNC_ERR_SIZE_MASK (0x0300) /* log2 of access size */
81:
82: /* common bus error bits: */
83: #define TME_SUN44C_BUSERR_COMMON_INVALID TME_BIT(0)
84: #define TME_SUN44C_BUSERR_COMMON_PROTERR TME_BIT(1)
85: #define TME_SUN44C_BUSERR_COMMON_TIMEOUT TME_BIT(2)
86: #define TME_SUN44C_BUSERR_COMMON_MEMORY TME_BIT(3)
87: #define TME_SUN4C_BUSERR_COMMON_SBUS TME_BIT(4)
88: #define TME_SUN4_BUSERR_COMMON_VMEBUS TME_BIT(5)
89: #define TME_SUN4C_BUSERR_COMMON_PGTYPE TME_BIT(6)
90:
91: /* this logs a bus error: */
92: static inline void
93: _tme_sun44c_buserr_log(struct tme_sun4 *sun4,
94: tme_uint32_t vaddr,
95: const struct tme_bus_cycle *cycle,
96: unsigned int async,
97: tme_uint32_t common_err,
98: tme_uint32_t spec_err)
99: {
100: struct tme_sun_mmu_pte pte;
101: tme_uint32_t pte_sun44c;
102: tme_uint32_t paddr;
103: const char *bus_name;
104: const char *err_type;
105: const char *err_name;
106: int rc;
107:
108: /* get the PTE involved. NB we wrap this call so this entire
109: function will get optimized away under TME_NO_LOG: */
110: /* XXX FIXME - this uses the system context register, which may not
111: be right for DVMA? */
112: #ifndef TME_NO_LOG
113: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu,
114: sun4->tme_sun44c_context,
115: vaddr,
116: &pte);
117: #else /* TME_NO_LOG */
118: rc = TME_OK;
119: pte.tme_sun_mmu_pte_raw = 0;
120: #endif /* TME_NO_LOG */
121: assert (rc == TME_OK);
122: pte_sun44c = pte.tme_sun_mmu_pte_raw;
123:
124: /* get the physical address: */
125: if (TME_SUN4_IS_SUN4C(sun4)) {
126: paddr = (((pte_sun44c & TME_SUN4C_PTE_PGFRAME) * TME_SUN4C_PAGE_SIZE)
127: | (vaddr % TME_SUN4C_PAGE_SIZE));
128: }
129: else {
130: paddr = (((pte_sun44c & TME_SUN4_PTE_PGFRAME) * TME_SUN4_PAGE_SIZE)
131: | (vaddr % TME_SUN4_PAGE_SIZE));
132: }
133:
134: /* this silences gcc -Wuninitialized: */
135: bus_name = NULL;
136:
137: /* get the bus name: */
138: switch (TME_FIELD_MASK_EXTRACTU(pte_sun44c, TME_SUN44C_PTE_PGTYPE)) {
139: case TME_SUN44C_PGTYPE_OBMEM:
140: bus_name = "obmem";
141: break;
142: case TME_SUN44C_PGTYPE_OBIO:
143: if (TME_SUN4_IS_SUN4C(sun4)) {
144: paddr |= 0xf0000000;
145: bus_name = (paddr >= TME_SUN4C_OBIO_SBUS
146: ? "SBus"
147: : "mainbus");
148: }
149: else {
150: bus_name = "obio";
151: }
152: break;
153: case TME_SUN4_PGTYPE_VME_D16:
154: bus_name = (TME_SUN4_IS_SUN4C(sun4) ? "TYPE_2" : "VME_D16");
155: break;
156: case TME_SUN4_PGTYPE_VME_D32:
157: bus_name = (TME_SUN4_IS_SUN4C(sun4) ? "TYPE_3" : "VME_D32");
158: break;
159: }
160:
161: /* get the error type and name: */
162: err_type = (TME_SUN4_IS_SUN4C(sun4)
163: ? (async
164: ? "async "
165: : "sync ")
166: : "");
167: err_name = "other";
168: if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) err_name = "timeout";
169: if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) err_name = "memory";
170: if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) err_name = "page invalid";
171: if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) err_name = "page protection";
172:
173: /* log this bus error: */
174: tme_log(TME_SUN4_LOG_HANDLE(sun4), 500, TME_OK,
175: (TME_SUN4_LOG_HANDLE(sun4),
176: _("%s%s buserr, virtual 0x%08x, %s 0x%08x, %serr = 0x%02x"),
177: err_type,
178: err_name,
179: vaddr,
180: bus_name,
181: paddr,
182: err_type,
183: spec_err));
184: }
185:
186: /* our sun4/4c common bus error handler: */
187: static int
188: _tme_sun44c_buserr_common(const void *_conn_bus_init,
189: const struct tme_bus_tlb *tlb,
190: const struct tme_bus_cycle *cycle,
191: unsigned int common_err)
192: {
193: const struct tme_bus_connection *conn_bus_init;
194: struct tme_sun4 *sun4;
195: tme_uint32_t vaddr;
196: unsigned int log2_size;
197: tme_uint32_t async_err;
198: tme_uint32_t sync_err;
199:
200: /* recover the initiator's bus connection and sun4: */
201: conn_bus_init = (struct tme_bus_connection *) _conn_bus_init;
202: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
203:
204: /* get the virtual address. certain errors, like memory errors,
205: still allow the cycle to complete, and for those we have to
206: subtract the cycle size from the post-cycle address: */
207: vaddr = cycle->tme_bus_cycle_address;
208: if (tlb != NULL) {
209: vaddr -= tlb->tme_bus_tlb_addr_offset;
210: }
211: if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) {
212: vaddr -= cycle->tme_bus_cycle_size;
213: }
214:
215: /* calculate the log2 of the cycle size: */
216: for (log2_size = 0;
217: (1 << log2_size) < cycle->tme_bus_cycle_size;
218: log2_size++);
219:
220: /* if this is a sun4c: */
221: if (TME_SUN4_IS_SUN4C(sun4)) {
222:
223: /* if this is any cycle not initiated by the CPU, or if this is a
224: CPU write cycle that was not faulted by the MMU: */
225: if (conn_bus_init->tme_bus_connection.tme_connection_type != TME_CONNECTION_BUS_SPARC
226: || (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
227: && !(common_err
228: & (TME_SUN44C_BUSERR_COMMON_INVALID
229: | TME_SUN44C_BUSERR_COMMON_PROTERR
230: | TME_SUN4C_BUSERR_COMMON_PGTYPE)))) {
231:
232: /* this is an asynchronous error: */
233: async_err = 0;
234: if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) async_err |= TME_SUN4C_ASYNC_ERR_TIMEOUT;
235: if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) async_err |= TME_SUN4C_ASYNC_ERR_MEMORY;
236: if (common_err & TME_SUN4C_BUSERR_COMMON_SBUS) async_err |= TME_SUN4C_ASYNC_ERR_SBUS;
237: if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) async_err |= TME_SUN4C_ASYNC_ERR_INVALID;
238: if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) async_err |= TME_SUN4C_ASYNC_ERR_PROTERR;
239: if (conn_bus_init->tme_bus_connection.tme_connection_type != TME_CONNECTION_BUS_SPARC) {
240: async_err |= TME_SUN4C_ASYNC_ERR_DVMA;
241: }
242:
243: /* if this is the first asynchronous error: */
244: if (sun4->tme_sun4c_async_err == 0) {
245:
246: /* set the asynchronous virtual address register: */
247: sun4->tme_sun4c_async_vaddr = vaddr;
248:
249: /* add the cycle size to the asynchronous error register value: */
250: TME_FIELD_MASK_DEPOSITU(async_err, TME_SUN4C_ASYNC_ERR_SIZE_MASK, log2_size);
251: }
252:
253: /* otherwise, this is not the first asynchronous error: */
254: else {
255:
256: /* there are multiple asynchronous errors: */
257: async_err |= TME_SUN4C_ASYNC_ERR_MULTIPLE;
258: }
259:
260: /* update the asynchronous error register: */
261: sun4->tme_sun4c_async_err |= async_err;
262:
263: /* send an NMI to the CPU: */
264: sun4->tme_sun4_int_signals[TME_SPARC_IPL_NMI / 8] |= TME_BIT(TME_SPARC_IPL_NMI % 8);
265: _tme_sun4_ipl_check(sun4);
266:
267: /* log this bus error: */
268: _tme_sun44c_buserr_log(sun4,
269: vaddr,
270: cycle,
271: TRUE,
272: common_err,
273: async_err);
274:
275: /* asynchronous errors aren't reported to the CPU as faults, but
276: they are reported as faults to another bus master (for whom
277: the error is really synchronous): */
278: return (conn_bus_init->tme_bus_connection.tme_connection_type == TME_CONNECTION_BUS_SPARC
279: ? TME_OK
280: : (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY)
281: ? EIO
282: : (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT)
283: ? ENOENT
284: : EFAULT);
285: }
286:
287: /* this is a synchronous error. NB that the cycle is only
288: considered a write if it's only a write cycle; read cycles and
289: all parts of read/modify/write cycles are considered reads: */
290: sync_err = 0;
291: if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) sync_err |= TME_SUN4C_SYNC_ERR_TIMEOUT;
292: if (common_err & TME_SUN44C_BUSERR_COMMON_MEMORY) sync_err |= TME_SUN4C_SYNC_ERR_MEMORY;
293: if (common_err & TME_SUN4C_BUSERR_COMMON_SBUS) sync_err |= TME_SUN4C_SYNC_ERR_SBUS;
294: if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) sync_err |= TME_SUN4C_SYNC_ERR_INVALID;
295: if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) sync_err |= TME_SUN4C_SYNC_ERR_PROTERR;
296: if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
297: sync_err |= TME_SUN4C_SYNC_ERR_WRITE;
298: }
299:
300: /* set the synchronous virtual address register: */
301: sun4->tme_sun4c_sync_vaddr = vaddr;
302:
303: /* update the synchronous error register: */
304: sun4->tme_sun4c_sync_err
305: = ((sun4->tme_sun4c_sync_err
306: & ~TME_SUN4C_SYNC_ERR_WRITE)
307: | sync_err);
308: sync_err = sun4->tme_sun4c_sync_err;
309: }
310:
311: /* otherwise, this is a sun4: */
312: else {
313:
314: /* this is a synchronous bus error: */
315: sync_err = 0;
316: if (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT) sync_err |= TME_SUN4_BUSERR_TIMEOUT;
317: if (common_err & TME_SUN4_BUSERR_COMMON_VMEBUS) sync_err |= TME_SUN4_BUSERR_VMEBUSERR;
318: if (common_err & TME_SUN44C_BUSERR_COMMON_INVALID) sync_err |= TME_SUN4_BUSERR_INVALID;
319: if (common_err & TME_SUN44C_BUSERR_COMMON_PROTERR) sync_err |= TME_SUN4_BUSERR_PROTERR;
320:
321: /* set the bus error register: */
322: sun4->tme_sun4_buserr = sync_err;
323: }
324:
325: /* log this bus error: */
326: _tme_sun44c_buserr_log(sun4,
327: vaddr,
328: cycle,
329: FALSE,
330: common_err,
331: sync_err);
332:
333: /* return a bus fault code: */
334: return ((common_err & TME_SUN44C_BUSERR_COMMON_MEMORY)
335: ? EIO
336: : (common_err & TME_SUN44C_BUSERR_COMMON_TIMEOUT)
337: ? ENOENT
338: : EFAULT);
339: }
340:
341: /* this maps a bus fault code to a common bus error: */
342: static inline unsigned int
343: _tme_sun44c_bus_fault_error(int rc)
344: {
345: switch (rc) {
346: default: abort();
347: case ENOENT: return (TME_SUN44C_BUSERR_COMMON_TIMEOUT);
348: case EIO: return (TME_SUN44C_BUSERR_COMMON_MEMORY);
349: }
350: }
351:
352: /* our page-invalid cycle handler: */
353: static int
354: _tme_sun44c_mmu_invalid(void *_conn_bus_init, struct tme_bus_cycle *cycle)
355: {
356:
357: /* call the common bus error handler: */
358: return (_tme_sun44c_buserr_common(_conn_bus_init,
359: NULL,
360: cycle,
361: TME_SUN44C_BUSERR_COMMON_INVALID));
362: }
363:
364: /* our protection error cycle handler: */
365: int
366: _tme_sun44c_mmu_proterr(void *_conn_bus_init, struct tme_bus_cycle *cycle)
367: {
368:
369: /* call the common bus error handler: */
370: return (_tme_sun44c_buserr_common(_conn_bus_init,
371: NULL,
372: cycle,
373: TME_SUN44C_BUSERR_COMMON_PROTERR));
374: }
375:
376: /* the sun4/4c obio and obmem bus fault handler: */
377: int
378: _tme_sun44c_ob_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
379: {
380:
381: /* call the common bus error handler: */
382: return (_tme_sun44c_buserr_common(_conn_bus_init,
383: tlb,
384: cycle,
385: _tme_sun44c_bus_fault_error(rc)));
386: }
387:
388: /* the sun4c obmem bus fault handler: */
389: static int
390: _tme_sun4c_obmem_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
391: {
392: tme_uint8_t *buffer;
393: unsigned int bytes;
394:
395: /* sun4c obmem (at least on an SS2) apparently doesn't give timeout
396: errors, because while an SS2 PROM's memory probe code seems to
397: tolerate faults, it never clears the synchronous error register
398: when they happen, which causes problems in later self tests that
399: check that register: */
400: if (rc == ENOENT) {
401:
402: /* nonexistent obmem discards writes and reads as all-bits-one: */
403: if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
404: for (bytes = cycle->tme_bus_cycle_size, buffer = cycle->tme_bus_cycle_buffer;
405: bytes > 0;
406: bytes--, buffer += cycle->tme_bus_cycle_buffer_increment) {
407: *buffer = 0xff;
408: }
409: }
410:
411: return (TME_OK);
412: }
413:
414: /* call the common bus error handler: */
415: return (_tme_sun44c_buserr_common(_conn_bus_init,
416: tlb,
417: cycle,
418: _tme_sun44c_bus_fault_error(rc)));
419: }
420:
421: /* the sun4c sbus fault handler: */
422: static int
423: _tme_sun4c_sbus_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
424: {
425:
426: /* call the common bus error handler: */
427: return (_tme_sun44c_buserr_common(_conn_bus_init,
428: tlb,
429: cycle,
430: (TME_SUN4C_BUSERR_COMMON_SBUS
431: | _tme_sun44c_bus_fault_error(rc))));
432: }
433:
434: /* the sun4c page type (type-2 and type-3) fault handler: */
435: static int
436: _tme_sun4c_pgtype_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
437: {
438:
439: /* call the common bus error handler: */
440: return (_tme_sun44c_buserr_common(_conn_bus_init,
441: tlb,
442: cycle,
443: (TME_SUN4C_BUSERR_COMMON_PGTYPE
444: | _tme_sun44c_bus_fault_error(rc))));
445: }
446:
447: /* the sun4 VMEbus fault handler: */
448: static int
449: _tme_sun4_vmebus_fault_handler(void *_conn_bus_init, struct tme_bus_tlb *tlb, struct tme_bus_cycle *cycle, int rc)
450: {
451:
452: /* call the common bus error handler: */
453: return (_tme_sun44c_buserr_common(_conn_bus_init,
454: tlb,
455: cycle,
456: (TME_SUN4_BUSERR_COMMON_VMEBUS
457: | _tme_sun44c_bus_fault_error(rc))));
458: }
459:
460: /* our bus timeout cycle handler: */
461: static int
462: _tme_sun44c_bus_timeout(void *_sun4, struct tme_bus_cycle *cycle)
463: {
464: return (ENOENT);
465: }
466:
467: /* this fills memory TLBs from the MMU: */
468: int
469: _tme_sun44c_tlb_fill_mmu(const struct tme_bus_connection *conn_bus_init,
470: struct tme_bus_tlb *tlb,
471: tme_uint32_t *_asi_mask,
472: tme_uint32_t address,
473: unsigned int cycles)
474: {
475: struct tme_sun4 *sun4;
476: tme_uint32_t asi_mask;
477: tme_uint32_t asi_mask_si;
478: unsigned short access;
479: struct tme_bus_tlb tlb_bus;
480: unsigned int tlb_i;
481: unsigned short tlb_flags;
482:
483: /* recover our sun4: */
484: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
485:
486: /* recover the ASI mask: */
487: asi_mask = *_asi_mask;
488:
489: /* this ASI mask must be a single ASI, for user or supervisor
490: instruction or data: */
491: assert (asi_mask == TME_SPARC32_ASI_MASK_UD
492: || asi_mask == TME_SPARC32_ASI_MASK_UI
493: || asi_mask == TME_SPARC32_ASI_MASK_SD
494: || asi_mask == TME_SPARC32_ASI_MASK_SI);
495:
496: /* assume that if this TLB entry ends up good for the supervisor,
497: it's good for the supervisor instruction ASI mask: */
498: asi_mask_si = TME_SPARC32_ASI_MASK_SI;
499:
500: /* if we're in the boot state: */
501: if (__tme_predict_false((sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0)) {
502:
503: /* if this is the supervisor instruction ASI: */
504: if (asi_mask == TME_SPARC32_ASI_MASK_SI) {
505:
506: /* fill this TLB entry directly from the obio (sun4c, sbus) or
507: obmem (sun4) bus: */
508: if (TME_SUN4_IS_SUN4C(sun4)) {
509: (*sun4->tme_sun4_32_obio->tme_bus_tlb_fill)
510: (sun4->tme_sun4_32_obio,
511: tlb,
512: TME_SUN44C_PROM_BASE | (address & (TME_SUN44C_PROM_SIZE - 1)),
513: cycles);
514: }
515: else {
516: (*sun4->tme_sun4_32_obmem->tme_bus_tlb_fill)
517: (sun4->tme_sun4_32_obmem,
518: tlb,
519: TME_SUN44C_PROM_BASE | (address & (TME_SUN44C_PROM_SIZE - 1)),
520: cycles);
521: }
522:
523: /* create the mapping TLB entry: */
524: tlb_bus.tme_bus_tlb_addr_first = address & (((tme_bus_addr_t) 0) - TME_SUN44C_PROM_SIZE);
525: tlb_bus.tme_bus_tlb_addr_last = address | (TME_SUN44C_PROM_SIZE - 1);
526: tlb_bus.tme_bus_tlb_cycles_ok
527: = TME_BUS_CYCLE_READ;
528:
529: /* map the filled TLB entry: */
530: tme_bus_tlb_map(tlb, TME_SUN44C_PROM_BASE | (address % TME_SUN44C_PROM_SIZE), &tlb_bus, address);
531:
532: /* this is good for the supervisor instruction ASI only: */
533: *_asi_mask = TME_SPARC32_ASI_MASK_SI;
534:
535: /* done: */
536: return(TME_OK);
537: }
538:
539: /* this should be the supervisor data ASI only: */
540: assert (asi_mask == TME_SPARC32_ASI_MASK_SD);
541:
542: /* update the head pointer for the active boot state TLB entry
543: list: */
544: tlb_i = sun4->tme_sun44c_boot_state_tlb_next
545: = ((sun4->tme_sun44c_boot_state_tlb_next
546: + 1)
547: % TME_SUN44C_BOOT_STATE_TLBS);
548:
549: /* if the new head pointer already has a TLB entry, and it doesn't
550: happen to be the same as this TLB entry, invalidate it: */
551: if (sun4->tme_sun44c_boot_state_tlbs[tlb_i] != NULL
552: && (sun4->tme_sun44c_boot_state_tlbs[tlb_i]
553: != tlb->tme_bus_tlb_global)) {
554: tme_bus_tlb_invalidate(sun4->tme_sun44c_boot_state_tlbs[tlb_i]);
555: }
556:
557: /* add this TLB entry to the active list: */
558: sun4->tme_sun44c_boot_state_tlbs[tlb_i] = tlb->tme_bus_tlb_global;
559:
560: /* if this TLB entry ends up good for the supervisor, it's not
561: good for the supervisor instruction ASI: */
562: asi_mask_si = 0;
563: }
564:
565: /* thread the initiator's bus connection down to
566: _tme_sun44c_tlb_fill_pte(): */
567: tlb->tme_bus_tlb_fault_handlers[0]
568: .tme_bus_tlb_fault_handler_private = (void *) conn_bus_init;
569:
570: /* fill this TLB entry from the MMU: */
571: access
572: = ((cycles & TME_BUS_CYCLE_WRITE)
573: ? TME_SUN_MMU_PTE_PROT_RW
574: : TME_SUN_MMU_PTE_PROT_RO);
575: access
576: = ((asi_mask == TME_SPARC32_ASI_MASK_UD
577: || asi_mask == TME_SPARC32_ASI_MASK_UI)
578: ? TME_SUN_MMU_PTE_PROT_USER(access)
579: : TME_SUN_MMU_PTE_PROT_SYSTEM(access));
580: tlb_flags = tme_sun_mmu_tlb_fill(sun4->tme_sun44c_mmu,
581: tlb,
582: TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus),
583: address,
584: access);
585:
586: /* this TLB entry is good for the program and instruction ASIs
587: for the user and/or the supervisor: */
588: *_asi_mask
589: = (((tlb_flags & TME_SUN_MMU_TLB_USER)
590: ? (TME_SPARC32_ASI_MASK_UD
591: | TME_SPARC32_ASI_MASK_UI)
592: : 0)
593: | ((tlb_flags & TME_SUN_MMU_TLB_SYSTEM)
594: ? (TME_SPARC32_ASI_MASK_SD
595: | asi_mask_si)
596: : 0));
597:
598: return (TME_OK);
599: }
600:
601: /* our sparc TLB filler: */
602: int
603: _tme_sun44c_tlb_fill_sparc(struct tme_sparc_bus_connection *conn_sparc,
604: struct tme_sparc_tlb *tlb_sparc,
605: tme_uint32_t asi_mask,
606: tme_bus_addr_t address,
607: unsigned int cycles)
608: {
609: struct tme_sun4 *sun4;
610: struct tme_bus_tlb *tlb;
611: struct tme_bus_tlb tlb_bus;
612:
613: /* recover our sun4: */
614: sun4 = (struct tme_sun4 *) conn_sparc->tme_sparc_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
615:
616: /* get the generic bus TLB: */
617: tlb = &tlb_sparc->tme_sparc_tlb_bus_tlb;
618:
619: /* if this is the for user or supervisor data or instruction address
620: spaces: */
621: if (__tme_predict_true(TME_SPARC_ASI_MASK_OVERLAP(asi_mask,
622: (TME_SPARC32_ASI_MASK_UI
623: | TME_SPARC32_ASI_MASK_SI
624: | TME_SPARC32_ASI_MASK_UD
625: | TME_SPARC32_ASI_MASK_SD)))) {
626:
627: /* call the current TLB filler: */
628: tlb_sparc->tme_sparc_tlb_asi_mask = asi_mask;
629: return ((*sun4->tme_sun4_tlb_fill)(&conn_sparc->tme_sparc_bus_connection,
630: tlb,
631: &tlb_sparc->tme_sparc_tlb_asi_mask,
632: address,
633: cycles));
634: }
635:
636:
637: /* assume that we need a TLB entry that allows reading and writing
638: over the entire address space, using the control cycle handler: */
639: tme_bus_tlb_initialize(tlb);
640: tlb->tme_bus_tlb_addr_first = 0;
641: tlb->tme_bus_tlb_addr_last = (((tme_uint32_t) 0) - 1);
642: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
643: tlb_sparc->tme_sparc_tlb_asi_mask = asi_mask;
644: tlb->tme_bus_tlb_cycle = _tme_sun44c_control_cycle_handler;
645: tlb->tme_bus_tlb_cycle_private = &sun4->tme_sun4_asis[TME_SPARC_ASI_MASK_WHICH(asi_mask)];
646:
647: /* if this address space isn't defined: */
648: if (__tme_predict_false(sun4->tme_sun4_asis[TME_SPARC_ASI_MASK_WHICH(asi_mask)].tme_sun4_asi_sun4 == NULL)) {
649: abort();
650: }
651:
652: /* if this is for control space: */
653: if (__tme_predict_false(asi_mask == TME_SPARC_ASI_MASK(TME_SUN4_32_ASI_CONTROL))) {
654:
655: /* if this address is before the UART bypass: */
656: if (__tme_predict_true(address < TME_SUN44C_CONTROL_UART_BYPASS)) {
657:
658: /* we cover the address space before the UART bypass: */
659: tlb->tme_bus_tlb_addr_last = TME_SUN44C_CONTROL_UART_BYPASS - 1;
660: }
661:
662: /* otherwise, this address is within the UART bypass: */
663: else {
664:
665: /* fill this TLB entry directly from the obio bus: */
666: (*sun4->tme_sun4_32_obio->tme_bus_tlb_fill)
667: (sun4->tme_sun4_32_obio,
668: tlb,
669: (address % TME_SUN_Z8530_SIZE) + TME_SUN44C_OBIO_ZS0,
670: cycles);
671:
672: /* create the mapping TLB entry: */
673: tlb_bus.tme_bus_tlb_addr_first = address & (((tme_uint32_t) 0) - TME_SUN_Z8530_SIZE);
674: tlb_bus.tme_bus_tlb_addr_last = address | (TME_SUN_Z8530_SIZE - 1);
675: tlb_bus.tme_bus_tlb_cycles_ok
676: = (TME_BUS_CYCLE_READ
677: | TME_BUS_CYCLE_WRITE);
678:
679: /* map the filled TLB entry: */
680: tme_bus_tlb_map(tlb, (address % TME_SUN_Z8530_SIZE) + TME_SUN44C_OBIO_ZS0, &tlb_bus, address);
681: }
682: }
683:
684: /* done: */
685: return (TME_OK);
686: }
687:
688: /* our bus TLB filler: */
689: int
690: _tme_sun44c_tlb_fill_bus(struct tme_bus_connection *conn_bus_init,
691: struct tme_bus_tlb *tlb,
692: tme_uint32_t address,
693: unsigned int cycles)
694: {
695: struct tme_sun4 *sun4;
696: struct tme_sun4_bus_connection *conn_sun4;
697: tme_uint32_t base, mask;
698: tme_uint32_t asi_mask;
699: struct tme_bus_tlb tlb_bus;
700: unsigned int tlb_i;
701:
702: /* recover our sun4: */
703: sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
704:
705: /* recover the internal sun4 mainbus, or sun4c board, connection: */
706: conn_sun4 = (struct tme_sun4_bus_connection *) conn_bus_init;
707:
708: /* dispatch on the internal connection. this turns the bus address
709: into a DVMA base address and size, except for the register
710: connections, which are handled specially: */
711: switch (conn_sun4->tme_sun4_bus_connection_which) {
712:
713: case TME_SUN4_32_CONN_BUS_OBIO:
714: if (TME_SUN4_IS_SUN4C(sun4)) {
715: base = 0x00000000;
716: mask = ((tme_uint32_t) 0) - 1;
717: }
718: else {
719: abort();
720: }
721: break;
722:
723: case TME_SUN4_32_CONN_REG_TIMER:
724:
725: /* return a TLB entry that allows reading and writing the two timers: */
726: tme_bus_tlb_initialize(tlb);
727: tlb->tme_bus_tlb_addr_first = 0;
728: tlb->tme_bus_tlb_addr_last = (TME_SUN44C_TIMER_SIZ_REG * 2) - 1;
729: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
730: tlb->tme_bus_tlb_cycle_private = sun4;
731: tlb->tme_bus_tlb_cycle = _tme_sun4_timer_cycle_control;
732: return (TME_OK);
733:
734: case TME_SUN4_32_CONN_REG_INTREG:
735: case TME_SUN4C4M_CONN_REG_AUXREG:
736:
737: /* return a TLB entry that allows reading and writing these 8-bit
738: registers: */
739: tme_bus_tlb_initialize(tlb);
740: tlb->tme_bus_tlb_addr_first = 0;
741: tlb->tme_bus_tlb_addr_last = sizeof(tme_uint8_t) - 1;
742: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
743: tlb->tme_bus_tlb_cycle_private = sun4;
744: tlb->tme_bus_tlb_cycle
745: = (conn_sun4->tme_sun4_bus_connection_which == TME_SUN4C4M_CONN_REG_AUXREG
746: ? _tme_sun4c_auxreg_cycle_control
747: : _tme_sun44c_intreg_cycle_control);
748: return (TME_OK);
749:
750:
751: case TME_SUN4_32_CONN_REG_MEMERR:
752:
753: /* return a TLB entry that allows reading and writing the memory
754: error register(s): */
755: tme_bus_tlb_initialize(tlb);
756: tlb->tme_bus_tlb_addr_first = 0;
757: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
758: tlb->tme_bus_tlb_cycle_private = sun4;
759: tlb->tme_bus_tlb_cycle = _tme_sun44c_memerr_cycle_control;
760:
761: /* the size of the memory error register(s) depends on
762: the model: */
763: tlb->tme_bus_tlb_addr_last
764: = (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)
765: ? (TME_SUN44C_MEMERR_SIZ_REG * 2)
766: : TME_SUN44C_MEMERR_SIZ_REG) - 1;
767:
768: return (TME_OK);
769:
770: default: abort();
771: }
772:
773: /* update the head pointer for the active SDVMA TLB entry list: */
774: tlb_i = sun4->tme_sun44c_sdvma_tlb_next
775: = ((sun4->tme_sun44c_sdvma_tlb_next
776: + 1)
777: & (TME_SUN44C_SDVMA_TLBS - 1));
778:
779: /* if the new head pointer already has a TLB entry, and it doesn't
780: happen to be the same as this TLB entry, invalidate it: */
781: if (sun4->tme_sun44c_sdvma_tlbs[tlb_i] != NULL
782: && (sun4->tme_sun44c_sdvma_tlbs[tlb_i]
783: != tlb->tme_bus_tlb_global)) {
784: tme_bus_tlb_invalidate(sun4->tme_sun44c_sdvma_tlbs[tlb_i]);
785: }
786:
787: /* add this TLB entry to the active list: */
788: sun4->tme_sun44c_sdvma_tlbs[tlb_i] = tlb->tme_bus_tlb_global;
789:
790: /* if system DVMA is disabled: */
791: if (__tme_predict_false(!(sun4->tme_sun44c_enable & TME_SUN44C_ENA_SDVMA))) {
792:
793: /* return a TLB entry that will generate a bus fault: */
794: tme_bus_tlb_initialize(tlb);
795: tlb->tme_bus_tlb_addr_first = 0;
796: tlb->tme_bus_tlb_addr_last = mask;
797: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
798: tlb->tme_bus_tlb_cycle_private = sun4;
799: tlb->tme_bus_tlb_cycle = _tme_sun44c_bus_timeout;
800: TME_BUS_TLB_FAULT_HANDLER(tlb,
801: (TME_SUN4_IS_SUN4C(sun4)
802: ? _tme_sun4c_sbus_fault_handler
803: : _tme_sun4_vmebus_fault_handler),
804: conn_bus_init);
805: return (TME_OK);
806: }
807:
808: assert (!(address & base)
809: && (address <= mask));
810:
811: /* call the current TLB filler: */
812: asi_mask = TME_SPARC32_ASI_MASK_SD;
813: (*sun4->tme_sun4_tlb_fill)(conn_bus_init,
814: tlb,
815: &asi_mask,
816: address,
817: cycles);
818:
819: /* create the mapping TLB entry. we do this even if base == 0,
820: because the TLB entry as currently filled may cover more address
821: space than DVMA space on this machine is supposed to cover: */
822: tlb_bus.tme_bus_tlb_addr_first = 0;
823: tlb_bus.tme_bus_tlb_addr_last = mask;
824: tlb_bus.tme_bus_tlb_cycles_ok
825: = (TME_BUS_CYCLE_READ
826: | TME_BUS_CYCLE_WRITE);
827:
828: /* map the filled TLB entry: */
829: tme_bus_tlb_map(tlb, address | base, &tlb_bus, address);
830:
831: return (TME_OK);
832: }
833:
834: /* our post-MMU TLB filler: */
835: static int
836: _tme_sun44c_tlb_fill_pte(void *_sun4,
837: struct tme_bus_tlb *tlb,
838: struct tme_sun_mmu_pte *pte,
839: tme_uint32_t *_address,
840: unsigned int cycles)
841: {
842: struct tme_sun4 *sun4;
843: tme_uint32_t address;
844: unsigned int bus_type;
845: void *_conn_bus_init;
846: struct tme_bus_connection *conn_bus_resp;
847: tme_bus_fault_handler bus_fault_handler;
848: int rc;
849:
850: /* recover our sun4: */
851: sun4 = (struct tme_sun4 *) _sun4;
852:
853: /* recover the initiator's bus connection. this is threaded down
854: from _tme_sun44c_tlb_fill_mmu(): */
855: _conn_bus_init =
856: tlb->tme_bus_tlb_fault_handlers[0]
857: .tme_bus_tlb_fault_handler_private;
858:
859: /* get the initial physical address and bus type: */
860: address = pte->tme_sun_mmu_pte_raw;
861: if (TME_SUN4_IS_SUN4C(sun4)) {
862: address = (address & TME_SUN4C_PTE_PGFRAME) * TME_SUN4C_PAGE_SIZE;
863: address += *_address % TME_SUN4C_PAGE_SIZE;
864: }
865: else {
866: address = (address & TME_SUN4_PTE_PGFRAME) * TME_SUN4_PAGE_SIZE;
867: address += *_address % TME_SUN4_PAGE_SIZE;
868: }
869: bus_type = TME_FIELD_MASK_EXTRACTU(pte->tme_sun_mmu_pte_raw, TME_SUN44C_PTE_PGTYPE);
870:
871: /* if this is obio: */
872: if (bus_type == TME_SUN44C_PGTYPE_OBIO) {
873: conn_bus_resp = sun4->tme_sun4_32_obio;
874: bus_fault_handler = _tme_sun44c_ob_fault_handler;
875: if (TME_SUN4_IS_SUN4C(sun4)) {
876: address |= 0xf0000000;
877: if (address >= TME_SUN4C_OBIO_SBUS) {
878: bus_fault_handler = _tme_sun4c_sbus_fault_handler;
879: }
880: }
881: else {
882: abort();
883: }
884: }
885:
886: /* if this is obmem: */
887: else if (bus_type == TME_SUN44C_PGTYPE_OBMEM) {
888: if (TME_SUN4_IS_SUN4C(sun4)) {
889: conn_bus_resp = sun4->tme_sun4_32_obio;
890: bus_fault_handler = _tme_sun4c_obmem_fault_handler;
891: }
892: else {
893: conn_bus_resp = sun4->tme_sun4_32_obmem;
894: bus_fault_handler = _tme_sun44c_ob_fault_handler;
895: }
896: }
897:
898: /* if this is the VME bus: */
899: else {
900: assert ((bus_type == TME_SUN4_PGTYPE_VME_D16
901: || bus_type == TME_SUN4_PGTYPE_VME_D32));
902: conn_bus_resp = sun4->tme_sun4_vmebus;
903: bus_fault_handler = _tme_sun4_vmebus_fault_handler;
904:
905: /* SS2 PROMs will try to map type-2 and type-3 space to test
906: synchronous timeouts: */
907: if (TME_SUN4_IS_SUN4C(sun4)) {
908:
909: /* return the real physical address: */
910: *_address = address;
911:
912: /* return a TLB entry that will generate a bus fault: */
913: tme_bus_tlb_initialize(tlb);
914: tlb->tme_bus_tlb_addr_first = 0;
915: tlb->tme_bus_tlb_addr_last = (((tme_uint32_t) 0) - 1);
916: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
917: tlb->tme_bus_tlb_cycle_private = sun4;
918: tlb->tme_bus_tlb_cycle = _tme_sun44c_bus_timeout;
919: TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun4c_pgtype_fault_handler, _conn_bus_init);
920: return (TME_OK);
921: }
922: }
923:
924: /* return the real physical address: */
925: *_address = address;
926:
927: /* call the bus TLB filler: */
928: rc = ((*conn_bus_resp->tme_bus_tlb_fill)
929: (conn_bus_resp, tlb, address, cycles));
930:
931: /* if the bus TLB filler succeeded, add our bus fault handler: */
932: if (rc == TME_OK) {
933: TME_BUS_TLB_FAULT_HANDLER(tlb, bus_fault_handler, _conn_bus_init);
934: }
935:
936: return (rc);
937: }
938:
939: /* this gets a PTE from the MMU: */
940: int
941: _tme_sun44c_mmu_pte_get(struct tme_sun4 *sun4, tme_uint32_t address, tme_uint32_t *_pte_sun44c)
942: {
943: struct tme_sun_mmu_pte pte;
944: tme_uint32_t pte_sun44c;
945: unsigned int pte_flags;
946: int rc;
947:
948: /* get the PTE from the MMU: */
949: rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu,
950: sun4->tme_sun44c_context,
951: address,
952: &pte);
953: assert(rc == TME_OK);
954:
955: /* form the Sun 4/4c PTE: */
956: pte_sun44c = pte.tme_sun_mmu_pte_raw;
957: pte_flags = pte.tme_sun_mmu_pte_flags;
958: if (pte_flags & TME_SUN_MMU_PTE_REF) {
959: pte_sun44c |= TME_SUN44C_PTE_REF;
960: }
961: if (pte_flags & TME_SUN_MMU_PTE_MOD) {
962: pte_sun44c |= TME_SUN44C_PTE_MOD;
963: }
964:
965: /* done: */
966: *_pte_sun44c = pte_sun44c;
967: tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
968: (TME_SUN4_LOG_HANDLE(sun4),
969: _("pte_get: PGMAP[%d:0x%08x] -> 0x%08x"),
970: sun4->tme_sun44c_context,
971: address,
972: pte_sun44c));
973: return (TME_OK);
974: }
975:
976: /* this sets a PTE into the MMU: */
977: int
978: _tme_sun44c_mmu_pte_set(struct tme_sun4 *sun4, tme_uint32_t address, tme_uint32_t pte_sun44c)
979: {
980: struct tme_sun_mmu_pte pte;
981: unsigned int pte_flags;
982: #ifndef TME_NO_LOG
983: const char *bus_name;
984: tme_bus_addr_t physical_address;
985:
986: /* this silences gcc -Wuninitialized: */
987: bus_name = NULL;
988:
989: /* log this setting: */
990: if (TME_SUN4_IS_SUN4C(sun4)) {
991: physical_address = (pte_sun44c & TME_SUN4C_PTE_PGFRAME) * TME_SUN4C_PAGE_SIZE;
992: }
993: else {
994: physical_address = (pte_sun44c & TME_SUN4_PTE_PGFRAME) * TME_SUN4_PAGE_SIZE;
995: }
996: switch (TME_FIELD_MASK_EXTRACTU(pte_sun44c, TME_SUN44C_PTE_PGTYPE)) {
997: case TME_SUN44C_PGTYPE_OBMEM: bus_name = "obmem"; break;
998: case TME_SUN44C_PGTYPE_OBIO:
999: if (TME_SUN4_IS_SUN4C(sun4)) {
1000: physical_address |= 0xf0000000;
1001: bus_name = (physical_address >= TME_SUN4C_OBIO_SBUS
1002: ? "SBus"
1003: : "mainbus");
1004: }
1005: else {
1006: bus_name = "obio";
1007: }
1008: break;
1009: case TME_SUN4_PGTYPE_VME_D16: bus_name = "VME_D16"; break;
1010: case TME_SUN4_PGTYPE_VME_D32: bus_name = "VME_D32"; break;
1011: }
1012: tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
1013: (TME_SUN4_LOG_HANDLE(sun4),
1014: _("pte_set: PGMAP[%d:0x%08x] <- 0x%08x (%s 0x%08x)"),
1015: sun4->tme_sun44c_context,
1016: address,
1017: pte_sun44c,
1018: bus_name,
1019: physical_address));
1020: #endif /* !TME_NO_LOG */
1021:
1022: /* store only the bits that the real hardware stores: */
1023: pte_sun44c
1024: &= (TME_SUN44C_PTE_VALID
1025: | TME_SUN44C_PTE_WRITE
1026: | TME_SUN44C_PTE_SYSTEM
1027: | TME_SUN44C_PTE_NC
1028: | TME_SUN44C_PTE_REF
1029: | TME_SUN44C_PTE_MOD
1030: | (TME_SUN4_IS_SUN4C(sun4)
1031: ? (TME_SUN44C_PTE_PGTYPE
1032: | TME_SUN4C_PTE_PGFRAME)
1033: : (TME_SUN44C_PTE_PGTYPE
1034: | TME_SUN4_PTE_PGFRAME)));
1035:
1036: pte.tme_sun_mmu_pte_raw = pte_sun44c;
1037:
1038: pte_flags = (pte_sun44c & TME_SUN44C_PTE_WRITE
1039: ? TME_SUN_MMU_PTE_PROT_RW
1040: : TME_SUN_MMU_PTE_PROT_RO);
1041: pte_flags = (TME_SUN_MMU_PTE_PROT_SYSTEM(pte_flags)
1042: | TME_SUN_MMU_PTE_PROT_USER(pte_sun44c & TME_SUN44C_PTE_SYSTEM
1043: ? TME_SUN_MMU_PTE_PROT_ERROR
1044: : pte_flags));
1045: if (pte_sun44c & TME_SUN44C_PTE_MOD) {
1046: pte_flags |= TME_SUN_MMU_PTE_MOD;
1047: }
1048: if (pte_sun44c & TME_SUN44C_PTE_REF) {
1049: pte_flags |= TME_SUN_MMU_PTE_REF;
1050: }
1051: if (pte_sun44c & TME_SUN44C_PTE_VALID) {
1052: pte_flags |= TME_SUN_MMU_PTE_VALID;
1053: }
1054: pte.tme_sun_mmu_pte_flags = pte_flags;
1055:
1056: return (tme_sun_mmu_pte_set(sun4->tme_sun44c_mmu,
1057: sun4->tme_sun44c_context,
1058: address,
1059: &pte));
1060: }
1061:
1062: /* this is called when the SDVMA bit is changed in the enable register: */
1063: void
1064: _tme_sun44c_mmu_sdvma_change(struct tme_sun4 *sun4)
1065: {
1066: unsigned int tlb_i;
1067:
1068: /* whenever the SDVMA bit changes, we have to invalidate all SDVMA
1069: TLB entries: */
1070: for (tlb_i = 0; tlb_i < TME_SUN44C_SDVMA_TLBS; tlb_i++) {
1071: if (sun4->tme_sun44c_sdvma_tlbs[tlb_i] != NULL) {
1072: tme_bus_tlb_invalidate(sun4->tme_sun44c_sdvma_tlbs[tlb_i]);
1073: sun4->tme_sun44c_sdvma_tlbs[tlb_i] = NULL;
1074: }
1075: }
1076: }
1077:
1078: /* this is called when the context register is set: */
1079: void
1080: _tme_sun44c_mmu_context_set(struct tme_sun4 *sun4)
1081: {
1082: unsigned int tlb_i;
1083:
1084: /* every TLB set has an extra context's worth of TLB entries.
1085: context zero is used for the "boot state", and the remaining
1086: contexts correspond to the normal MMU contexts.
1087:
1088: context zero is used for the boot state because at TLB set
1089: allocation time, TLB sets are initialized pointing to the context
1090: zero TLBs (by tme_sun_mmu_tlb_set_allocate), and TLBs must be
1091: initialized to the boot state TLBs.
1092:
1093: in the boot state, TLB fills for supervisor program references
1094: bypass the MMU and are filled to reference the PROM, and data
1095: fills are filled as normal using the current context. since context
1096: register changes can happen while in the boot state, but we only
1097: have one boot state context in the TLB sets, we have to track
1098: the data TLBs we fill in the boot state.
1099:
1100: we don't bother to track the supervisor program TLB fills, since
1101: they never change. */
1102:
1103: /* in the not-boot (i.e., normal, state): */
1104: if (__tme_predict_true(sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT)) {
1105:
1106: tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
1107: (TME_SUN4_LOG_HANDLE(sun4),
1108: _("context now #%d"),
1109: sun4->tme_sun44c_context));
1110:
1111: /* update all TLB sets to reflect the context change: */
1112: tme_sun_mmu_tlbs_context_set(sun4->tme_sun44c_mmu, sun4->tme_sun44c_context + 1);
1113: }
1114:
1115: /* in the boot state: */
1116: else {
1117:
1118: tme_log(TME_SUN4_LOG_HANDLE(sun4), 1000, TME_OK,
1119: (TME_SUN4_LOG_HANDLE(sun4),
1120: _("context now #%d (boot state)"),
1121: sun4->tme_sun44c_context));
1122:
1123: /* update all TLB sets to reflect the pseudo-context change: */
1124: tme_sun_mmu_tlbs_context_set(sun4->tme_sun44c_mmu, 0);
1125:
1126: /* invalidate all of the boot-state data TLBs: */
1127: for (tlb_i = 0; tlb_i < TME_SUN44C_BOOT_STATE_TLBS; tlb_i++) {
1128: if (sun4->tme_sun44c_boot_state_tlbs[tlb_i] != NULL) {
1129: tme_bus_tlb_invalidate(sun4->tme_sun44c_boot_state_tlbs[tlb_i]);
1130: sun4->tme_sun44c_boot_state_tlbs[tlb_i] = NULL;
1131: }
1132: }
1133: }
1134: }
1135:
1136: /* this allocates a new TLB set: */
1137: int
1138: _tme_sun44c_mmu_tlb_set_allocate(struct tme_bus_connection *conn_bus_asker,
1139: unsigned int count, unsigned int sizeof_one,
1140: struct tme_bus_tlb * tme_shared * _tlbs,
1141: tme_rwlock_t *_tlbs_rwlock)
1142: {
1143: struct tme_sun4 *sun4;
1144: int rc;
1145:
1146: /* recover our sun4: */
1147: sun4 = (struct tme_sun4 *) conn_bus_asker->tme_bus_connection.tme_connection_element->tme_element_private;
1148:
1149: /* get the MMU to allocate the TLB set: */
1150: rc = tme_sun_mmu_tlb_set_allocate(sun4->tme_sun44c_mmu, count, sizeof_one, _tlbs, _tlbs_rwlock);
1151:
1152: return (rc);
1153: }
1154:
1155: /* this creates a sun4/4c MMU: */
1156: void
1157: _tme_sun44c_mmu_new(struct tme_sun4 *sun4)
1158: {
1159: struct tme_sun_mmu_info mmu_info;
1160:
1161: memset(&mmu_info, 0, sizeof(mmu_info));
1162: mmu_info.tme_sun_mmu_info_element = sun4->tme_sun4_element;
1163: mmu_info.tme_sun_mmu_info_address_bits = 32;
1164: if (TME_SUN4_IS_SUN4C(sun4)) {
1165: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN4C_PAGE_SIZE_LOG2;
1166: mmu_info.tme_sun_mmu_info_topindex_bits = -3; /* the address hole makes the top 3 address bits the same */
1167: }
1168: else {
1169: mmu_info.tme_sun_mmu_info_pgoffset_bits = TME_SUN4_PAGE_SIZE_LOG2;
1170: }
1171: mmu_info.tme_sun_mmu_info_pteindex_bits = 18 - mmu_info.tme_sun_mmu_info_pgoffset_bits;
1172: if (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)) {
1173: mmu_info.tme_sun_mmu_info_contexts = 16;
1174: mmu_info.tme_sun_mmu_info_pmegs = 256;
1175: }
1176: else if (TME_SUN4_IS_SUN4C(sun4)) {
1177: mmu_info.tme_sun_mmu_info_contexts = 8;
1178: mmu_info.tme_sun_mmu_info_pmegs = 128;
1179: }
1180: else {
1181: abort();
1182: }
1183: mmu_info.tme_sun_mmu_info_contexts++; /* internal context zero is for the boot state */
1184: mmu_info.tme_sun_mmu_info_tlb_fill_private = sun4;
1185: mmu_info.tme_sun_mmu_info_tlb_fill = _tme_sun44c_tlb_fill_pte;
1186: mmu_info.tme_sun_mmu_info_proterr_private = &sun4->tme_sun4_dummy_connection_sparc;
1187: mmu_info.tme_sun_mmu_info_proterr = _tme_sun44c_mmu_proterr;
1188: mmu_info.tme_sun_mmu_info_invalid_private = &sun4->tme_sun4_dummy_connection_sparc;
1189: mmu_info.tme_sun_mmu_info_invalid = _tme_sun44c_mmu_invalid;
1190: sun4->tme_sun44c_mmu = tme_sun_mmu_new(&mmu_info);
1191: sun4->tme_sun44c_mmu_pmegs = mmu_info.tme_sun_mmu_info_pmegs;
1192: sun4->tme_sun4_dummy_connection_sparc.tme_connection_type = TME_CONNECTION_BUS_SPARC;
1193: sun4->tme_sun4_dummy_connection_sparc.tme_connection_element = sun4->tme_sun4_element;
1194: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.