diff options
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/luna88k/luna88k/m8820x.c | 1411 | ||||
-rw-r--r-- | sys/arch/m88k/conf/files.m88k | 3 | ||||
-rw-r--r-- | sys/arch/m88k/include/cmmu.h | 4 | ||||
-rw-r--r-- | sys/arch/m88k/include/m8820x.h | 28 | ||||
-rw-r--r-- | sys/arch/m88k/m88k/cmmu.c | 4 | ||||
-rw-r--r-- | sys/arch/m88k/m88k/m8820x_machdep.c | 1223 | ||||
-rw-r--r-- | sys/arch/mvme88k/include/m8820x.h | 16 | ||||
-rw-r--r-- | sys/arch/mvme88k/mvme88k/m8820x.c | 1329 |
8 files changed, 1364 insertions, 2654 deletions
diff --git a/sys/arch/luna88k/luna88k/m8820x.c b/sys/arch/luna88k/luna88k/m8820x.c index 02f00e3521a..1c5c17a5149 100644 --- a/sys/arch/luna88k/luna88k/m8820x.c +++ b/sys/arch/luna88k/luna88k/m8820x.c @@ -1,4 +1,4 @@ -/* $OpenBSD: m8820x.c,v 1.4 2004/08/04 15:54:35 miod Exp $ */ +/* $OpenBSD: m8820x.c,v 1.5 2004/08/06 13:23:47 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * @@ -83,189 +83,14 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/simplelock.h> #include <machine/asm_macro.h> -#include <machine/board.h> #include <machine/cpu_number.h> #include <machine/locore.h> #include <machine/cmmu.h> #include <machine/m8820x.h> - -#include <uvm/uvm_extern.h> - -#ifdef DDB -#include <ddb/db_output.h> /* db_printf() */ -#endif /* DDB */ - -/* - * On some versions of the 88200, page size flushes don't work. I am using - * sledge hammer approach till I find for sure which ones are bad XXX nivas - */ -#define BROKEN_MMU_MASK - -#ifdef DEBUG -unsigned int m8820x_debuglevel; -#define dprintf(_X_) \ - do { \ - if (m8820x_debuglevel != 0) { \ - unsigned int psr = disable_interrupts_return_psr(); \ - printf("%d: ", cpu_number()); \ - printf _X_; \ - set_psr(psr); \ - } \ - } while (0) -#else -#define dprintf(_X_) do { } while (0) -#endif - -void m8820x_cmmu_init(void); -void m8820x_setup_board_config(void); -void m8820x_cpu_configuration_print(int); -void m8820x_cmmu_shutdown_now(void); -void m8820x_cmmu_parity_enable(void); -unsigned m8820x_cmmu_cpu_number(void); -void m8820x_cmmu_set_sapr(unsigned, unsigned); -void m8820x_cmmu_set_uapr(unsigned); -void m8820x_cmmu_flush_tlb(unsigned, unsigned, vaddr_t, vsize_t); -void m8820x_cmmu_flush_cache(int, paddr_t, psize_t); -void m8820x_cmmu_flush_inst_cache(int, paddr_t, psize_t); -void m8820x_cmmu_flush_data_cache(int, paddr_t, psize_t); -void m8820x_dma_cachectl(vaddr_t, vsize_t, int); -void m8820x_dma_cachectl_pa(paddr_t, psize_t, int); -void m8820x_cmmu_dump_config(void); -void m8820x_cmmu_show_translation(unsigned, unsigned, unsigned, int); -void m8820x_show_apr(unsigned); - -/* This is the function table for the mc8820x CMMUs */ -struct cmmu_p cmmu8820x = { - m8820x_cmmu_init, - m8820x_setup_board_config, - m8820x_cpu_configuration_print, - m8820x_cmmu_shutdown_now, - m8820x_cmmu_parity_enable, - m8820x_cmmu_cpu_number, - m8820x_cmmu_set_sapr, - m8820x_cmmu_set_uapr, - m8820x_cmmu_flush_tlb, - m8820x_cmmu_flush_cache, - m8820x_cmmu_flush_inst_cache, - m8820x_cmmu_flush_data_cache, - m8820x_dma_cachectl, - m8820x_dma_cachectl_pa, -#ifdef DDB - m8820x_cmmu_dump_config, - m8820x_cmmu_show_translation, -#else - NULL, - NULL, -#endif -#ifdef DEBUG - m8820x_show_apr, -#else - NULL, -#endif -}; - -/* - * CMMU kernel information - */ -struct m8820x_cmmu { - unsigned *volatile cmmu_regs; /* CMMU "base" area */ - unsigned int cmmu_cpu; /* cpu number it is attached to */ - unsigned int cmmu_type; -#define INST_CMMU 0 -#define DATA_CMMU 1 - unsigned int cmmu_access; -#define CMMU_ACS_USER 0 -#define CMMU_ACS_SUPER 1 -#define CMMU_ACS_BOTH 2 - unsigned int cmmu_alive; -#define CMMU_DEAD 0 /* This cmmu is not there */ -#define CMMU_AVAILABLE 1 /* It's there, but which cpu's? */ -#define CMMU_MARRIED 2 /* Know which cpu it belongs to. */ - vaddr_t cmmu_addr; /* address range */ - vaddr_t cmmu_addr_mask; /* address mask */ - int cmmu_addr_match;/* return value of address comparison */ -}; - -/* - * Structure for accessing MMUS properly - */ - -#define MAX_CMMUS (2 * MAX_CPUS) /* maximum cmmus on the board */ - -struct m8820x_cmmu m8820x_cmmu[MAX_CMMUS] = -{ - /* address, cpu, mode, access, alive, addr, mask */ - {(unsigned *volatile)CMMU_I0, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_D0, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_I1, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_D1, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_I2, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_D2, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_I3, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}, - {(unsigned *volatile)CMMU_D3, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0} -}; - -struct cpu_cmmu { - struct m8820x_cmmu *pair[2]; -} cpu_cmmu[MAX_CPUS]; - -/* - * CMMU per CPU split strategies - */ - -#define CMMU_SPLIT_ADDRESS 0x00 -#define CMMU_SPLIT_SPV 0x01 -#define CMMU_SPLIT_SRAM_SPV 0x02 -#define CMMU_SPLIT_SRAM_ALL 0x03 - -#define CMMU_SPLIT_MASK 0x03 - -struct cmmu_strategy { - int inst; - int data; -} cpu_cmmu_strategy[] = { - /* inst data */ - { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS}, /* CPU 0 */ - { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS}, /* CPU 1 */ - { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS}, /* CPU 2 */ - { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS} /* CPU 3 */ -}; - -unsigned int cmmu_shift; - -/* local prototypes */ -void m8820x_cmmu_set(int, unsigned, int, int, int, int, vaddr_t); -void m8820x_cmmu_wait(int); -void m8820x_cmmu_sync_cache(paddr_t, psize_t); -void m8820x_cmmu_sync_inval_cache(paddr_t, psize_t); -void m8820x_cmmu_inval_cache(paddr_t, psize_t); - -/* Flags passed to m8820x_cmmu_set() */ -#define MODE_VAL 0x01 -#define ACCESS_VAL 0x02 -#define ADDR_VAL 0x04 - -#ifdef DEBUG -void -m8820x_show_apr(value) - unsigned value; -{ - printf("table @ 0x%x000", PG_PFNUM(value)); - if (value & CACHE_WT) - printf(", writethrough"); - if (value & CACHE_GLOBAL) - printf(", global"); - if (value & CACHE_INH) - printf(", cache inhibit"); - if (value & APR_V) - printf(", valid"); - printf("\n"); -} -#endif +#include <machine/board.h> /* * This routine sets up the CPU/CMMU configuration. @@ -273,418 +98,66 @@ m8820x_show_apr(value) void m8820x_setup_board_config() { - int num, cmmu_num; - unsigned *volatile cr; + struct m8820x_cmmu *cmmu; + int num; master_cpu = 0; /* temp to get things going */ - max_cpus = 4; - max_cmmus = 8; - cmmu_shift = ff1(max_cmmus / max_cpus); + m8820x_cmmu[0].cmmu_regs = (void *)CMMU_I0; + m8820x_cmmu[1].cmmu_regs = (void *)CMMU_D0; + m8820x_cmmu[2].cmmu_regs = (void *)CMMU_I1; + m8820x_cmmu[3].cmmu_regs = (void *)CMMU_D1; + m8820x_cmmu[4].cmmu_regs = (void *)CMMU_I2; + m8820x_cmmu[5].cmmu_regs = (void *)CMMU_D2; + m8820x_cmmu[6].cmmu_regs = (void *)CMMU_I3; + m8820x_cmmu[7].cmmu_regs = (void *)CMMU_D3; + + /* + * Probe all CMMU address to discover if the CPU slots are populated. + */ + cmmu = m8820x_cmmu; + for (max_cmmus = 0; max_cmmus < 8; max_cmmus++, cmmu++) { + if (badwordaddr((vaddr_t)cmmu->cmmu_regs) != 0) + break; + } + + max_cpus = max_cmmus >> 1; + max_cmmus = max_cpus << 1; + cmmu_shift = 1; /* fixed 2:1 configuration */ +#ifdef DEBUG /* - * Probe for available MMUs + * Check CMMU type */ - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; + for (num = 0; num < max_cmmus; num++) { + volatile unsigned *cr = m8820x_cmmu[num].cmmu_regs; if (badwordaddr((vaddr_t)cr) == 0) { int type; type = CMMU_TYPE(cr[CMMU_IDR]); -#ifdef DIAGNOSTIC if (type != M88200_ID && type != M88204_ID) { printf("WARNING: non M8820x circuit found " "at CMMU address %p\n", cr); continue; /* will probably die quickly */ } -#endif - m8820x_cmmu[cmmu_num].cmmu_alive = CMMU_AVAILABLE; - dprintf(("m8820x_setup_cmmu_config: CMMU %d found at %p\n", - cmmu_num, cr)); } } +#endif /* - * Now that we know which CMMUs are there, let's report on which - * CPU/CMMU sets seem complete (hopefully all) + * Now that we know which CMMUs are there, report every association */ for (num = 0; num < max_cpus; num++) { - int i, type; + int type; - for (i = 0; i < (1 << cmmu_shift); i++) { - dprintf(("cmmu_init: testing CMMU %d for CPU %d\n", - (num << cmmu_shift) | i, num)); -#ifdef DIAGNOSTIC - if (m8820x_cmmu[(num << cmmu_shift) | i].cmmu_alive == CMMU_DEAD) { - printf("CMMU %d attached to CPU %d is not working\n", - (num << cmmu_shift) | i, num); - continue; /* will probably die quickly */ - } -#endif - } cpu_sets[num] = 1; /* This cpu installed... */ type = CMMU_TYPE(m8820x_cmmu[num << cmmu_shift]. cmmu_regs[CMMU_IDR]); - printf("CPU%d is attached with %d MC%x CMMUs\n", - num, 1 << cmmu_shift, type == M88204_ID ? 0x88204 : 0x88200); - } - - /* - * Calculate the CMMU<->CPU connections - */ - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - m8820x_cmmu[cmmu_num].cmmu_cpu = - (cmmu_num * max_cpus) / max_cmmus; - dprintf(("m8820x_setup_cmmu_config: CMMU %d connected with CPU %d\n", - cmmu_num, m8820x_cmmu[cmmu_num].cmmu_cpu)); - } - - /* - * Now set m8820x_cmmu[].cmmu_access and addr - */ - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - /* - * We don't set up anything for the hardwired configurations. - */ - m8820x_cmmu[cmmu_num].cmmu_addr = 0; - m8820x_cmmu[cmmu_num].cmmu_addr_mask = 0; - m8820x_cmmu[cmmu_num].cmmu_addr_match = 1; - m8820x_cmmu[cmmu_num].cmmu_access = CMMU_ACS_BOTH; - } -} - -#ifdef DDB - -const char *cmmu_strat_string[] = { - "address split ", - "user/spv split", - "spv SRAM split", - "all SRAM split" -}; - -void -m8820x_cmmu_dump_config() -{ - int cmmu_num; - - db_printf("Current CPU/CMMU configuration:\n"); - - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - db_printf("CMMU #%d: %s CMMU for CPU %d:\n Strategy: %s\n %s access addr 0x%08lx mask 0x%08lx match %s\n", - cmmu_num, - (m8820x_cmmu[cmmu_num].cmmu_type == INST_CMMU) ? "inst" : "data", - m8820x_cmmu[cmmu_num].cmmu_cpu, - cmmu_strat_string[(m8820x_cmmu[cmmu_num].cmmu_type == INST_CMMU) ? - cpu_cmmu_strategy[m8820x_cmmu[cmmu_num].cmmu_cpu].inst : - cpu_cmmu_strategy[m8820x_cmmu[cmmu_num].cmmu_cpu].data], - (m8820x_cmmu[cmmu_num].cmmu_access == CMMU_ACS_BOTH) ? "User and spv" : - ((m8820x_cmmu[cmmu_num].cmmu_access == CMMU_ACS_USER) ? "User " : - "Supervisor "), - m8820x_cmmu[cmmu_num].cmmu_addr, - m8820x_cmmu[cmmu_num].cmmu_addr_mask, - m8820x_cmmu[cmmu_num].cmmu_addr_match ? "TRUE" : "FALSE"); + printf("CPU%d is associated to %d MC8820%c CMMUs\n", + num, 1 << cmmu_shift, type == M88204_ID ? '4' : '0'); } } -#endif /* DDB */ - -/* - * This function is called by the MMU module and pokes values - * into the CMMU's registers. - */ -void -m8820x_cmmu_set(reg, val, flags, num, mode, access, addr) - int reg; - unsigned val; - int flags, num, mode, access; - vaddr_t addr; -{ - int mmu; - - /* - * We scan all CMMUs to find the matching ones and store the - * values there. - */ - for (mmu = num << cmmu_shift; - mmu < (num + 1) << cmmu_shift; mmu++) { - if (((flags & MODE_VAL)) && - (m8820x_cmmu[mmu].cmmu_type != mode)) - continue; - if (((flags & ACCESS_VAL)) && - (m8820x_cmmu[mmu].cmmu_access != access) && - (m8820x_cmmu[mmu].cmmu_access != CMMU_ACS_BOTH)) - continue; - if (flags & ADDR_VAL) { - if (((addr & m8820x_cmmu[mmu].cmmu_addr_mask) == m8820x_cmmu[mmu].cmmu_addr) - != m8820x_cmmu[mmu].cmmu_addr_match) { - continue; - } - } - m8820x_cmmu[mmu].cmmu_regs[reg] = val; - } -} - -/* - * Force a read from the CMMU status register, thereby forcing execution to - * stop until all pending CMMU operations are finished. - * This is used by the various cache invalidation functions. - */ -void -m8820x_cmmu_wait(int cpu) -{ - int mmu; - - /* - * We scan all related CMMUs and read their status register. - */ - for (mmu = cpu << cmmu_shift; - mmu < (cpu + 1) << cmmu_shift; mmu++) { -#ifdef DEBUG - if (m8820x_cmmu[mmu].cmmu_regs[CMMU_SSR] & CMMU_SSR_BE) { - panic("cache flush failed!"); - } -#else - /* force the read access, but do not issue this statement... */ - __asm__ __volatile__ ("|or r0, r0, %0" :: - "r" (m8820x_cmmu[mmu].cmmu_regs[CMMU_SSR])); -#endif - } -} - -const char *mmutypes[8] = { - "Unknown (0)", - "Unknown (1)", - "Unknown (2)", - "Unknown (3)", - "Unknown (4)", - "M88200 (16K)", - "M88204 (64K)", - "Unknown (7)" -}; - -/* - * Should only be called after the calling cpus knows its cpu - * number and master/slave status . Should be called first - * by the master, before the slaves are started. -*/ -void -m8820x_cpu_configuration_print(master) - int master; -{ - int pid = read_processor_identification_register(); - int proctype = (pid & 0xff00) >> 8; - int procvers = (pid & 0xe) >> 1; - int mmu, cpu = cpu_number(); - struct simplelock print_lock; - - if (master) - simple_lock_init(&print_lock); - - simple_lock(&print_lock); - - printf("cpu%d: ", cpu); - if (proctype != 0) { - printf("unknown model arch 0x%x rev 0x%x\n", - proctype, procvers); - simple_unlock(&print_lock); - return; - } - - printf("M88100 rev 0x%x", procvers); -#if 0 /* not useful yet */ -#ifdef MVME188 - if (brdtyp == BRD_188) - printf(", %s", master ? "master" : "slave"); -#endif -#endif - printf(", %d CMMU", 1 << cmmu_shift); - - for (mmu = cpu << cmmu_shift; mmu < (cpu + 1) << cmmu_shift; - mmu++) { - int idr = m8820x_cmmu[mmu].cmmu_regs[CMMU_IDR]; - int mmuid = CMMU_TYPE(idr); - int access = m8820x_cmmu[mmu].cmmu_access; - - if (mmu % 2 == 0) - printf("\ncpu%d: ", cpu); - else - printf(", "); - - if (mmutypes[mmuid][0] == 'U') - printf("unknown model id 0x%x", mmuid); - else - printf("%s", mmutypes[mmuid]); - printf(" rev 0x%x, %s %scache", - CMMU_VERSION(idr), - access == CMMU_ACS_BOTH ? "global" : - (access == CMMU_ACS_USER ? "user" : "sup"), - m8820x_cmmu[mmu].cmmu_type == INST_CMMU ? "I" : "D"); - } - printf("\n"); - -#ifndef ERRATA__XXX_USR - { - static int errata_warn = 0; - - if (proctype != 0 && procvers < 2) { - if (!errata_warn++) - printf("WARNING: M88100 bug workaround code " - "not enabled.\nPlease recompile the kernel " - "with option ERRATA__XXX_USR !\n"); - } - } -#endif - - simple_unlock(&print_lock); -} - -/* - * CMMU initialization routine - */ -void -m8820x_cmmu_init() -{ - unsigned int line, cmmu_num; - int cssp, cpu, type; - u_int32_t apr; - unsigned *volatile cr; - - for (cpu = 0; cpu < max_cpus; cpu++) { - cpu_cmmu[cpu].pair[INST_CMMU] = 0; - cpu_cmmu[cpu].pair[DATA_CMMU] = 0; - } - - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - if (m8820x_cmmu[cmmu_num].cmmu_alive != CMMU_DEAD) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; - type = CMMU_TYPE(cr[CMMU_IDR]); - - cpu_cmmu[m8820x_cmmu[cmmu_num].cmmu_cpu]. - pair[m8820x_cmmu[cmmu_num].cmmu_type] = - &m8820x_cmmu[cmmu_num]; - - /* - * Reset cache - */ - for (cssp = type == M88204_ID ? 3 : 0; - cssp >= 0; cssp--) - for (line = 0; line <= 255; line++) { - cr[CMMU_SAR] = - line << MC88200_CACHE_SHIFT; - cr[CMMU_CSSP(cssp)] = - CMMU_CSSP_L5 | CMMU_CSSP_L4 | - CMMU_CSSP_L3 | CMMU_CSSP_L2 | - CMMU_CSSP_L1 | CMMU_CSSP_L0 | - CMMU_CSSP_VV(3, CMMU_VV_INVALID) | - CMMU_CSSP_VV(2, CMMU_VV_INVALID) | - CMMU_CSSP_VV(1, CMMU_VV_INVALID) | - CMMU_CSSP_VV(0, CMMU_VV_INVALID); - } - - /* - * Set the SCTR, SAPR, and UAPR to some known state - */ - cr[CMMU_SCTR] &= - ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR); - cr[CMMU_SAPR] = cr[CMMU_UAPR] = - ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL | - CACHE_INH) & ~APR_V; - - cr[CMMU_BWP0] = cr[CMMU_BWP1] = - cr[CMMU_BWP2] = cr[CMMU_BWP3] = - cr[CMMU_BWP4] = cr[CMMU_BWP5] = - cr[CMMU_BWP6] = cr[CMMU_BWP7] = 0; - cr[CMMU_SCR] = CMMU_FLUSH_CACHE_INV_ALL; - __asm__ __volatile__ ("|or r0, r0, %0" :: - "r" (cr[CMMU_SSR])); - cr[CMMU_SCR] = CMMU_FLUSH_SUPER_ALL; - cr[CMMU_SCR] = CMMU_FLUSH_USER_ALL; - } - } - - /* - * Enable snooping on MVME188 only. - * Snooping is enabled for instruction cmmus as well so that - * we can share breakpoints. - */ - - for (cpu = 0; cpu < max_cpus; cpu++) { - if (cpu_sets[cpu] == 0) - continue; - - m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu, - DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu, - INST_CMMU, 0, 0); - - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL, - ACCESS_VAL, cpu, 0, CMMU_ACS_SUPER, 0); - m8820x_cmmu_wait(cpu); - /* Icache gets flushed just below */ - } - - /* - * Enable instruction cache. - * Data cache can not be enabled at this point, because some device - * addresses can never be cached, and the no-caching zones are not - * set up yet. - */ - for (cpu = 0; cpu < max_cpus; cpu++) { - if (cpu_sets[cpu] == 0) - continue; - - apr = ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL) - & ~(CACHE_INH | APR_V); - - m8820x_cmmu_set(CMMU_SAPR, apr, MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL, - ACCESS_VAL, cpu, 0, CMMU_ACS_SUPER, 0); - m8820x_cmmu_wait(cpu); - } -} - -/* - * Just before poweroff or reset.... - */ -void -m8820x_cmmu_shutdown_now() -{ - unsigned cmmu_num; - unsigned *volatile cr; - - CMMU_LOCK; - for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++) - if (m8820x_cmmu[cmmu_num].cmmu_alive != CMMU_DEAD) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; - - cr[CMMU_SCTR] &= - ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR); - cr[CMMU_SAPR] = cr[CMMU_UAPR] = - ((0x00000 << PG_BITS) | CACHE_INH) & - ~(CACHE_WT | CACHE_GLOBAL | APR_V); - } - CMMU_UNLOCK; -} - -/* - * enable parity - */ -void -m8820x_cmmu_parity_enable() -{ - unsigned cmmu_num; - unsigned *volatile cr; - - CMMU_LOCK; - - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) - if (m8820x_cmmu[cmmu_num].cmmu_alive != CMMU_DEAD) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; - cr[CMMU_SCTR] |= CMMU_SCTR_PE; - } - - CMMU_UNLOCK; -} /* * Find out the CPU number from accessing CMMU @@ -696,34 +169,30 @@ m8820x_cmmu_parity_enable() unsigned m8820x_cmmu_cpu_number() { - unsigned cmmu_no; - int i, cpu; + unsigned cmmu; + u_int i; CMMU_LOCK; for (i = 0; i < 10; i++) { - /* clear CMMU p-bus status registers */ - for (cmmu_no = 0; cmmu_no < MAX_CMMUS; cmmu_no++) { - if (m8820x_cmmu[cmmu_no].cmmu_alive == CMMU_AVAILABLE && - m8820x_cmmu[cmmu_no].cmmu_type == DATA_CMMU) - m8820x_cmmu[cmmu_no].cmmu_regs[CMMU_PFSR] = 0; + /* clear CMMU P-bus status registers */ + for (cmmu = 0; cmmu < max_cmmus; cmmu++) { + if (CMMU_MODE(cmmu) != INST_CMMU) + m8820x_cmmu[cmmu].cmmu_regs[CMMU_PFSR] = 0; } /* access faulting address */ badwordaddr((vaddr_t)ILLADDRESS); /* check which CMMU reporting the fault */ - for (cmmu_no = 0; cmmu_no < MAX_CMMUS; cmmu_no++) { - if (m8820x_cmmu[cmmu_no].cmmu_alive == CMMU_AVAILABLE && - m8820x_cmmu[cmmu_no].cmmu_type == DATA_CMMU && - CMMU_PFSR_FAULT(m8820x_cmmu[cmmu_no]. + for (cmmu = 0; cmmu < max_cmmus; cmmu++) { + if (CMMU_MODE(cmmu) != INST_CMMU && + CMMU_PFSR_FAULT(m8820x_cmmu[cmmu]. cmmu_regs[CMMU_PFSR]) != CMMU_PFSR_SUCCESS) { /* clean register, just in case... */ - m8820x_cmmu[cmmu_no].cmmu_regs[CMMU_PFSR] = 0; - m8820x_cmmu[cmmu_no].cmmu_alive = CMMU_MARRIED; - cpu = m8820x_cmmu[cmmu_no].cmmu_cpu; + m8820x_cmmu[cmmu].cmmu_regs[CMMU_PFSR] = 0; CMMU_UNLOCK; - return cpu; + return cmmu >> 1; } } } @@ -731,793 +200,3 @@ m8820x_cmmu_cpu_number() panic("m8820x_cmmu_cpu_number: could not determine my cpu number"); } - -void -m8820x_cmmu_set_sapr(cpu, ap) - unsigned cpu, ap; -{ - CMMU_LOCK; - m8820x_cmmu_set(CMMU_SAPR, ap, ACCESS_VAL, cpu, 0, CMMU_ACS_SUPER, 0); - CMMU_UNLOCK; -} - -void -m8820x_cmmu_set_uapr(ap) - unsigned ap; -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - m8820x_cmmu_set(CMMU_UAPR, ap, ACCESS_VAL, cpu, 0, CMMU_ACS_USER, 0); - CMMU_UNLOCK; - splx(s); -} - -/* - * Functions that invalidate TLB entries. - */ - -/* - * flush any tlb - */ -void -m8820x_cmmu_flush_tlb(unsigned cpu, unsigned kernel, vaddr_t vaddr, - vsize_t size) -{ - int s = splhigh(); - - CMMU_LOCK; - - /* - * Since segment operations are horribly expensive, don't - * do any here. Invalidations of up to three pages are performed - * as page invalidations, otherwise the entire tlb is flushed. - * - * Note that this code relies upon size being a multiple of - * a page and vaddr being page-aligned. - */ - if (size == PAGE_SIZE) { /* most frequent situation */ - m8820x_cmmu_set(CMMU_SAR, vaddr, - ADDR_VAL | ACCESS_VAL, cpu, 0, - kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr); - m8820x_cmmu_set(CMMU_SCR, - kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE, - ADDR_VAL | ACCESS_VAL, cpu, 0, - kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr); - } else if (size > 3 * PAGE_SIZE) { - m8820x_cmmu_set(CMMU_SCR, - kernel ? CMMU_FLUSH_SUPER_ALL : CMMU_FLUSH_USER_ALL, - ACCESS_VAL, cpu, 0, - kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, 0); - } else - while (size != 0) { - m8820x_cmmu_set(CMMU_SAR, vaddr, - ADDR_VAL | ACCESS_VAL, cpu, 0, - kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr); - m8820x_cmmu_set(CMMU_SCR, - kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE, - ADDR_VAL | ACCESS_VAL, cpu, 0, - kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr); - - size -= PAGE_SIZE; - vaddr += PAGE_SIZE; - } - - CMMU_UNLOCK; - splx(s); -} - -/* - * Functions that invalidate caches. - * - * Cache invalidates require physical addresses. Care must be exercised when - * using segment invalidates. This implies that the starting physical address - * plus the segment length should be invalidated. A typical mistake is to - * extract the first physical page of a segment from a virtual address, and - * then expecting to invalidate when the pages are not physically contiguous. - * - * We don't push Instruction Caches prior to invalidate because they are not - * snooped and never modified (I guess it doesn't matter then which form - * of the command we use then). - */ - -/* - * flush both Instruction and Data caches - */ -void -m8820x_cmmu_flush_cache(int cpu, paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0, - cpu, 0, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL, - cpu, 0, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, ADDR_VAL, - cpu, 0, 0, (unsigned)physaddr); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL, - cpu, 0, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, ADDR_VAL, - cpu, 0, 0, (unsigned)physaddr); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, 0, - cpu, 0, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, 0, - cpu, 0, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0, - cpu, 0, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -/* - * flush Instruction caches - */ -void -m8820x_cmmu_flush_inst_cache(int cpu, paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_cmmu_flush_data_cache(int cpu, paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -/* - * sync dcache (and icache too) - */ -void -m8820x_cmmu_sync_cache(paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_LINE, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_LINE, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_PAGE, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_PAGE, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_cmmu_sync_inval_cache(paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_cmmu_inval_cache(paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_LINE, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_LINE, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_PAGE, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_PAGE, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, DATA_CMMU, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, INST_CMMU, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_dma_cachectl(vaddr_t va, vsize_t size, int op) -{ - paddr_t pa; -#if !defined(BROKEN_MMU_MASK) - psize_t count; - - while (size != 0) { - count = NBPG - (va & PGOFSET); - - if (size < count) - count = size; - - if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) { - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, count); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, count); - break; - default: - m8820x_cmmu_inval_cache(pa, count); - break; - } - } - - va += count; - size -= count; - } -#else - /* XXX This assumes the space is also physically contiguous */ - if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) { - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, size); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, size); - break; - default: - m8820x_cmmu_inval_cache(pa, size); - break; - } - } -#endif /* !BROKEN_MMU_MASK */ -} - -void -m8820x_dma_cachectl_pa(paddr_t pa, psize_t size, int op) -{ -#if !defined(BROKEN_MMU_MASK) - psize_t count; - - while (size != 0) { - count = NBPG - (va & PGOFSET); - - if (size < count) - count = size; - - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, count); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, count); - break; - default: - m8820x_cmmu_inval_cache(pa, count); - break; - } - - pa += count; - size -= count; - } -#else - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, size); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, size); - break; - default: - m8820x_cmmu_inval_cache(pa, size); - break; - } -#endif /* !BROKEN_MMU_MASK */ -} - -#ifdef DDB -union ssr { - unsigned bits; - struct { - unsigned :16, - ce:1, - be:1, - :4, - wt:1, - sp:1, - g:1, - ci:1, - :1, - m:1, - u:1, - wp:1, - bh:1, - v:1; - } field; -}; - -union cssp { - unsigned bits; - struct { - unsigned : 2, - l: 6, - d3: 1, - d2: 1, - d1: 1, - d0: 1, - vv3: 2, - vv2: 2, - vv1: 2, - vv0: 2, - :12; - } field; -}; - -union batcu { - unsigned bits; - struct { /* block address translation register */ - unsigned int - lba:13, /* logical block address */ - pba:13, /* physical block address */ - s:1, /* supervisor */ - wt:4, /* write through */ - g:1, /* global */ - ci:1, /* cache inhibit */ - wp:1, /* write protect */ - v:1; /* valid */ - } field; -}; - - #define VV_EX_UNMOD 0 - #define VV_EX_MOD 1 - #define VV_SHARED_UNMOD 2 - #define VV_INVALID 3 - - #define D(UNION, LINE) \ - ((LINE) == 3 ? (UNION).field.d3 : \ - ((LINE) == 2 ? (UNION).field.d2 : \ - ((LINE) == 1 ? (UNION).field.d1 : \ - ((LINE) == 0 ? (UNION).field.d0 : ~0)))) - #define VV(UNION, LINE) \ - ((LINE) == 3 ? (UNION).field.vv3 : \ - ((LINE) == 2 ? (UNION).field.vv2 : \ - ((LINE) == 1 ? (UNION).field.vv1 : \ - ((LINE) == 0 ? (UNION).field.vv0 : ~0)))) - - #undef VEQR_ADDR - #define VEQR_ADDR 0 -/* - * Show (for debugging) how the given CMMU translates the given ADDRESS. - * If cmmu == -1, the data cmmu for the current cpu is used. - */ -void -m8820x_cmmu_show_translation(address, supervisor_flag, verbose_flag, cmmu_num) - unsigned address, supervisor_flag, verbose_flag; - int cmmu_num; -{ - /* - * A virtual address is split into three fields. Two are used as - * indicies into tables (segment and page), and one is an offset into - * a page of memory. - */ - union { - unsigned bits; - struct { - unsigned segment_table_index:SDT_BITS, - page_table_index:PDT_BITS, - page_offset:PG_BITS; - } field; - } virtual_address; - u_int32_t value; - - if (verbose_flag) - db_printf("-------------------------------------------\n"); - - - - /****** ACCESS PROPER CMMU or THREAD ***********/ - if (cmmu_num == -1) { - int cpu = cpu_number(); - if (cpu_cmmu[cpu].pair[DATA_CMMU] == 0) { - db_printf("ack! can't figure my own data cmmu number.\n"); - return; - } - cmmu_num = cpu_cmmu[cpu].pair[DATA_CMMU] - m8820x_cmmu; - if (verbose_flag) - db_printf("The data cmmu for cpu#%d is cmmu#%d.\n", - 0, cmmu_num); - } else if (cmmu_num < 0 || cmmu_num >= MAX_CMMUS) { - db_printf("invalid cpu number [%d]... must be in range [0..%d]\n", - cmmu_num, MAX_CMMUS - 1); - - return; - } - - if (m8820x_cmmu[cmmu_num].cmmu_alive == CMMU_DEAD) { - db_printf("warning: cmmu %d is not alive.\n", cmmu_num); -#if 0 - return; -#endif - } - - if (!verbose_flag) { - if (!(m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE)) - db_printf("WARNING: snooping not enabled for CMMU#%d.\n", - cmmu_num); - } else { - int i; - for (i = 0; i < MAX_CMMUS; i++) - if ((i == cmmu_num || m8820x_cmmu[i].cmmu_alive != CMMU_DEAD) && - (verbose_flag > 1 || !(m8820x_cmmu[i].cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE))) { - db_printf("CMMU#%d (cpu %d %s) snooping %s\n", i, - m8820x_cmmu[i].cmmu_cpu, m8820x_cmmu[i].cmmu_type ? "data" : "inst", - (m8820x_cmmu[i].cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE) ? "on":"OFF"); - } - } - - if (supervisor_flag) - value = m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_SAPR]; - else - value = m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_UAPR]; - - /******* SEE WHAT A PROBE SAYS (if not a thread) ***********/ - { - union ssr ssr; - unsigned *volatile cmmu_regs = m8820x_cmmu[cmmu_num].cmmu_regs; - cmmu_regs[CMMU_SAR] = address; - cmmu_regs[CMMU_SCR] = supervisor_flag ? CMMU_PROBE_SUPER : CMMU_PROBE_USER; - ssr.bits = cmmu_regs[CMMU_SSR]; - if (verbose_flag > 1) - db_printf("probe of 0x%08x returns ssr=0x%08x\n", - address, ssr.bits); - if (ssr.field.v) - db_printf("PROBE of 0x%08x returns phys=0x%x", - address, cmmu_regs[CMMU_SAR]); - else - db_printf("PROBE fault at 0x%x", cmmu_regs[CMMU_PFAR]); - if (ssr.field.ce) db_printf(", copyback err"); - if (ssr.field.be) db_printf(", bus err"); - if (ssr.field.wt) db_printf(", writethrough"); - if (ssr.field.sp) db_printf(", sup prot"); - if (ssr.field.g) db_printf(", global"); - if (ssr.field.ci) db_printf(", cache inhibit"); - if (ssr.field.m) db_printf(", modified"); - if (ssr.field.u) db_printf(", used"); - if (ssr.field.wp) db_printf(", write prot"); - if (ssr.field.bh) db_printf(", BATC"); - db_printf(".\n"); - } - - /******* INTERPRET AREA DESCRIPTOR *********/ - { - if (verbose_flag > 1) { - db_printf("CMMU#%d", cmmu_num); - db_printf(" %cAPR is 0x%08x\n", - supervisor_flag ? 'S' : 'U', value); - } - db_printf("CMMU#%d", cmmu_num); - db_printf(" %cAPR: SegTbl: 0x%x000p", - supervisor_flag ? 'S' : 'U', PG_PFNUM(value)); - if (value & CACHE_WT) - db_printf(", WTHRU"); - if (value & CACHE_GLOBAL) - db_printf(", GLOBAL"); - if (value & CACHE_INH) - db_printf(", INHIBIT"); - if (value & APR_V) - db_printf(", VALID"); - db_printf("\n"); - - /* if not valid, done now */ - if ((value & APR_V) == 0) { - db_printf("<would report an error, valid bit not set>\n"); - - return; - } - - value &= PG_FRAME; /* now point to seg page */ - } - - /* translate value from physical to virtual */ - if (verbose_flag) - db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR); - value += VEQR_ADDR; - - virtual_address.bits = address; - - /****** ACCESS SEGMENT TABLE AND INTERPRET SEGMENT DESCRIPTOR *******/ - { - sdt_entry_t sdt; - if (verbose_flag) - db_printf("will follow to entry %d of page at 0x%x...\n", - virtual_address.field.segment_table_index, value); - value |= virtual_address.field.segment_table_index * - sizeof(sdt_entry_t); - - if (badwordaddr((vaddr_t)value)) { - db_printf("ERROR: unable to access page at 0x%08x.\n", value); - return; - } - - sdt = *(sdt_entry_t *)value; - if (verbose_flag > 1) - db_printf("SEG DESC @0x%x is 0x%08x\n", value, sdt); - db_printf("SEG DESC @0x%x: PgTbl: 0x%x000", - value, PG_PFNUM(sdt)); - if (sdt & CACHE_WT) db_printf(", WTHRU"); - else db_printf(", !wthru"); - if (sdt & SG_SO) db_printf(", S-PROT"); - else db_printf(", UserOk"); - if (sdt & CACHE_GLOBAL) db_printf(", GLOBAL"); - else db_printf(", !global"); - if (sdt & CACHE_INH) db_printf(", $INHIBIT"); - else db_printf(", $ok"); - if (sdt & SG_PROT) db_printf(", W-PROT"); - else db_printf(", WriteOk"); - if (sdt & SG_V) db_printf(", VALID"); - else db_printf(", !valid"); - db_printf(".\n"); - - /* if not valid, done now */ - if (!(sdt & SG_V)) { - db_printf("<would report an error, STD entry not valid>\n"); - return; - } - - value = ptoa(PG_PFNUM(sdt)); - } - - /* translate value from physical to virtual */ - if (verbose_flag) - db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR); - value += VEQR_ADDR; - - /******* PAGE TABLE *********/ - { - pt_entry_t pte; - if (verbose_flag) - db_printf("will follow to entry %d of page at 0x%x...\n", - virtual_address.field.page_table_index, value); - value |= virtual_address.field.page_table_index * - sizeof(pt_entry_t); - - if (badwordaddr((vaddr_t)value)) { - db_printf("error: unable to access page at 0x%08x.\n", value); - - return; - } - - pte = *(pt_entry_t *)value; - if (verbose_flag > 1) - db_printf("PAGE DESC @0x%x is 0x%08x.\n", value, pte); - db_printf("PAGE DESC @0x%x: page @%x000", - value, PG_PFNUM(pte)); - if (pte & PG_W) db_printf(", WIRE"); - else db_printf(", !wire"); - if (pte & CACHE_WT) db_printf(", WTHRU"); - else db_printf(", !wthru"); - if (pte & PG_SO) db_printf(", S-PROT"); - else db_printf(", UserOk"); - if (pte & CACHE_GLOBAL) db_printf(", GLOBAL"); - else db_printf(", !global"); - if (pte & CACHE_INH) db_printf(", $INHIBIT"); - else db_printf(", $ok"); - if (pte & PG_M) db_printf(", MOD"); - else db_printf(", !mod"); - if (pte & PG_U) db_printf(", USED"); - else db_printf(", !used"); - if (pte & PG_PROT) db_printf(", W-PROT"); - else db_printf(", WriteOk"); - if (pte & PG_V) db_printf(", VALID"); - else db_printf(", !valid"); - db_printf(".\n"); - - /* if not valid, done now */ - if (!(pte & PG_V)) { - db_printf("<would report an error, PTE entry not valid>\n"); - return; - } - - value = ptoa(PG_PFNUM(pte)); - if (verbose_flag) - db_printf("will follow to byte %d of page at 0x%x...\n", - virtual_address.field.page_offset, value); - value |= virtual_address.field.page_offset; - - if (badwordaddr((vaddr_t)value)) { - db_printf("error: unable to access page at 0x%08x.\n", value); - return; - } - } - - /* translate value from physical to virtual */ - if (verbose_flag) - db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR); - value += VEQR_ADDR; - - db_printf("WORD at 0x%x is 0x%08x.\n", value, *(unsigned *)value); - -} -#endif /* DDB */ diff --git a/sys/arch/m88k/conf/files.m88k b/sys/arch/m88k/conf/files.m88k index a849b4541e8..11232f62b0d 100644 --- a/sys/arch/m88k/conf/files.m88k +++ b/sys/arch/m88k/conf/files.m88k @@ -1,4 +1,4 @@ -# $OpenBSD: files.m88k,v 1.6 2004/08/01 17:18:05 miod Exp $ +# $OpenBSD: files.m88k,v 1.7 2004/08/06 13:23:49 miod Exp $ file arch/m88k/m88k/cmmu.c file arch/m88k/m88k/db_disasm.c ddb @@ -8,6 +8,7 @@ file arch/m88k/m88k/m88100_fp.S m88100 file arch/m88k/m88k/m88100_machdep.c m88100 file arch/m88k/m88k/m88110_fp.S m88110 file arch/m88k/m88k/m88110_mmu.S m88110 +file arch/m88k/m88k/m8820x_machdep.c m88100 file arch/m88k/m88k/pmap.c file arch/m88k/m88k/process.S file arch/m88k/m88k/process_machdep.c diff --git a/sys/arch/m88k/include/cmmu.h b/sys/arch/m88k/include/cmmu.h index 8bbaf4b840b..630af8664e7 100644 --- a/sys/arch/m88k/include/cmmu.h +++ b/sys/arch/m88k/include/cmmu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cmmu.h,v 1.4 2004/08/04 15:54:37 miod Exp $ */ +/* $OpenBSD: cmmu.h,v 1.5 2004/08/06 13:23:49 miod Exp $ */ /* * Mach Operating System * Copyright (c) 1993-1992 Carnegie Mellon University @@ -36,7 +36,7 @@ */ extern unsigned cpu_sets[MAX_CPUS]; extern unsigned master_cpu; -extern int max_cpus, max_cmmus; +extern int max_cpus; /* * This lock protects the cmmu SAR and SCR's; other ports diff --git a/sys/arch/m88k/include/m8820x.h b/sys/arch/m88k/include/m8820x.h index 98ab49f2adc..f37cd64767c 100644 --- a/sys/arch/m88k/include/m8820x.h +++ b/sys/arch/m88k/include/m8820x.h @@ -1,4 +1,4 @@ -/* $OpenBSD: m8820x.h,v 1.2 2004/08/04 09:08:19 miod Exp $ */ +/* $OpenBSD: m8820x.h,v 1.3 2004/08/06 13:23:49 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * @@ -171,4 +171,30 @@ #define NBSG (1 << (PDT_BITS + PG_BITS)) /* segment size */ +#ifndef _LOCORE + +/* + * CMMU kernel information + */ +struct m8820x_cmmu { + volatile u_int32_t *cmmu_regs; /* CMMU "base" area */ +#ifdef M88200_HAS_SPLIT_ADDRESS + vaddr_t cmmu_addr; /* address range */ + vaddr_t cmmu_addr_mask; /* address mask */ +#endif +}; + +#define INST_CMMU 0x00 /* even number */ +#define DATA_CMMU 0x01 /* odd number */ +#define CMMU_MODE(num) ((num) & 1) + +#define MAX_CMMUS 8 /* maximum cmmus on the board */ +extern struct m8820x_cmmu m8820x_cmmu[MAX_CMMUS]; +extern u_int cmmu_shift; +extern u_int max_cmmus; + +extern void m8820x_setup_board_config(void); +extern unsigned m8820x_cmmu_cpu_number(void); + +#endif /* _LOCORE */ #endif /* __M88K_M8820X_H__ */ diff --git a/sys/arch/m88k/m88k/cmmu.c b/sys/arch/m88k/m88k/cmmu.c index b82898ca979..30f2d82dde3 100644 --- a/sys/arch/m88k/m88k/cmmu.c +++ b/sys/arch/m88k/m88k/cmmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmmu.c,v 1.1 2004/04/29 14:33:27 miod Exp $ */ +/* $OpenBSD: cmmu.c,v 1.2 2004/08/06 13:23:49 miod Exp $ */ /* * Copyright (c) 1998 Steve Murphree, Jr. * Copyright (c) 1996 Nivas Madhur @@ -73,6 +73,6 @@ struct simplelock cmmu_cpu_lock; unsigned cpu_sets[MAX_CPUS]; unsigned master_cpu = 0; -int max_cpus, max_cmmus; +int max_cpus; struct cmmu_p *cmmu; diff --git a/sys/arch/m88k/m88k/m8820x_machdep.c b/sys/arch/m88k/m88k/m8820x_machdep.c new file mode 100644 index 00000000000..30bee9aad77 --- /dev/null +++ b/sys/arch/m88k/m88k/m8820x_machdep.c @@ -0,0 +1,1223 @@ +/* $OpenBSD: m8820x_machdep.c,v 1.1 2004/08/06 13:23:49 miod Exp $ */ +/* + * Copyright (c) 2004, Miodrag Vallat. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2001 Steve Murphree, Jr. + * Copyright (c) 1996 Nivas Madhur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Nivas Madhur. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/simplelock.h> + +#include <machine/asm_macro.h> +#include <machine/cpu_number.h> +#include <machine/locore.h> + +#include <machine/cmmu.h> +#include <machine/m8820x.h> + +#include <uvm/uvm_extern.h> + +#ifdef DDB +#include <ddb/db_output.h> /* db_printf() */ +#endif + +/* + * On some versions of the 88200, page size flushes don't work. I am using + * sledge hammer approach till I find for sure which ones are bad XXX nivas + */ +#define BROKEN_MMU_MASK + +void m8820x_cmmu_init(void); +void m8820x_cpu_configuration_print(int); +void m8820x_cmmu_shutdown_now(void); +void m8820x_cmmu_parity_enable(void); +void m8820x_cmmu_set_sapr(unsigned, unsigned); +void m8820x_cmmu_set_uapr(unsigned); +void m8820x_cmmu_flush_tlb(unsigned, unsigned, vaddr_t, vsize_t); +void m8820x_cmmu_flush_cache(int, paddr_t, psize_t); +void m8820x_cmmu_flush_inst_cache(int, paddr_t, psize_t); +void m8820x_cmmu_flush_data_cache(int, paddr_t, psize_t); +void m8820x_dma_cachectl(vaddr_t, vsize_t, int); +void m8820x_dma_cachectl_pa(paddr_t, psize_t, int); +void m8820x_cmmu_dump_config(void); +void m8820x_cmmu_show_translation(unsigned, unsigned, unsigned, int); +void m8820x_show_apr(unsigned); + +/* This is the function table for the mc8820x CMMUs */ +struct cmmu_p cmmu8820x = { + m8820x_cmmu_init, + m8820x_setup_board_config, + m8820x_cpu_configuration_print, + m8820x_cmmu_shutdown_now, + m8820x_cmmu_parity_enable, + m8820x_cmmu_cpu_number, + m8820x_cmmu_set_sapr, + m8820x_cmmu_set_uapr, + m8820x_cmmu_flush_tlb, + m8820x_cmmu_flush_cache, + m8820x_cmmu_flush_inst_cache, + m8820x_cmmu_flush_data_cache, + m8820x_dma_cachectl, + m8820x_dma_cachectl_pa, +#ifdef DDB + m8820x_cmmu_dump_config, + m8820x_cmmu_show_translation, +#else + NULL, + NULL, +#endif +#ifdef DEBUG + m8820x_show_apr, +#else + NULL, +#endif +}; + +/* + * Systems with more than 2 CMMUs per CPU use programmable split schemes. + * + * The following schemes are available on MVME188 boards: + * - split on A12 address bit (A14 for 88204) + * - split on supervisor/user access + * - split on SRAM/non-SRAM addresses, with either supervisor-only or all + * access to SRAM. + * + * MVME188 configuration 6, with 4 CMMUs par CPU, also forces a split on + * A14 address bit. + * + * Under OpenBSD, we will only split on A12 and A14 address bits, since we + * do not want to waste CMMU resources on the SRAM, and user/supervisor + * splits seem less efficient. + * + * The really nasty part of this choice is in the exception handling code, + * when it needs to get error information from up to 4 CMMUs. See eh.S on + * mvme88k for the gory details, luna88k is more sane. + */ + +struct m8820x_cmmu m8820x_cmmu[MAX_CMMUS]; +u_int max_cmmus; +u_int cmmu_shift; + +/* local prototypes */ +void m8820x_cmmu_set(int, unsigned, int, int, int, vaddr_t); +void m8820x_cmmu_wait(int); +void m8820x_cmmu_sync_cache(paddr_t, psize_t); +void m8820x_cmmu_sync_inval_cache(paddr_t, psize_t); +void m8820x_cmmu_inval_cache(paddr_t, psize_t); + +/* Flags passed to m8820x_cmmu_set() */ +#define MODE_VAL 0x01 +#define ADDR_VAL 0x02 + +/* + * This function is called by the MMU module and pokes values + * into the CMMU's registers. + */ +void +m8820x_cmmu_set(int reg, unsigned val, int flags, int cpu, int mode, + vaddr_t addr) +{ + struct m8820x_cmmu *cmmu; + int mmu, cnt; + + mmu = cpu << cmmu_shift; + cmmu = m8820x_cmmu + mmu; + + /* + * We scan all CMMUs to find the matching ones and store the + * values there. + */ + for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, mmu++, cmmu++) { + if ((flags & MODE_VAL) != 0) { + if (CMMU_MODE(mmu) != mode) + continue; + } +#ifdef M88200_HAS_SPLIT_ADDRESS + if ((flags & ADDR_VAL) != 0) { + if (cmmu->cmmu_addr_mask != 0 && + (addr & cmmu->cmmu_addr_mask) != cmmu->cmmu_addr) + continue; + } +#endif + cmmu->cmmu_regs[reg] = val; + } +} + +/* + * Force a read from the CMMU status register, thereby forcing execution to + * stop until all pending CMMU operations are finished. + * This is used by the various cache invalidation functions. + */ +void +m8820x_cmmu_wait(int cpu) +{ + struct m8820x_cmmu *cmmu; + int mmu, cnt; + + mmu = cpu << cmmu_shift; + cmmu = m8820x_cmmu + mmu; + + /* + * We scan all related CMMUs and read their status register. + */ + for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, mmu++, cmmu++) { +#ifdef DEBUG + if (cmmu->cmmu_regs[CMMU_SSR] & CMMU_SSR_BE) { + panic("cache flush failed!"); + } +#else + /* force the read access, but do not issue this statement... */ + __asm__ __volatile__ ("|or r0, r0, %0" :: + "r" (cmmu->cmmu_regs[CMMU_SSR])); +#endif + } +} + +const char *mmutypes[8] = { + "Unknown (0)", + "Unknown (1)", + "Unknown (2)", + "Unknown (3)", + "Unknown (4)", + "M88200 (16K)", + "M88204 (64K)", + "Unknown (7)" +}; + +/* + * Should only be called after the calling cpus knows its cpu + * number and master/slave status . Should be called first + * by the master, before the slaves are started. +*/ +void +m8820x_cpu_configuration_print(int master) +{ + struct m8820x_cmmu *cmmu; + int pid = read_processor_identification_register(); + int proctype = (pid & 0xff00) >> 8; + int procvers = (pid & 0xe) >> 1; + int mmu, cnt, cpu = cpu_number(); + struct simplelock print_lock; + + if (master) + simple_lock_init(&print_lock); + + simple_lock(&print_lock); + + printf("cpu%d: ", cpu); + if (proctype != 0) { + printf("unknown model arch 0x%x rev 0x%x\n", + proctype, procvers); + simple_unlock(&print_lock); + return; + } + + printf("M88100 rev 0x%x", procvers); +#if 0 /* not useful yet */ + if (max_cpus > 1) + printf(", %s", master ? "master" : "slave"); +#endif + printf(", %d CMMU", 1 << cmmu_shift); + + mmu = cpu << cmmu_shift; + cmmu = m8820x_cmmu + mmu; + for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, mmu++, cmmu++) { + int idr = cmmu->cmmu_regs[CMMU_IDR]; + int mmuid = CMMU_TYPE(idr); + + if (mmu % 2 == 0) + printf("\ncpu%d: ", cpu); + else + printf(", "); + + if (mmutypes[mmuid][0] == 'U') + printf("unknown model id 0x%x", mmuid); + else + printf("%s", mmutypes[mmuid]); + /* XXX print address lines */ + printf(" rev 0x%x, %ccache", + CMMU_VERSION(idr), CMMU_MODE(mmu) == INST_CMMU ? 'I' : 'D'); + } + printf("\n"); + +#ifndef ERRATA__XXX_USR + { + static int errata_warn = 0; + + if (proctype != 0 && procvers < 2) { + if (!errata_warn++) + printf("WARNING: M88100 bug workaround code " + "not enabled.\nPlease recompile the kernel " + "with option ERRATA__XXX_USR !\n"); + } + } +#endif + + simple_unlock(&print_lock); +} + +/* + * CMMU initialization routine + */ +void +m8820x_cmmu_init() +{ + struct m8820x_cmmu *cmmu; + unsigned int line, cmmu_num; + int cssp, cpu, type; + u_int32_t apr; + + cmmu = m8820x_cmmu; + for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++, cmmu++) { + type = CMMU_TYPE(cmmu->cmmu_regs[CMMU_IDR]); + + /* + * Reset cache + */ + for (cssp = type == M88204_ID ? 3 : 0; cssp >= 0; cssp--) + for (line = 0; line <= 255; line++) { + cmmu->cmmu_regs[CMMU_SAR] = + line << MC88200_CACHE_SHIFT; + cmmu->cmmu_regs[CMMU_CSSP(cssp)] = + CMMU_CSSP_L5 | CMMU_CSSP_L4 | + CMMU_CSSP_L3 | CMMU_CSSP_L2 | + CMMU_CSSP_L1 | CMMU_CSSP_L0 | + CMMU_CSSP_VV(3, CMMU_VV_INVALID) | + CMMU_CSSP_VV(2, CMMU_VV_INVALID) | + CMMU_CSSP_VV(1, CMMU_VV_INVALID) | + CMMU_CSSP_VV(0, CMMU_VV_INVALID); + } + + /* + * Set the SCTR, SAPR, and UAPR to some known state + */ + cmmu->cmmu_regs[CMMU_SCTR] &= + ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR); + cmmu->cmmu_regs[CMMU_SAPR] = cmmu->cmmu_regs[CMMU_UAPR] = + ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL | + CACHE_INH) & ~APR_V; + + cmmu->cmmu_regs[CMMU_BWP0] = cmmu->cmmu_regs[CMMU_BWP1] = + cmmu->cmmu_regs[CMMU_BWP2] = cmmu->cmmu_regs[CMMU_BWP3] = + cmmu->cmmu_regs[CMMU_BWP4] = cmmu->cmmu_regs[CMMU_BWP5] = + cmmu->cmmu_regs[CMMU_BWP6] = cmmu->cmmu_regs[CMMU_BWP7] = 0; + cmmu->cmmu_regs[CMMU_SCR] = CMMU_FLUSH_CACHE_INV_ALL; + __asm__ __volatile__ ("|or r0, r0, %0" :: + "r" (cmmu->cmmu_regs[CMMU_SSR])); + cmmu->cmmu_regs[CMMU_SCR] = CMMU_FLUSH_SUPER_ALL; + cmmu->cmmu_regs[CMMU_SCR] = CMMU_FLUSH_USER_ALL; + } + + /* + * Enable snooping on multiprocessor systems. + * Snooping is enabled for instruction cmmus as well so that + * we can share breakpoints. + */ + if (max_cpus > 1) { + for (cpu = 0; cpu < max_cpus; cpu++) { +#ifdef DIAGNOSTIC + if (cpu_sets[cpu] == 0) + continue; +#endif + + m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu, + DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu, + INST_CMMU, 0); + + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL, + 0, cpu, 0, 0); + m8820x_cmmu_wait(cpu); + /* Icache gets flushed just below */ + } + } + + /* + * Enable instruction cache. + * Data cache can not be enabled at this point, because some device + * addresses can never be cached, and the no-caching zones are not + * set up yet. + */ + for (cpu = 0; cpu < max_cpus; cpu++) { +#ifdef DIAGNOSTIC + if (cpu_sets[cpu] == 0) + continue; +#endif + + apr = ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL) + & ~(CACHE_INH | APR_V); + + m8820x_cmmu_set(CMMU_SAPR, apr, MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL, + 0, cpu, 0, 0); + m8820x_cmmu_wait(cpu); + } +} + +/* + * Just before poweroff or reset.... + */ +void +m8820x_cmmu_shutdown_now() +{ + unsigned cmmu_num; + struct m8820x_cmmu *cmmu; + + CMMU_LOCK; + cmmu = m8820x_cmmu; + for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++, cmmu++) { + cmmu->cmmu_regs[CMMU_SCTR] &= + ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR); + cmmu->cmmu_regs[CMMU_SAPR] = cmmu->cmmu_regs[CMMU_UAPR] = + ((0x00000 << PG_BITS) | CACHE_INH) & + ~(CACHE_WT | CACHE_GLOBAL | APR_V); + } + CMMU_UNLOCK; +} + +/* + * enable parity + */ +void +m8820x_cmmu_parity_enable() +{ + unsigned cmmu_num; + struct m8820x_cmmu *cmmu; + + cmmu = m8820x_cmmu; + CMMU_LOCK; + for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++, cmmu++) + cmmu->cmmu_regs[CMMU_SCTR] |= CMMU_SCTR_PE; + CMMU_UNLOCK; +} + +void +m8820x_cmmu_set_sapr(unsigned cpu, unsigned ap) +{ + CMMU_LOCK; + m8820x_cmmu_set(CMMU_SAPR, ap, 0, cpu, 0, 0); + CMMU_UNLOCK; +} + +void +m8820x_cmmu_set_uapr(unsigned ap) +{ + int s = splhigh(); + int cpu = cpu_number(); + + CMMU_LOCK; + m8820x_cmmu_set(CMMU_UAPR, ap, 0, cpu, 0, 0); + CMMU_UNLOCK; + splx(s); +} + +/* + * Functions that invalidate TLB entries. + */ + +/* + * flush any tlb + */ +void +m8820x_cmmu_flush_tlb(unsigned cpu, unsigned kernel, vaddr_t vaddr, + vsize_t size) +{ + int s = splhigh(); + + CMMU_LOCK; + + /* + * Since segment operations are horribly expensive, don't + * do any here. Invalidations of up to three pages are performed + * as page invalidations, otherwise the entire tlb is flushed. + * + * Note that this code relies upon size being a multiple of + * a page and vaddr being page-aligned. + */ + if (size == PAGE_SIZE) { /* most frequent situation */ + m8820x_cmmu_set(CMMU_SAR, vaddr, + ADDR_VAL, cpu, 0, vaddr); + m8820x_cmmu_set(CMMU_SCR, + kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE, + ADDR_VAL, cpu, 0, vaddr); + } else if (size > 3 * PAGE_SIZE) { + m8820x_cmmu_set(CMMU_SCR, + kernel ? CMMU_FLUSH_SUPER_ALL : CMMU_FLUSH_USER_ALL, + 0, cpu, 0, 0); + } else + while (size != 0) { + m8820x_cmmu_set(CMMU_SAR, vaddr, + ADDR_VAL, cpu, 0, vaddr); + m8820x_cmmu_set(CMMU_SCR, + kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE, + ADDR_VAL, cpu, 0, vaddr); + + size -= PAGE_SIZE; + vaddr += PAGE_SIZE; + } + + CMMU_UNLOCK; + splx(s); +} + +/* + * Functions that invalidate caches. + * + * Cache invalidates require physical addresses. Care must be exercised when + * using segment invalidates. This implies that the starting physical address + * plus the segment length should be invalidated. A typical mistake is to + * extract the first physical page of a segment from a virtual address, and + * then expecting to invalidate when the pages are not physically contiguous. + * + * We don't push Instruction Caches prior to invalidate because they are not + * snooped and never modified (I guess it doesn't matter then which form + * of the command we use then). + */ + +/* + * flush both Instruction and Data caches + */ +void +m8820x_cmmu_flush_cache(int cpu, paddr_t physaddr, psize_t size) +{ + int s = splhigh(); + CMMU_LOCK; + +#if !defined(BROKEN_MMU_MASK) + if (size > NBSG) { + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0, + cpu, 0, 0); + } else if (size <= MC88200_CACHE_LINE) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL, + cpu, 0, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, ADDR_VAL, + cpu, 0, (unsigned)physaddr); + } else if (size <= NBPG) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL, + cpu, 0, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, ADDR_VAL, + cpu, 0, (unsigned)physaddr); + } else { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, 0, + cpu, 0, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, 0, + cpu, 0, 0); + } +#else + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0, cpu, 0, 0); +#endif /* !BROKEN_MMU_MASK */ + + m8820x_cmmu_wait(cpu); + + CMMU_UNLOCK; + splx(s); +} + +/* + * flush Instruction caches + */ +void +m8820x_cmmu_flush_inst_cache(int cpu, paddr_t physaddr, psize_t size) +{ + int s = splhigh(); + CMMU_LOCK; + +#if !defined(BROKEN_MMU_MASK) + if (size > NBSG) { + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, INST_CMMU, 0); + } else if (size <= MC88200_CACHE_LINE) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + } else if (size <= NBPG) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + } else { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, + MODE_VAL, cpu, INST_CMMU, 0); + } +#else + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, INST_CMMU, 0); +#endif /* !BROKEN_MMU_MASK */ + + m8820x_cmmu_wait(cpu); + + CMMU_UNLOCK; + splx(s); +} + +void +m8820x_cmmu_flush_data_cache(int cpu, paddr_t physaddr, psize_t size) +{ + int s = splhigh(); + CMMU_LOCK; + +#if !defined(BROKEN_MMU_MASK) + if (size > NBSG) { + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + } else if (size <= MC88200_CACHE_LINE) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + } else if (size <= NBPG) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + } else { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL, cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, + MODE_VAL, cpu, DATA_CMMU, 0); + } +#else + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); +#endif /* !BROKEN_MMU_MASK */ + + m8820x_cmmu_wait(cpu); + + CMMU_UNLOCK; + splx(s); +} + +/* + * sync dcache (and icache too) + */ +void +m8820x_cmmu_sync_cache(paddr_t physaddr, psize_t size) +{ + int s = splhigh(); + int cpu = cpu_number(); + + CMMU_LOCK; + +#if !defined(BROKEN_MMU_MASK) + if (size > NBSG) { + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, + cpu, INST_CMMU, 0); + } else if (size <= MC88200_CACHE_LINE) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_LINE, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_LINE, + MODE_VAL, cpu, DATA_CMMU, 0); + } else if (size <= NBPG) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_PAGE, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_PAGE, + MODE_VAL, cpu, DATA_CMMU, 0); + } else { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_SEGMENT, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_SEGMENT, + MODE_VAL, cpu, DATA_CMMU, 0); + } +#else + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, + cpu, INST_CMMU, 0); +#endif /* !BROKEN_MMU_MASK */ + + m8820x_cmmu_wait(cpu); + + CMMU_UNLOCK; + splx(s); +} + +void +m8820x_cmmu_sync_inval_cache(paddr_t physaddr, psize_t size) +{ + int s = splhigh(); + int cpu = cpu_number(); + + CMMU_LOCK; + +#if !defined(BROKEN_MMU_MASK) + if (size > NBSG) { + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, INST_CMMU, 0); + } else if (size <= MC88200_CACHE_LINE) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, + MODE_VAL, cpu, DATA_CMMU, 0); + } else if (size <= NBPG) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, + MODE_VAL, cpu, DATA_CMMU, 0); + } else { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, + MODE_VAL, cpu, DATA_CMMU, 0); + } +#else + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, + cpu, INST_CMMU, 0); +#endif /* !BROKEN_MMU_MASK */ + + m8820x_cmmu_wait(cpu); + + CMMU_UNLOCK; + splx(s); +} + +void +m8820x_cmmu_inval_cache(paddr_t physaddr, psize_t size) +{ + int s = splhigh(); + int cpu = cpu_number(); + + CMMU_LOCK; + +#if !defined(BROKEN_MMU_MASK) + if (size > NBSG) { + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, + cpu, INST_CMMU, 0); + } else if (size <= MC88200_CACHE_LINE) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_LINE, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_LINE, + MODE_VAL, cpu, DATA_CMMU, 0); + } else if (size <= NBPG) { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_PAGE, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_PAGE, + MODE_VAL, cpu, DATA_CMMU, 0); + } else { + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_SEGMENT, + MODE_VAL, cpu, INST_CMMU, 0); + m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, + MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_SEGMENT, + MODE_VAL, cpu, DATA_CMMU, 0); + } +#else + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, + cpu, DATA_CMMU, 0); + m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, + cpu, INST_CMMU, 0); +#endif /* !BROKEN_MMU_MASK */ + + m8820x_cmmu_wait(cpu); + + CMMU_UNLOCK; + splx(s); +} + +void +m8820x_dma_cachectl(vaddr_t va, vsize_t size, int op) +{ + paddr_t pa; +#if !defined(BROKEN_MMU_MASK) + psize_t count; + + while (size != 0) { + count = NBPG - (va & PGOFSET); + + if (size < count) + count = size; + + if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) { + switch (op) { + case DMA_CACHE_SYNC: + m8820x_cmmu_sync_cache(pa, count); + break; + case DMA_CACHE_SYNC_INVAL: + m8820x_cmmu_sync_inval_cache(pa, count); + break; + default: + m8820x_cmmu_inval_cache(pa, count); + break; + } + } + + va += count; + size -= count; + } +#else + /* XXX This assumes the space is also physically contiguous */ + if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) { + switch (op) { + case DMA_CACHE_SYNC: + m8820x_cmmu_sync_cache(pa, size); + break; + case DMA_CACHE_SYNC_INVAL: + m8820x_cmmu_sync_inval_cache(pa, size); + break; + default: + m8820x_cmmu_inval_cache(pa, size); + break; + } + } +#endif /* !BROKEN_MMU_MASK */ +} + +void +m8820x_dma_cachectl_pa(paddr_t pa, psize_t size, int op) +{ +#if !defined(BROKEN_MMU_MASK) + psize_t count; + + while (size != 0) { + count = NBPG - (va & PGOFSET); + + if (size < count) + count = size; + + switch (op) { + case DMA_CACHE_SYNC: + m8820x_cmmu_sync_cache(pa, count); + break; + case DMA_CACHE_SYNC_INVAL: + m8820x_cmmu_sync_inval_cache(pa, count); + break; + default: + m8820x_cmmu_inval_cache(pa, count); + break; + } + + pa += count; + size -= count; + } +#else + switch (op) { + case DMA_CACHE_SYNC: + m8820x_cmmu_sync_cache(pa, size); + break; + case DMA_CACHE_SYNC_INVAL: + m8820x_cmmu_sync_inval_cache(pa, size); + break; + default: + m8820x_cmmu_inval_cache(pa, size); + break; + } +#endif /* !BROKEN_MMU_MASK */ +} + +#ifdef DDB +void +m8820x_cmmu_dump_config() +{ + struct m8820x_cmmu *cmmu; + int cmmu_num; + + db_printf("Current CPU/CMMU configuration:\n"); + cmmu = m8820x_cmmu; + for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++, cmmu++) { +#ifdef M88200_HAS_SPLIT_ADDRESS + db_printf("CMMU #%d: %s CMMU for CPU %d, addr 0x%08lx mask 0x%08lx\n", + cmmu_num, + CMMU_MODE(cmmu_num) == INST_CMMU ? "inst" : "data", + cmmu_num >> cmmu_shift, + cmmu->cmmu_addr, cmmu->cmmu_addr_mask); +#else + db_printf("CMMU #%d: %s CMMU for CPU %d", + cmmu_num, + CMMU_MODE(cmmu_num) == INST_CMMU ? "inst" : "data", + cmmu_num >> cmmu_shift); +#endif + } +} + +/* + * Show (for debugging) how the current CPU translates the given ADDRESS + * (as DATA). + */ +void +m8820x_cmmu_show_translation(unsigned address, unsigned supervisor_flag, + unsigned verbose_flag, int unused __attribute__ ((unused))) +{ + struct m8820x_cmmu *cmmu; + int cpu = cpu_number(); + vaddr_t va = address; + int cmmu_num, cnt; + u_int32_t value; + + /* + * Find the correct data CMMU. + */ + cmmu_num = cpu << cmmu_shift; + cmmu = m8820x_cmmu + cmmu_num; + for (cnt = 1 << cmmu_shift; cnt != 0; cnt--, cmmu_num++, cmmu++) { + if (CMMU_MODE(cmmu_num) == INST_CMMU) + continue; +#ifdef M88200_HAS_SPLIT_ADDRESS + if (cmmu->cmmu_addr_mask == 0 || + (va & cmmu->cmmu_addr_mask) == + cmmu->cmmu_addr) +#endif + break; + } + if (cnt == 0) { + db_printf("No matching cmmu for VA %08x\n", address); + return; + } + + if (verbose_flag != 0) + db_printf("VA %08x is managed by CMMU#%d.\n", + address, cmmu_num); + + /* + * Perform some sanity checks. + */ + if (verbose_flag == 0) { + if ((cmmu->cmmu_regs[CMMU_SCTR] & + CMMU_SCTR_SE) == 0) + db_printf("WARNING: snooping not enabled for CMMU#%d.\n", + cmmu_num); + } else { + int i; + + cmmu = m8820x_cmmu; + for (i = 0; i < max_cmmus; i++, cmmu++) + if (verbose_flag > 1 || + (cmmu->cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE) == 0) { + db_printf("CMMU#%d (cpu %d %s) snooping %s\n", + i, i >> cmmu_shift, + CMMU_MODE(i) == INST_CMMU ? "inst" : "data", + (cmmu->cmmu_regs[CMMU_SCTR] & + CMMU_SCTR_SE) ? "on" : "OFF"); + } + cmmu = m8820x_cmmu + cmmu_num; + } + + /* + * Ask for a CMMU probe and report its result. + */ + { + u_int32_t ssr; + + cmmu->cmmu_regs[CMMU_SAR] = address; + cmmu->cmmu_regs[CMMU_SCR] = + supervisor_flag ? CMMU_PROBE_SUPER : CMMU_PROBE_USER; + ssr = cmmu->cmmu_regs[CMMU_SSR]; + + switch (verbose_flag) { + case 2: + db_printf("probe of 0x%08x returns ssr=0x%08x\n", + address, ssr); + /* FALLTHROUGH */ + case 1: + if (ssr & CMMU_SSR_V) + db_printf("PROBE of 0x%08x returns phys=0x%x", + address, cmmu->cmmu_regs[CMMU_SAR]); + else + db_printf("PROBE fault at 0x%x", + cmmu->cmmu_regs[CMMU_PFAR]); + if (ssr & CMMU_SSR_CE) + db_printf(", copyback err"); + if (ssr & CMMU_SSR_BE) + db_printf(", bus err"); + if (ssr & CACHE_WT) + db_printf(", writethrough"); + if (ssr & CMMU_SSR_SO) + db_printf(", sup prot"); + if (ssr & CACHE_GLOBAL) + db_printf(", global"); + if (ssr & CACHE_INH) + db_printf(", cache inhibit"); + if (ssr & CMMU_SSR_M) + db_printf(", modified"); + if (ssr & CMMU_SSR_U) + db_printf(", used"); + if (ssr & CMMU_SSR_PROT) + db_printf(", write prot"); + if (ssr & CMMU_SSR_BH) + db_printf(", BATC"); + db_printf(".\n"); + break; + } + } + + /* + * Interpret area descriptor. + */ + + if (supervisor_flag) + value = cmmu->cmmu_regs[CMMU_SAPR]; + else + value = cmmu->cmmu_regs[CMMU_UAPR]; + + switch (verbose_flag) { + case 2: + db_printf("CMMU#%d", cmmu_num); + db_printf(" %cAPR is 0x%08x\n", + supervisor_flag ? 'S' : 'U', value); + /* FALLTHROUGH */ + case 1: + db_printf("CMMU#%d", cmmu_num); + db_printf(" %cAPR: SegTbl: 0x%x000p", + supervisor_flag ? 'S' : 'U', PG_PFNUM(value)); + if (value & CACHE_WT) + db_printf(", WTHRU"); + if (value & CACHE_GLOBAL) + db_printf(", GLOBAL"); + if (value & CACHE_INH) + db_printf(", INHIBIT"); + if (value & APR_V) + db_printf(", VALID"); + db_printf("\n"); + break; + } + + if ((value & APR_V) == 0) { + db_printf("VA 0x%08x -> apr 0x%08x not valid\n", va, value); + return; + } + + value &= PG_FRAME; /* now point to seg page */ + + /* + * Walk segment and page tables to find our page. + */ + { + sdt_entry_t sdt; + + if (verbose_flag) + db_printf("will follow to entry %d of page at 0x%x...\n", + SDTIDX(va), value); + value |= SDTIDX(va) * sizeof(sdt_entry_t); + + if (badwordaddr((vaddr_t)value)) { + db_printf("VA 0x%08x -> segment table @0x%08x not accessible\n", + va, value); + return; + } + + sdt = *(sdt_entry_t *)value; + switch (verbose_flag) { + case 2: + db_printf("SEG DESC @0x%x is 0x%08x\n", value, sdt); + /* FALLTHROUGH */ + case 1: + db_printf("SEG DESC @0x%x: PgTbl: 0x%x000", + value, PG_PFNUM(sdt)); + if (sdt & CACHE_WT) + db_printf(", WTHRU"); + if (sdt & SG_SO) + db_printf(", S-PROT"); + if (sdt & CACHE_GLOBAL) + db_printf(", GLOBAL"); + if (sdt & CACHE_INH) + db_printf(", $INHIBIT"); + if (sdt & SG_PROT) + db_printf(", W-PROT"); + if (sdt & SG_V) + db_printf(", VALID"); + db_printf(".\n"); + break; + } + + if ((sdt & SG_V) == 0) { + db_printf("VA 0x%08x -> segment entry 0x%8x @0x%08x not valid\n", + va, sdt, value); + return; + } + + value = ptoa(PG_PFNUM(sdt)); + } + + { + pt_entry_t pte; + + if (verbose_flag) + db_printf("will follow to entry %d of page at 0x%x...\n", + PDTIDX(va), value); + value |= PDTIDX(va) * sizeof(pt_entry_t); + + if (badwordaddr((vaddr_t)value)) { + db_printf("VA 0x%08x -> page table entry @0x%08x not accessible\n", + va, value); + return; + } + + pte = *(pt_entry_t *)value; + switch (verbose_flag) { + case 2: + db_printf("PAGE DESC @0x%x is 0x%08x.\n", value, pte); + /* FALLTHROUGH */ + case 1: + db_printf("PAGE DESC @0x%x: page @%x000", + value, PG_PFNUM(pte)); + if (pte & PG_W) + db_printf(", WIRE"); + if (pte & CACHE_WT) + db_printf(", WTHRU"); + if (pte & PG_SO) + db_printf(", S-PROT"); + if (pte & CACHE_GLOBAL) + db_printf(", GLOBAL"); + if (pte & CACHE_INH) + db_printf(", $INHIBIT"); + if (pte & PG_M) + db_printf(", MOD"); + if (pte & PG_U) + db_printf(", USED"); + if (pte & PG_PROT) + db_printf(", W-PROT"); + if (pte & PG_V) + db_printf(", VALID"); + db_printf(".\n"); + break; + } + + if ((pte & PG_V) == 0) { + db_printf("VA 0x%08x -> page table entry 0x%08x @0x%08x not valid\n", + va, pte, value); + return; + } + + value = ptoa(PG_PFNUM(pte)) | (va & PAGE_MASK); + } + + db_printf("VA 0x%08x -> PA 0x%08x\n", va, value); +} +#endif /* DDB */ + +#ifdef DEBUG +void +m8820x_show_apr(unsigned value) +{ + printf("table @ 0x%x000", PG_PFNUM(value)); + if (value & CACHE_WT) + printf(", writethrough"); + if (value & CACHE_GLOBAL) + printf(", global"); + if (value & CACHE_INH) + printf(", cache inhibit"); + if (value & APR_V) + printf(", valid"); + printf("\n"); +} +#endif diff --git a/sys/arch/mvme88k/include/m8820x.h b/sys/arch/mvme88k/include/m8820x.h index 4b881800351..1a763f05f48 100644 --- a/sys/arch/mvme88k/include/m8820x.h +++ b/sys/arch/mvme88k/include/m8820x.h @@ -1,4 +1,6 @@ -/* $OpenBSD: m8820x.h,v 1.14 2004/08/02 08:35:00 miod Exp $ */ +#ifndef _MVME88K_M8820X_H_ +#define _MVME88K_M8820X_H_ +/* $OpenBSD: m8820x.h,v 1.15 2004/08/06 13:23:49 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * @@ -49,7 +51,13 @@ * the rights to redistribute these changes. */ -#include <m88k/m8820x.h> +/* + * Code features to enable + */ + +#ifdef MVME188 +#define M88200_HAS_SPLIT_ADDRESS +#endif /* * Address masks for MVME188 CMMU configs @@ -59,3 +67,7 @@ #define CMMU_A12_MASK (1 << 12) #define CMMU_A14_MASK (1 << 14) #define CMMU_SRAM_MASK ((1 << 31) | (1 << 30)) + +#include <m88k/m8820x.h> + +#endif /* _MVME88K_M8820X_H_ */ diff --git a/sys/arch/mvme88k/mvme88k/m8820x.c b/sys/arch/mvme88k/mvme88k/m8820x.c index 8011a7e5abc..d9172b67905 100644 --- a/sys/arch/mvme88k/mvme88k/m8820x.c +++ b/sys/arch/mvme88k/mvme88k/m8820x.c @@ -1,4 +1,4 @@ -/* $OpenBSD: m8820x.c,v 1.38 2004/08/04 15:54:38 miod Exp $ */ +/* $OpenBSD: m8820x.c,v 1.39 2004/08/06 13:23:49 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * @@ -23,71 +23,15 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -/* - * Copyright (c) 2001 Steve Murphree, Jr. - * Copyright (c) 1996 Nivas Madhur - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Nivas Madhur. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -/* - * Mach Operating System - * Copyright (c) 1993-1991 Carnegie Mellon University - * Copyright (c) 1991 OMRON Corporation - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND - * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ #include <sys/param.h> #include <sys/systm.h> -#include <sys/simplelock.h> #include <machine/asm_macro.h> #include <machine/cpu_number.h> +#ifdef DEBUG #include <machine/locore.h> +#endif #include <machine/cmmu.h> #include <machine/m8820x.h> @@ -98,68 +42,7 @@ #include <machine/mvme188.h> #endif -#include <uvm/uvm_extern.h> - -#ifdef DDB -#include <ddb/db_output.h> /* db_printf() */ -#endif - -/* - * On some versions of the 88200, page size flushes don't work. I am using - * sledge hammer approach till I find for sure which ones are bad XXX nivas - */ -#define BROKEN_MMU_MASK - -u_int max_cmmus; - -void m8820x_cmmu_init(void); -void m8820x_setup_board_config(void); -void m8820x_cpu_configuration_print(int); -void m8820x_cmmu_shutdown_now(void); -void m8820x_cmmu_parity_enable(void); -unsigned m8820x_cmmu_cpu_number(void); -void m8820x_cmmu_set_sapr(unsigned, unsigned); -void m8820x_cmmu_set_uapr(unsigned); -void m8820x_cmmu_flush_tlb(unsigned, unsigned, vaddr_t, vsize_t); -void m8820x_cmmu_flush_cache(int, paddr_t, psize_t); -void m8820x_cmmu_flush_inst_cache(int, paddr_t, psize_t); -void m8820x_cmmu_flush_data_cache(int, paddr_t, psize_t); -void m8820x_dma_cachectl(vaddr_t, vsize_t, int); -void m8820x_dma_cachectl_pa(paddr_t, psize_t, int); -void m8820x_cmmu_dump_config(void); -void m8820x_cmmu_show_translation(unsigned, unsigned, unsigned, int); -void m8820x_show_apr(unsigned); - -/* This is the function table for the mc8820x CMMUs */ -struct cmmu_p cmmu8820x = { - m8820x_cmmu_init, - m8820x_setup_board_config, - m8820x_cpu_configuration_print, - m8820x_cmmu_shutdown_now, - m8820x_cmmu_parity_enable, - m8820x_cmmu_cpu_number, - m8820x_cmmu_set_sapr, - m8820x_cmmu_set_uapr, - m8820x_cmmu_flush_tlb, - m8820x_cmmu_flush_cache, - m8820x_cmmu_flush_inst_cache, - m8820x_cmmu_flush_data_cache, - m8820x_dma_cachectl, - m8820x_dma_cachectl_pa, -#ifdef DDB - m8820x_cmmu_dump_config, - m8820x_cmmu_show_translation, -#else - NULL, - NULL, -#endif -#ifdef DEBUG - m8820x_show_apr, -#else - NULL, -#endif -}; - +#ifdef MVME188 /* * There are 6 possible MVME188 HYPERmodule configurations: * - config 0: 4 CPUs, 8 CMMUs @@ -167,69 +50,8 @@ struct cmmu_p cmmu8820x = { * - config 2: 1 CPUs, 8 CMMUs * - config 5: 2 CPUs, 4 CMMUs * - config 6: 1 CPU, 4 CMMUs - * - config A: 1 CPU, 2 CMMUs + * - config A: 1 CPU, 2 CMMUs (similar in operation to MVME187) * which can exist either with MC88200 or MC88204 CMMUs. - * - * Systems with more than 2 CMMUs per CPU use programmable split schemes, - * through PCNFA (for code CMMUs) and PCNFB (for data CMMUs) configuration - * registers. - * - * The following schemes are available: - * - split on A12 address bit (A14 for 88204) - * - split on supervisor/user access - * - split on SRAM/non-SRAM addresses, with either supervisor-only or all - * access to SRAM. - * - * Configuration 6, with 4 CMMUs par CPU, also forces a split on A14 address - * bit. - * - * Under OpenBSD, we will only split on A12 and A14 address bits, since we - * do not want to waste CMMU resources on the SRAM, and user/supervisor - * splits seem less efficient. - * - * The really nasty part of this choice is in the exception handling code, - * when it needs to get error information from up to 4 CMMUs. See eh.S for - * the gory details. - */ - -/* - * CMMU kernel information - */ -struct m8820x_cmmu { - volatile u_int32_t *cmmu_regs; /* CMMU "base" area */ - unsigned int cmmu_cpu; /* cpu number it is attached to */ - unsigned int cmmu_type; -#define NO_CMMU 0x00 -#define INST_CMMU 0x01 -#define DATA_CMMU 0x02 - vaddr_t cmmu_addr; /* address range */ - vaddr_t cmmu_addr_mask; /* address mask */ -}; - -/* - * Structure for accessing MMUS properly - */ - -#define MAX_CMMUS (2 * MAX_CPUS) /* maximum cmmus on the board */ - -struct m8820x_cmmu m8820x_cmmu[MAX_CMMUS] = { - /* address, cpu, mode, addr, mask */ - { NULL, -1, INST_CMMU, 0, 0 }, - { NULL, -1, DATA_CMMU, 0, 0 }, - { NULL, -1, INST_CMMU, 0, 0 }, - { NULL, -1, DATA_CMMU, 0, 0 }, - { NULL, -1, INST_CMMU, 0, 0 }, - { NULL, -1, DATA_CMMU, 0, 0 }, - { NULL, -1, INST_CMMU, 0, 0 }, - { NULL, -1, DATA_CMMU, 0, 0 } -}; - -unsigned int cmmu_shift; - -#ifdef MVME188 -/* - * The following list describes the different MVME188 configurations - * which are supported by this code. */ const struct board_config { int ncpus; @@ -254,45 +76,17 @@ const struct board_config { }; #endif -/* local prototypes */ -void m8820x_cmmu_set(int, unsigned, int, int, int, vaddr_t); -void m8820x_cmmu_wait(int); -void m8820x_cmmu_sync_cache(paddr_t, psize_t); -void m8820x_cmmu_sync_inval_cache(paddr_t, psize_t); -void m8820x_cmmu_inval_cache(paddr_t, psize_t); - -/* Flags passed to m8820x_cmmu_set() */ -#define MODE_VAL 0x01 -#define ADDR_VAL 0x02 - -#ifdef DEBUG -void -m8820x_show_apr(unsigned value) -{ - printf("table @ 0x%x000", PG_PFNUM(value)); - if (value & CACHE_WT) - printf(", writethrough"); - if (value & CACHE_GLOBAL) - printf(", global"); - if (value & CACHE_INH) - printf(", cache inhibit"); - if (value & APR_V) - printf(", valid"); - printf("\n"); -} -#endif - /* * This routine sets up the CPU/CMMU configuration. */ void m8820x_setup_board_config() { - volatile unsigned *cr; + struct m8820x_cmmu *cmmu; int num, cmmu_num; int vme188_config; #ifdef MVME188 - u_int32_t *volatile whoami; + u_int32_t whoami; #endif master_cpu = 0; /* temp to get things going */ @@ -303,21 +97,16 @@ m8820x_setup_board_config() /* There is no WHOAMI reg on MVME187 - fake it... */ vme188_config = 0x0a; m8820x_cmmu[0].cmmu_regs = (void *)SBC_CMMU_I; - m8820x_cmmu[0].cmmu_cpu = 0; m8820x_cmmu[1].cmmu_regs = (void *)SBC_CMMU_D; - m8820x_cmmu[1].cmmu_cpu = 0; - m8820x_cmmu[2].cmmu_regs = (void *)NULL; - m8820x_cmmu[3].cmmu_regs = (void *)NULL; - m8820x_cmmu[4].cmmu_regs = (void *)NULL; - m8820x_cmmu[5].cmmu_regs = (void *)NULL; - m8820x_cmmu[6].cmmu_regs = (void *)NULL; - m8820x_cmmu[7].cmmu_regs = (void *)NULL; + max_cpus = 1; + max_cmmus = 2; + cmmu_shift = 1; break; #endif /* MVME187 */ #ifdef MVME188 case BRD_188: - whoami = (u_int32_t *volatile)MVME188_WHOAMI; - vme188_config = (*whoami & 0xf0) >> 4; + whoami = *(volatile u_int32_t *)MVME188_WHOAMI; + vme188_config = (whoami & 0xf0) >> 4; m8820x_cmmu[0].cmmu_regs = (void *)VME_CMMU_I0; m8820x_cmmu[1].cmmu_regs = (void *)VME_CMMU_D0; m8820x_cmmu[2].cmmu_regs = (void *)VME_CMMU_I1; @@ -326,17 +115,15 @@ m8820x_setup_board_config() m8820x_cmmu[5].cmmu_regs = (void *)VME_CMMU_D2; m8820x_cmmu[6].cmmu_regs = (void *)VME_CMMU_I3; m8820x_cmmu[7].cmmu_regs = (void *)VME_CMMU_D3; + max_cpus = bd_config[vme188_config].ncpus; + max_cmmus = bd_config[vme188_config].ncmmus; + cmmu_shift = ff1(max_cmmus / max_cpus); break; #endif /* MVME188 */ } - max_cpus = bd_config[vme188_config].ncpus; - max_cmmus = bd_config[vme188_config].ncmmus; - - cmmu_shift = ff1(max_cmmus / max_cpus); - #ifdef MVME188 - if (bd_config[vme188_config].ncpus > 0) { + if (bd_config[vme188_config].ncpus != 0) { /* 187 has a fixed configuration, no need to print it */ if (brdtyp == BRD_188) { printf("MVME188 board configuration #%X " @@ -349,12 +136,12 @@ m8820x_setup_board_config() } #endif -#ifdef DIAGNOSTIC +#ifdef DEBUG /* - * Probe for available MMUs + * Check CMMU type */ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; + volatile unsigned *cr = m8820x_cmmu[cmmu_num].cmmu_regs; if (badwordaddr((vaddr_t)cr) == 0) { int type; @@ -364,14 +151,12 @@ m8820x_setup_board_config() "at CMMU address %p\n", cr); continue; /* will probably die quickly */ } - } else - m8820x_cmmu[cmmu_num].cmmu_type = NO_CMMU; + } } #endif /* - * Now that we know which CMMUs are there, let's report on which - * CPU/CMMU sets seem complete (hopefully all) + * Now that we know which CMMUs are there, report every association */ for (num = 0; num < max_cpus; num++) { int type; @@ -380,16 +165,29 @@ m8820x_setup_board_config() type = CMMU_TYPE(m8820x_cmmu[num << cmmu_shift]. cmmu_regs[CMMU_IDR]); - printf("CPU%d is attached with %d MC8820%c CMMUs\n", + printf("CPU%d is associated to %d MC8820%c CMMUs\n", num, 1 << cmmu_shift, type == M88204_ID ? '4' : '0'); } #ifdef MVME188 /* - * Configure CPU/CMMU strategy into PCNFA and PCNFB board registers. - * We should theoretically only set these on configurations 1, 2 - * and 6, since the other ones do not have P bus decoders. + * Systems with more than 2 CMMUs per CPU use programmable split + * schemes, through PCNFA (for code CMMUs) and PCNFB (for data CMMUs) + * configuration registers. + * + * The following schemes are available: + * - split on A12 address bit (A14 for 88204) + * - split on supervisor/user access + * - split on SRAM/non-SRAM addresses, with either supervisor-only or + * all access to SRAM. + * + * Configuration 6, with 4 CMMUs par CPU, also allows a split on A14 + * address bit. + * + * Setup the default A12/A14 split here. We should theoretically only + * set the PCNFA and PCNFB on configurations 1, 2 and 6, since the + * other ones do not have P bus decoders. * However, is it safe to write them anyways - the values will be * discarded. Just don't do this on a 187... */ @@ -397,20 +195,12 @@ m8820x_setup_board_config() *(volatile unsigned long *)MVME188_PCNFA = 0; *(volatile unsigned long *)MVME188_PCNFB = 0; } -#endif - - /* - * Calculate the CMMU<->CPU connections - */ - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - m8820x_cmmu[cmmu_num].cmmu_cpu = - (cmmu_num * max_cpus) / max_cmmus; - } /* * Now set up addressing limits */ - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { + for (cmmu_num = 0, cmmu = m8820x_cmmu; cmmu_num < max_cmmus; + cmmu_num++, cmmu++) { num = cmmu_num >> 1; /* CPU view of the CMMU */ switch (cmmu_shift) { @@ -420,9 +210,8 @@ m8820x_setup_board_config() * CMMU numbers 0 and 1 match on A14 set, * 2 and 3 on A14 clear */ - m8820x_cmmu[cmmu_num].cmmu_addr |= - (num < 2 ? CMMU_A14_MASK : 0); - m8820x_cmmu[cmmu_num].cmmu_addr_mask |= CMMU_A14_MASK; + cmmu->cmmu_addr |= (num < 2 ? CMMU_A14_MASK : 0); + cmmu->cmmu_addr_mask |= CMMU_A14_MASK; /* FALLTHROUGH */ case 2: @@ -431,9 +220,8 @@ m8820x_setup_board_config() * CMMU numbers 0 and 2 match on A12 set, * 1 and 3 on A12 clear. */ - m8820x_cmmu[cmmu_num].cmmu_addr |= - (num & 1 ? 0 : CMMU_A12_MASK); - m8820x_cmmu[cmmu_num].cmmu_addr_mask |= CMMU_A12_MASK; + cmmu->cmmu_addr |= (num & 1 ? 0 : CMMU_A12_MASK); + cmmu->cmmu_addr_mask |= CMMU_A12_MASK; break; case 1: @@ -441,8 +229,8 @@ m8820x_setup_board_config() * We don't need to set up anything for the hardwired * configurations. */ - m8820x_cmmu[cmmu_num].cmmu_addr = 0; - m8820x_cmmu[cmmu_num].cmmu_addr_mask = 0; + cmmu->cmmu_addr = 0; + cmmu->cmmu_addr_mask = 0; break; } @@ -450,321 +238,12 @@ m8820x_setup_board_config() * If these CMMUs are 88204, these splitting address lines * need to be shifted two bits. */ - if (CMMU_TYPE(m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_IDR]) == - M88204_ID) { - m8820x_cmmu[cmmu_num].cmmu_addr <<= 2; - m8820x_cmmu[cmmu_num].cmmu_addr_mask <<= 2; + if (CMMU_TYPE(cmmu->cmmu_regs[CMMU_IDR]) == M88204_ID) { + cmmu->cmmu_addr <<= 2; + cmmu->cmmu_addr_mask <<= 2; } } -} - -#ifdef DDB -void -m8820x_cmmu_dump_config() -{ -#ifdef MVME188 - int cmmu_num; - -#ifdef MVME187 - if (brdtyp != BRD_188) - return; #endif - - db_printf("Current CPU/CMMU configuration:\n"); - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - db_printf("CMMU #%d: %s CMMU for CPU %d:\n addr 0x%08lx mask 0x%08lx\n", - cmmu_num, - (m8820x_cmmu[cmmu_num].cmmu_type == INST_CMMU) ? "inst" : "data", - m8820x_cmmu[cmmu_num].cmmu_cpu, - m8820x_cmmu[cmmu_num].cmmu_addr, - m8820x_cmmu[cmmu_num].cmmu_addr_mask); - } -#endif /* MVME188 */ -} -#endif /* DDB */ - -/* - * This function is called by the MMU module and pokes values - * into the CMMU's registers. - */ -void -m8820x_cmmu_set(int reg, unsigned val, int flags, int cpu, int mode, - vaddr_t addr) -{ - int mmu; - - /* - * We scan all CMMUs to find the matching ones and store the - * values there. - */ - for (mmu = cpu << cmmu_shift; - mmu < (cpu + 1) << cmmu_shift; mmu++) { - if ((flags & MODE_VAL) != 0) { - if (m8820x_cmmu[mmu].cmmu_type != mode) - continue; - } -#ifdef MVME188 - if ((flags & ADDR_VAL) != 0) { - if (m8820x_cmmu[mmu].cmmu_addr_mask != 0 && - (addr & m8820x_cmmu[mmu].cmmu_addr_mask) != - m8820x_cmmu[mmu].cmmu_addr) - continue; - } -#endif - m8820x_cmmu[mmu].cmmu_regs[reg] = val; - } -} - -/* - * Force a read from the CMMU status register, thereby forcing execution to - * stop until all pending CMMU operations are finished. - * This is used by the various cache invalidation functions. - */ -void -m8820x_cmmu_wait(int cpu) -{ - int mmu; - - /* - * We scan all related CMMUs and read their status register. - */ - for (mmu = cpu << cmmu_shift; - mmu < (cpu + 1) << cmmu_shift; mmu++) { -#ifdef DEBUG - if (m8820x_cmmu[mmu].cmmu_regs[CMMU_SSR] & CMMU_SSR_BE) { - panic("cache flush failed!"); - } -#else - /* force the read access, but do not issue this statement... */ - __asm__ __volatile__ ("|or r0, r0, %0" :: - "r" (m8820x_cmmu[mmu].cmmu_regs[CMMU_SSR])); -#endif - } -} - -const char *mmutypes[8] = { - "Unknown (0)", - "Unknown (1)", - "Unknown (2)", - "Unknown (3)", - "Unknown (4)", - "M88200 (16K)", - "M88204 (64K)", - "Unknown (7)" -}; - -/* - * Should only be called after the calling cpus knows its cpu - * number and master/slave status . Should be called first - * by the master, before the slaves are started. -*/ -void -m8820x_cpu_configuration_print(int master) -{ - int pid = read_processor_identification_register(); - int proctype = (pid & 0xff00) >> 8; - int procvers = (pid & 0xe) >> 1; - int mmu, cpu = cpu_number(); - struct simplelock print_lock; - - if (master) - simple_lock_init(&print_lock); - - simple_lock(&print_lock); - - printf("cpu%d: ", cpu); - if (proctype != 0) { - printf("unknown model arch 0x%x rev 0x%x\n", - proctype, procvers); - simple_unlock(&print_lock); - return; - } - - printf("M88100 rev 0x%x", procvers); -#if 0 /* not useful yet */ -#ifdef MVME188 - if (brdtyp == BRD_188) - printf(", %s", master ? "master" : "slave"); -#endif -#endif - printf(", %d CMMU", 1 << cmmu_shift); - - for (mmu = cpu << cmmu_shift; mmu < (cpu + 1) << cmmu_shift; - mmu++) { - int idr = m8820x_cmmu[mmu].cmmu_regs[CMMU_IDR]; - int mmuid = CMMU_TYPE(idr); - - if (mmu % 2 == 0) - printf("\ncpu%d: ", cpu); - else - printf(", "); - - if (mmutypes[mmuid][0] == 'U') - printf("unknown model id 0x%x", mmuid); - else - printf("%s", mmutypes[mmuid]); - printf(" rev 0x%x, %scache", - CMMU_VERSION(idr), - m8820x_cmmu[mmu].cmmu_type == INST_CMMU ? "I" : "D"); - } - printf("\n"); - -#ifndef ERRATA__XXX_USR - { - static int errata_warn = 0; - - if (proctype != 0 && procvers < 2) { - if (!errata_warn++) - printf("WARNING: M88100 bug workaround code " - "not enabled.\nPlease recompile the kernel " - "with option ERRATA__XXX_USR !\n"); - } - } -#endif - - simple_unlock(&print_lock); -} - -/* - * CMMU initialization routine - */ -void -m8820x_cmmu_init() -{ - unsigned int line, cmmu_num; - int cssp, cpu, type; - u_int32_t apr; - volatile unsigned *cr; - - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) { - if (m8820x_cmmu[cmmu_num].cmmu_type != NO_CMMU) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; - type = CMMU_TYPE(cr[CMMU_IDR]); - - /* - * Reset cache - */ - for (cssp = type == M88204_ID ? 3 : 0; - cssp >= 0; cssp--) - for (line = 0; line <= 255; line++) { - cr[CMMU_SAR] = - line << MC88200_CACHE_SHIFT; - cr[CMMU_CSSP(cssp)] = - CMMU_CSSP_L5 | CMMU_CSSP_L4 | - CMMU_CSSP_L3 | CMMU_CSSP_L2 | - CMMU_CSSP_L1 | CMMU_CSSP_L0 | - CMMU_CSSP_VV(3, CMMU_VV_INVALID) | - CMMU_CSSP_VV(2, CMMU_VV_INVALID) | - CMMU_CSSP_VV(1, CMMU_VV_INVALID) | - CMMU_CSSP_VV(0, CMMU_VV_INVALID); - } - - /* - * Set the SCTR, SAPR, and UAPR to some known state - */ - cr[CMMU_SCTR] &= - ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR); - cr[CMMU_SAPR] = cr[CMMU_UAPR] = - ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL | - CACHE_INH) & ~APR_V; - - cr[CMMU_BWP0] = cr[CMMU_BWP1] = - cr[CMMU_BWP2] = cr[CMMU_BWP3] = - cr[CMMU_BWP4] = cr[CMMU_BWP5] = - cr[CMMU_BWP6] = cr[CMMU_BWP7] = 0; - cr[CMMU_SCR] = CMMU_FLUSH_CACHE_INV_ALL; - __asm__ __volatile__ ("|or r0, r0, %0" :: - "r" (cr[CMMU_SSR])); - cr[CMMU_SCR] = CMMU_FLUSH_SUPER_ALL; - cr[CMMU_SCR] = CMMU_FLUSH_USER_ALL; - } - } - - /* - * Enable snooping on MVME188 only. - * Snooping is enabled for instruction cmmus as well so that - * we can share breakpoints. - */ -#ifdef MVME188 - if (brdtyp == BRD_188) { - for (cpu = 0; cpu < max_cpus; cpu++) { - if (cpu_sets[cpu] == 0) - continue; - - m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu, - DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu, - INST_CMMU, 0); - - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL, - 0, cpu, 0, 0); - m8820x_cmmu_wait(cpu); - /* Icache gets flushed just below */ - } - } -#endif - - /* - * Enable instruction cache. - * Data cache can not be enabled at this point, because some device - * addresses can never be cached, and the no-caching zones are not - * set up yet. - */ - for (cpu = 0; cpu < max_cpus; cpu++) { - if (cpu_sets[cpu] == 0) - continue; - - apr = ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL) - & ~(CACHE_INH | APR_V); - - m8820x_cmmu_set(CMMU_SAPR, apr, MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL, - 0, cpu, 0, 0); - m8820x_cmmu_wait(cpu); - } -} - -/* - * Just before poweroff or reset.... - */ -void -m8820x_cmmu_shutdown_now() -{ - unsigned cmmu_num; - volatile unsigned *cr; - - CMMU_LOCK; - for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++) - if (m8820x_cmmu[cmmu_num].cmmu_type != NO_CMMU) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; - - cr[CMMU_SCTR] &= - ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR); - cr[CMMU_SAPR] = cr[CMMU_UAPR] = - ((0x00000 << PG_BITS) | CACHE_INH) & - ~(CACHE_WT | CACHE_GLOBAL | APR_V); - } - CMMU_UNLOCK; -} - -/* - * enable parity - */ -void -m8820x_cmmu_parity_enable() -{ - unsigned cmmu_num; - volatile unsigned *cr; - - CMMU_LOCK; - - for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) - if (m8820x_cmmu[cmmu_num].cmmu_type != NO_CMMU) { - cr = m8820x_cmmu[cmmu_num].cmmu_regs; - cr[CMMU_SCTR] |= CMMU_SCTR_PE; - } - - CMMU_UNLOCK; } /* @@ -812,713 +291,3 @@ m8820x_cmmu_cpu_number() panic("can't figure out cpu number from whoami register %x", whoami); #endif } - -void -m8820x_cmmu_set_sapr(unsigned cpu, unsigned ap) -{ - CMMU_LOCK; - m8820x_cmmu_set(CMMU_SAPR, ap, 0, cpu, 0, 0); - CMMU_UNLOCK; -} - -void -m8820x_cmmu_set_uapr(unsigned ap) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - m8820x_cmmu_set(CMMU_UAPR, ap, 0, cpu, 0, 0); - CMMU_UNLOCK; - splx(s); -} - -/* - * Functions that invalidate TLB entries. - */ - -/* - * flush any tlb - */ -void -m8820x_cmmu_flush_tlb(unsigned cpu, unsigned kernel, vaddr_t vaddr, - vsize_t size) -{ - int s = splhigh(); - - CMMU_LOCK; - - /* - * Since segment operations are horribly expensive, don't - * do any here. Invalidations of up to three pages are performed - * as page invalidations, otherwise the entire tlb is flushed. - * - * Note that this code relies upon size being a multiple of - * a page and vaddr being page-aligned. - */ - if (size == PAGE_SIZE) { /* most frequent situation */ - m8820x_cmmu_set(CMMU_SAR, vaddr, - ADDR_VAL, cpu, 0, vaddr); - m8820x_cmmu_set(CMMU_SCR, - kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE, - ADDR_VAL, cpu, 0, vaddr); - } else if (size > 3 * PAGE_SIZE) { - m8820x_cmmu_set(CMMU_SCR, - kernel ? CMMU_FLUSH_SUPER_ALL : CMMU_FLUSH_USER_ALL, - 0, cpu, 0, 0); - } else - while (size != 0) { - m8820x_cmmu_set(CMMU_SAR, vaddr, - ADDR_VAL, cpu, 0, vaddr); - m8820x_cmmu_set(CMMU_SCR, - kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE, - ADDR_VAL, cpu, 0, vaddr); - - size -= PAGE_SIZE; - vaddr += PAGE_SIZE; - } - - CMMU_UNLOCK; - splx(s); -} - -/* - * Functions that invalidate caches. - * - * Cache invalidates require physical addresses. Care must be exercised when - * using segment invalidates. This implies that the starting physical address - * plus the segment length should be invalidated. A typical mistake is to - * extract the first physical page of a segment from a virtual address, and - * then expecting to invalidate when the pages are not physically contiguous. - * - * We don't push Instruction Caches prior to invalidate because they are not - * snooped and never modified (I guess it doesn't matter then which form - * of the command we use then). - */ - -/* - * flush both Instruction and Data caches - */ -void -m8820x_cmmu_flush_cache(int cpu, paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0, - cpu, 0, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL, - cpu, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, ADDR_VAL, - cpu, 0, (unsigned)physaddr); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL, - cpu, 0, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, ADDR_VAL, - cpu, 0, (unsigned)physaddr); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, 0, - cpu, 0, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, 0, - cpu, 0, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0, cpu, 0, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -/* - * flush Instruction caches - */ -void -m8820x_cmmu_flush_inst_cache(int cpu, paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_cmmu_flush_data_cache(int cpu, paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL, cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -/* - * sync dcache (and icache too) - */ -void -m8820x_cmmu_sync_cache(paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, INST_CMMU, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_LINE, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_LINE, - MODE_VAL, cpu, DATA_CMMU, 0); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_PAGE, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_PAGE, - MODE_VAL, cpu, DATA_CMMU, 0); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL, - cpu, INST_CMMU, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_cmmu_sync_inval_cache(paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_LINE, - MODE_VAL, cpu, DATA_CMMU, 0); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_PAGE, - MODE_VAL, cpu, DATA_CMMU, 0); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL, - cpu, INST_CMMU, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_cmmu_inval_cache(paddr_t physaddr, psize_t size) -{ - int s = splhigh(); - int cpu = cpu_number(); - - CMMU_LOCK; - -#if !defined(BROKEN_MMU_MASK) - if (size > NBSG) { - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, INST_CMMU, 0); - } else if (size <= MC88200_CACHE_LINE) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_LINE, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_LINE, - MODE_VAL, cpu, DATA_CMMU, 0); - } else if (size <= NBPG) { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_PAGE, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_PAGE, - MODE_VAL, cpu, DATA_CMMU, 0); - } else { - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, INST_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_SEGMENT, - MODE_VAL, cpu, INST_CMMU, 0); - m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, - MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, (unsigned)physaddr); - m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_SEGMENT, - MODE_VAL, cpu, DATA_CMMU, 0); - } -#else - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, DATA_CMMU, 0); - m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL, - cpu, INST_CMMU, 0); -#endif /* !BROKEN_MMU_MASK */ - - m8820x_cmmu_wait(cpu); - - CMMU_UNLOCK; - splx(s); -} - -void -m8820x_dma_cachectl(vaddr_t va, vsize_t size, int op) -{ - paddr_t pa; -#if !defined(BROKEN_MMU_MASK) - psize_t count; - - while (size != 0) { - count = NBPG - (va & PGOFSET); - - if (size < count) - count = size; - - if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) { - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, count); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, count); - break; - default: - m8820x_cmmu_inval_cache(pa, count); - break; - } - } - - va += count; - size -= count; - } -#else - /* XXX This assumes the space is also physically contiguous */ - if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) { - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, size); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, size); - break; - default: - m8820x_cmmu_inval_cache(pa, size); - break; - } - } -#endif /* !BROKEN_MMU_MASK */ -} - -void -m8820x_dma_cachectl_pa(paddr_t pa, psize_t size, int op) -{ -#if !defined(BROKEN_MMU_MASK) - psize_t count; - - while (size != 0) { - count = NBPG - (va & PGOFSET); - - if (size < count) - count = size; - - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, count); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, count); - break; - default: - m8820x_cmmu_inval_cache(pa, count); - break; - } - - pa += count; - size -= count; - } -#else - switch (op) { - case DMA_CACHE_SYNC: - m8820x_cmmu_sync_cache(pa, size); - break; - case DMA_CACHE_SYNC_INVAL: - m8820x_cmmu_sync_inval_cache(pa, size); - break; - default: - m8820x_cmmu_inval_cache(pa, size); - break; - } -#endif /* !BROKEN_MMU_MASK */ -} - -#ifdef DDB -/* - * Show (for debugging) how the current CPU translates the given ADDRESS - * (as DATA). - */ -void -m8820x_cmmu_show_translation(unsigned address, unsigned supervisor_flag, - unsigned verbose_flag, int unused __attribute__ ((unused))) -{ - int cpu = cpu_number(); - vaddr_t va = address; - int cmmu_num; - u_int32_t value; - - /* - * Find the correct data CMMU. - */ - for (cmmu_num = cpu << cmmu_shift; - cmmu_num < (cpu + 1) << cmmu_shift; cmmu_num++) { - if (m8820x_cmmu[cmmu_num].cmmu_type != DATA_CMMU) - continue; - if (m8820x_cmmu[cmmu_num].cmmu_addr_mask == 0 || - (va & m8820x_cmmu[cmmu_num].cmmu_addr_mask) == - m8820x_cmmu[cmmu_num].cmmu_addr) - break; - } - if (cmmu_num == (cpu + 1) << cmmu_shift) { - db_printf("No matching cmmu for VA %08x\n", address); - return; - } - - if (verbose_flag != 0) - db_printf("VA %08x is managed by CMMU#%d.\n", - address, cmmu_num); - - /* - * Perform some sanity checks. - */ - if (verbose_flag == 0) { - if ((m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_SCTR] & - CMMU_SCTR_SE) == 0) - db_printf("WARNING: snooping not enabled for CMMU#%d.\n", - cmmu_num); - } else { - int i; - - for (i = 0; i < max_cmmus; i++) - if (m8820x_cmmu[i].cmmu_type != NO_CMMU && - (verbose_flag > 1 || - (m8820x_cmmu[i].cmmu_regs[CMMU_SCTR] & - CMMU_SCTR_SE) == 0)) { - db_printf("CMMU#%d (cpu %d %s) snooping %s\n", - i, m8820x_cmmu[i].cmmu_cpu, - m8820x_cmmu[i].cmmu_type ? "data" : "inst", - (m8820x_cmmu[i].cmmu_regs[CMMU_SCTR] & - CMMU_SCTR_SE) ? "on":"OFF"); - } - } - - /* - * Ask for a CMMU probe and report its result. - */ - { - volatile unsigned *cmmu_regs = m8820x_cmmu[cmmu_num].cmmu_regs; - u_int32_t ssr; - - cmmu_regs[CMMU_SAR] = address; - cmmu_regs[CMMU_SCR] = - supervisor_flag ? CMMU_PROBE_SUPER : CMMU_PROBE_USER; - ssr = cmmu_regs[CMMU_SSR]; - - switch (verbose_flag) { - case 2: - db_printf("probe of 0x%08x returns ssr=0x%08x\n", - address, ssr); - /* FALLTHROUGH */ - case 1: - if (ssr & CMMU_SSR_V) - db_printf("PROBE of 0x%08x returns phys=0x%x", - address, cmmu_regs[CMMU_SAR]); - else - db_printf("PROBE fault at 0x%x", - cmmu_regs[CMMU_PFAR]); - if (ssr & CMMU_SSR_CE) - db_printf(", copyback err"); - if (ssr & CMMU_SSR_BE) - db_printf(", bus err"); - if (ssr & CACHE_WT) - db_printf(", writethrough"); - if (ssr & CMMU_SSR_SO) - db_printf(", sup prot"); - if (ssr & CACHE_GLOBAL) - db_printf(", global"); - if (ssr & CACHE_INH) - db_printf(", cache inhibit"); - if (ssr & CMMU_SSR_M) - db_printf(", modified"); - if (ssr & CMMU_SSR_U) - db_printf(", used"); - if (ssr & CMMU_SSR_PROT) - db_printf(", write prot"); - if (ssr & CMMU_SSR_BH) - db_printf(", BATC"); - db_printf(".\n"); - break; - } - } - - /* - * Interpret area descriptor. - */ - - if (supervisor_flag) - value = m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_SAPR]; - else - value = m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_UAPR]; - - switch (verbose_flag) { - case 2: - db_printf("CMMU#%d", cmmu_num); - db_printf(" %cAPR is 0x%08x\n", - supervisor_flag ? 'S' : 'U', value); - /* FALLTHROUGH */ - case 1: - db_printf("CMMU#%d", cmmu_num); - db_printf(" %cAPR: SegTbl: 0x%x000p", - supervisor_flag ? 'S' : 'U', PG_PFNUM(value)); - if (value & CACHE_WT) - db_printf(", WTHRU"); - if (value & CACHE_GLOBAL) - db_printf(", GLOBAL"); - if (value & CACHE_INH) - db_printf(", INHIBIT"); - if (value & APR_V) - db_printf(", VALID"); - db_printf("\n"); - break; - } - - if ((value & APR_V) == 0) { - db_printf("VA 0x%08x -> apr 0x%08x not valid\n", va, value); - return; - } - - value &= PG_FRAME; /* now point to seg page */ - - /* - * Walk segment and page tables to find our page. - */ - { - sdt_entry_t sdt; - - if (verbose_flag) - db_printf("will follow to entry %d of page at 0x%x...\n", - SDTIDX(va), value); - value |= SDTIDX(va) * sizeof(sdt_entry_t); - - if (badwordaddr((vaddr_t)value)) { - db_printf("VA 0x%08x -> segment table @0x%08x not accessible\n", - va, value); - return; - } - - sdt = *(sdt_entry_t *)value; - switch (verbose_flag) { - case 2: - db_printf("SEG DESC @0x%x is 0x%08x\n", value, sdt); - /* FALLTHROUGH */ - case 1: - db_printf("SEG DESC @0x%x: PgTbl: 0x%x000", - value, PG_PFNUM(sdt)); - if (sdt & CACHE_WT) - db_printf(", WTHRU"); - if (sdt & SG_SO) - db_printf(", S-PROT"); - if (sdt & CACHE_GLOBAL) - db_printf(", GLOBAL"); - if (sdt & CACHE_INH) - db_printf(", $INHIBIT"); - if (sdt & SG_PROT) - db_printf(", W-PROT"); - if (sdt & SG_V) - db_printf(", VALID"); - db_printf(".\n"); - break; - } - - if ((sdt & SG_V) == 0) { - db_printf("VA 0x%08x -> segment entry 0x%8x @0x%08x not valid\n", - va, sdt, value); - return; - } - - value = ptoa(PG_PFNUM(sdt)); - } - - { - pt_entry_t pte; - - if (verbose_flag) - db_printf("will follow to entry %d of page at 0x%x...\n", - PDTIDX(va), value); - value |= PDTIDX(va) * sizeof(pt_entry_t); - - if (badwordaddr((vaddr_t)value)) { - db_printf("VA 0x%08x -> page table entry @0x%08x not accessible\n", - va, value); - return; - } - - pte = *(pt_entry_t *)value; - switch (verbose_flag) { - case 2: - db_printf("PAGE DESC @0x%x is 0x%08x.\n", value, pte); - /* FALLTHROUGH */ - case 1: - db_printf("PAGE DESC @0x%x: page @%x000", - value, PG_PFNUM(pte)); - if (pte & PG_W) - db_printf(", WIRE"); - if (pte & CACHE_WT) - db_printf(", WTHRU"); - if (pte & PG_SO) - db_printf(", S-PROT"); - if (pte & CACHE_GLOBAL) - db_printf(", GLOBAL"); - if (pte & CACHE_INH) - db_printf(", $INHIBIT"); - if (pte & PG_M) - db_printf(", MOD"); - if (pte & PG_U) - db_printf(", USED"); - if (pte & PG_PROT) - db_printf(", W-PROT"); - if (pte & PG_V) - db_printf(", VALID"); - db_printf(".\n"); - break; - } - - if ((pte & PG_V) == 0) { - db_printf("VA 0x%08x -> page table entry 0x%08x @0x%08x not valid\n", - va, pte, value); - return; - } - - value = ptoa(PG_PFNUM(pte)) | (va & PAGE_MASK); - } - - db_printf("VA 0x%08x -> PA 0x%08x\n", va, value); -} -#endif /* DDB */ |