diff options
Diffstat (limited to 'arch/blackfin/kernel/cplb-mpu')
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/Makefile | 6 | ||||
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/cacheinit.c | 4 | ||||
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/cplbinfo.c | 136 | ||||
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/cplbinit.c | 48 | ||||
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 119 |
5 files changed, 96 insertions, 217 deletions
diff --git a/arch/blackfin/kernel/cplb-mpu/Makefile b/arch/blackfin/kernel/cplb-mpu/Makefile index 286b69357f97..7d70d3bf3212 100644 --- a/arch/blackfin/kernel/cplb-mpu/Makefile +++ b/arch/blackfin/kernel/cplb-mpu/Makefile @@ -4,5 +4,7 @@ obj-y := cplbinit.o cacheinit.o cplbmgr.o -obj-$(CONFIG_CPLB_INFO) += cplbinfo.o - +CFLAGS_cplbmgr.o := -ffixed-I0 -ffixed-I1 -ffixed-I2 -ffixed-I3 \ + -ffixed-L0 -ffixed-L1 -ffixed-L2 -ffixed-L3 \ + -ffixed-M0 -ffixed-M1 -ffixed-M2 -ffixed-M3 \ + -ffixed-B0 -ffixed-B1 -ffixed-B2 -ffixed-B3 diff --git a/arch/blackfin/kernel/cplb-mpu/cacheinit.c b/arch/blackfin/kernel/cplb-mpu/cacheinit.c index a8b712a24c59..c6ff947f9d37 100644 --- a/arch/blackfin/kernel/cplb-mpu/cacheinit.c +++ b/arch/blackfin/kernel/cplb-mpu/cacheinit.c @@ -25,7 +25,7 @@ #include <asm/cplbinit.h> #if defined(CONFIG_BFIN_ICACHE) -void __init bfin_icache_init(void) +void __cpuinit bfin_icache_init(struct cplb_entry *icplb_tbl) { unsigned long ctrl; int i; @@ -43,7 +43,7 @@ void __init bfin_icache_init(void) #endif #if defined(CONFIG_BFIN_DCACHE) -void __init bfin_dcache_init(void) +void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl) { unsigned long ctrl; int i; diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c deleted file mode 100644 index 822beefa3a4b..000000000000 --- a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * File: arch/blackfin/mach-common/cplbinfo.c - * Based on: - * Author: Sonic Zhang <sonic.zhang@analog.com> - * - * Created: Jan. 2005 - * Description: Display CPLB status - * - * Modified: - * Copyright 2004-2006 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/uaccess.h> - -#include <asm/current.h> -#include <asm/system.h> -#include <asm/cplb.h> -#include <asm/cplbinit.h> -#include <asm/blackfin.h> - -static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" }; - -static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched) -{ - int i; - buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n"); - for (i = 0; i < MAX_CPLBS; i++) { - unsigned long data = tbl[i].data; - unsigned long addr = tbl[i].addr; - if (!(data & CPLB_VALID)) - continue; - - buf += - sprintf(buf, - "%d\t0x%08lx\t%06lx\t%s\t%c\t%c\t%c\t%c\n", - i, addr, data, - page_size_string_table[(data & 0x30000) >> 16], - (data & CPLB_USER_RD) ? 'Y' : 'N', - (data & CPLB_USER_WR) ? 'Y' : 'N', - (data & CPLB_SUPV_WR) ? 'Y' : 'N', - i < switched ? 'N' : 'Y'); - } - buf += sprintf(buf, "\n"); - - return buf; -} - -int cplbinfo_proc_output(char *buf) -{ - char *p; - - p = buf; - - p += sprintf(p, "------------------ CPLB Information ------------------\n\n"); - - if (bfin_read_IMEM_CONTROL() & ENICPLB) { - p += sprintf(p, "Instruction CPLB entry:\n"); - p = cplb_print_entry(p, icplb_tbl, first_switched_icplb); - } else - p += sprintf(p, "Instruction CPLB is disabled.\n\n"); - - if (1 || bfin_read_DMEM_CONTROL() & ENDCPLB) { - p += sprintf(p, "Data CPLB entry:\n"); - p = cplb_print_entry(p, dcplb_tbl, first_switched_dcplb); - } else - p += sprintf(p, "Data CPLB is disabled.\n"); - - p += sprintf(p, "ICPLB miss: %d\nICPLB supervisor miss: %d\n", - nr_icplb_miss, nr_icplb_supv_miss); - p += sprintf(p, "DCPLB miss: %d\nDCPLB protection fault:%d\n", - nr_dcplb_miss, nr_dcplb_prot); - p += sprintf(p, "CPLB flushes: %d\n", - nr_cplb_flush); - - return p - buf; -} - -static int cplbinfo_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len; - - len = cplbinfo_proc_output(page); - if (len <= off + count) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; -} - -static int __init cplbinfo_init(void) -{ - struct proc_dir_entry *entry; - - entry = create_proc_entry("cplbinfo", 0, NULL); - if (!entry) - return -ENOMEM; - - entry->read_proc = cplbinfo_read_proc; - entry->data = NULL; - - return 0; -} - -static void __exit cplbinfo_exit(void) -{ - remove_proc_entry("cplbinfo", NULL); -} - -module_init(cplbinfo_init); -module_exit(cplbinfo_exit); diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c index 55af729f8495..bdb958486e76 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c @@ -25,18 +25,19 @@ #include <asm/blackfin.h> #include <asm/cplb.h> #include <asm/cplbinit.h> +#include <asm/mem_map.h> #if ANOMALY_05000263 # error the MPU will not function safely while Anomaly 05000263 applies #endif -struct cplb_entry icplb_tbl[MAX_CPLBS]; -struct cplb_entry dcplb_tbl[MAX_CPLBS]; +struct cplb_entry icplb_tbl[NR_CPUS][MAX_CPLBS]; +struct cplb_entry dcplb_tbl[NR_CPUS][MAX_CPLBS]; int first_switched_icplb, first_switched_dcplb; int first_mask_dcplb; -void __init generate_cplb_tables(void) +void __init generate_cplb_tables_cpu(unsigned int cpu) { int i_d, i_i; unsigned long addr; @@ -55,15 +56,16 @@ void __init generate_cplb_tables(void) d_cache |= CPLB_L1_AOW | CPLB_WT; #endif #endif + i_d = i_i = 0; /* Set up the zero page. */ - dcplb_tbl[i_d].addr = 0; - dcplb_tbl[i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB; + dcplb_tbl[cpu][i_d].addr = 0; + dcplb_tbl[cpu][i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB; #if 0 - icplb_tbl[i_i].addr = 0; - icplb_tbl[i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB; + icplb_tbl[cpu][i_i].addr = 0; + icplb_tbl[cpu][i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB; #endif /* Cover kernel memory with 4M pages. */ @@ -72,28 +74,28 @@ void __init generate_cplb_tables(void) i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB; for (; addr < memory_start; addr += 4 * 1024 * 1024) { - dcplb_tbl[i_d].addr = addr; - dcplb_tbl[i_d++].data = d_data; - icplb_tbl[i_i].addr = addr; - icplb_tbl[i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0); + dcplb_tbl[cpu][i_d].addr = addr; + dcplb_tbl[cpu][i_d++].data = d_data; + icplb_tbl[cpu][i_i].addr = addr; + icplb_tbl[cpu][i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0); } /* Cover L1 memory. One 4M area for code and data each is enough. */ #if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0 - dcplb_tbl[i_d].addr = L1_DATA_A_START; - dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB; + dcplb_tbl[cpu][i_d].addr = get_l1_data_a_start_cpu(cpu); + dcplb_tbl[cpu][i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB; #endif #if L1_CODE_LENGTH > 0 - icplb_tbl[i_i].addr = L1_CODE_START; - icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB; + icplb_tbl[cpu][i_i].addr = get_l1_code_start_cpu(cpu); + icplb_tbl[cpu][i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB; #endif /* Cover L2 memory */ #if L2_LENGTH > 0 - dcplb_tbl[i_d].addr = L2_START; - dcplb_tbl[i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB; - icplb_tbl[i_i].addr = L2_START; - icplb_tbl[i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB; + dcplb_tbl[cpu][i_d].addr = L2_START; + dcplb_tbl[cpu][i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB; + icplb_tbl[cpu][i_i].addr = L2_START; + icplb_tbl[cpu][i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB; #endif first_mask_dcplb = i_d; @@ -101,7 +103,11 @@ void __init generate_cplb_tables(void) first_switched_icplb = i_i; while (i_d < MAX_CPLBS) - dcplb_tbl[i_d++].data = 0; + dcplb_tbl[cpu][i_d++].data = 0; while (i_i < MAX_CPLBS) - icplb_tbl[i_i++].data = 0; + icplb_tbl[cpu][i_i++].data = 0; +} + +void generate_cplb_tables_all(void) +{ } diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index baa52e261f0d..87463ce87f5a 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -25,15 +25,21 @@ #include <asm/cplbinit.h> #include <asm/mmu_context.h> -#define FAULT_RW (1 << 16) -#define FAULT_USERSUPV (1 << 17) +/* + * WARNING + * + * This file is compiled with certain -ffixed-reg options. We have to + * make sure not to call any functions here that could clobber these + * registers. + */ int page_mask_nelts; int page_mask_order; -unsigned long *current_rwx_mask; +unsigned long *current_rwx_mask[NR_CPUS]; -int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot; -int nr_cplb_flush; +int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS]; +int nr_icplb_supv_miss[NR_CPUS], nr_dcplb_prot[NR_CPUS]; +int nr_cplb_flush[NR_CPUS]; static inline void disable_dcplb(void) { @@ -98,42 +104,42 @@ static inline int write_permitted(int status, unsigned long data) } /* Counters to implement round-robin replacement. */ -static int icplb_rr_index, dcplb_rr_index; +static int icplb_rr_index[NR_CPUS], dcplb_rr_index[NR_CPUS]; /* * Find an ICPLB entry to be evicted and return its index. */ -static int evict_one_icplb(void) +static int evict_one_icplb(unsigned int cpu) { int i; for (i = first_switched_icplb; i < MAX_CPLBS; i++) - if ((icplb_tbl[i].data & CPLB_VALID) == 0) + if ((icplb_tbl[cpu][i].data & CPLB_VALID) == 0) return i; - i = first_switched_icplb + icplb_rr_index; + i = first_switched_icplb + icplb_rr_index[cpu]; if (i >= MAX_CPLBS) { i -= MAX_CPLBS - first_switched_icplb; - icplb_rr_index -= MAX_CPLBS - first_switched_icplb; + icplb_rr_index[cpu] -= MAX_CPLBS - first_switched_icplb; } - icplb_rr_index++; + icplb_rr_index[cpu]++; return i; } -static int evict_one_dcplb(void) +static int evict_one_dcplb(unsigned int cpu) { int i; for (i = first_switched_dcplb; i < MAX_CPLBS; i++) - if ((dcplb_tbl[i].data & CPLB_VALID) == 0) + if ((dcplb_tbl[cpu][i].data & CPLB_VALID) == 0) return i; - i = first_switched_dcplb + dcplb_rr_index; + i = first_switched_dcplb + dcplb_rr_index[cpu]; if (i >= MAX_CPLBS) { i -= MAX_CPLBS - first_switched_dcplb; - dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb; + dcplb_rr_index[cpu] -= MAX_CPLBS - first_switched_dcplb; } - dcplb_rr_index++; + dcplb_rr_index[cpu]++; return i; } -static noinline int dcplb_miss(void) +static noinline int dcplb_miss(unsigned int cpu) { unsigned long addr = bfin_read_DCPLB_FAULT_ADDR(); int status = bfin_read_DCPLB_STATUS(); @@ -141,7 +147,7 @@ static noinline int dcplb_miss(void) int idx; unsigned long d_data; - nr_dcplb_miss++; + nr_dcplb_miss[cpu]++; d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_DCACHE @@ -168,25 +174,25 @@ static noinline int dcplb_miss(void) } else if (addr >= _ramend) { d_data |= CPLB_USER_RD | CPLB_USER_WR; } else { - mask = current_rwx_mask; + mask = current_rwx_mask[cpu]; if (mask) { int page = addr >> PAGE_SHIFT; - int offs = page >> 5; + int idx = page >> 5; int bit = 1 << (page & 31); - if (mask[offs] & bit) + if (mask[idx] & bit) d_data |= CPLB_USER_RD; mask += page_mask_nelts; - if (mask[offs] & bit) + if (mask[idx] & bit) d_data |= CPLB_USER_WR; } } - idx = evict_one_dcplb(); + idx = evict_one_dcplb(cpu); addr &= PAGE_MASK; - dcplb_tbl[idx].addr = addr; - dcplb_tbl[idx].data = d_data; + dcplb_tbl[cpu][idx].addr = addr; + dcplb_tbl[cpu][idx].data = d_data; disable_dcplb(); bfin_write32(DCPLB_DATA0 + idx * 4, d_data); @@ -196,21 +202,21 @@ static noinline int dcplb_miss(void) return 0; } -static noinline int icplb_miss(void) +static noinline int icplb_miss(unsigned int cpu) { unsigned long addr = bfin_read_ICPLB_FAULT_ADDR(); int status = bfin_read_ICPLB_STATUS(); int idx; unsigned long i_data; - nr_icplb_miss++; + nr_icplb_miss[cpu]++; /* If inside the uncached DMA region, fault. */ if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend) return CPLB_PROT_VIOL; if (status & FAULT_USERSUPV) - nr_icplb_supv_miss++; + nr_icplb_supv_miss[cpu]++; /* * First, try to find a CPLB that matches this address. If we @@ -218,8 +224,8 @@ static noinline int icplb_miss(void) * that the instruction crosses a page boundary. */ for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) { - if (icplb_tbl[idx].data & CPLB_VALID) { - unsigned long this_addr = icplb_tbl[idx].addr; + if (icplb_tbl[cpu][idx].data & CPLB_VALID) { + unsigned long this_addr = icplb_tbl[cpu][idx].addr; if (this_addr <= addr && this_addr + PAGE_SIZE > addr) { addr += PAGE_SIZE; break; @@ -257,23 +263,23 @@ static noinline int icplb_miss(void) * Otherwise, check the x bitmap of the current process. */ if (!(status & FAULT_USERSUPV)) { - unsigned long *mask = current_rwx_mask; + unsigned long *mask = current_rwx_mask[cpu]; if (mask) { int page = addr >> PAGE_SHIFT; - int offs = page >> 5; + int idx = page >> 5; int bit = 1 << (page & 31); mask += 2 * page_mask_nelts; - if (mask[offs] & bit) + if (mask[idx] & bit) i_data |= CPLB_USER_RD; } } } - idx = evict_one_icplb(); + idx = evict_one_icplb(cpu); addr &= PAGE_MASK; - icplb_tbl[idx].addr = addr; - icplb_tbl[idx].data = i_data; + icplb_tbl[cpu][idx].addr = addr; + icplb_tbl[cpu][idx].data = i_data; disable_icplb(); bfin_write32(ICPLB_DATA0 + idx * 4, i_data); @@ -283,19 +289,19 @@ static noinline int icplb_miss(void) return 0; } -static noinline int dcplb_protection_fault(void) +static noinline int dcplb_protection_fault(unsigned int cpu) { int status = bfin_read_DCPLB_STATUS(); - nr_dcplb_prot++; + nr_dcplb_prot[cpu]++; if (status & FAULT_RW) { int idx = faulting_cplb_index(status); - unsigned long data = dcplb_tbl[idx].data; + unsigned long data = dcplb_tbl[cpu][idx].data; if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) && write_permitted(status, data)) { data |= CPLB_DIRTY; - dcplb_tbl[idx].data = data; + dcplb_tbl[cpu][idx].data = data; bfin_write32(DCPLB_DATA0 + idx * 4, data); return 0; } @@ -306,44 +312,45 @@ static noinline int dcplb_protection_fault(void) int cplb_hdr(int seqstat, struct pt_regs *regs) { int cause = seqstat & 0x3f; + unsigned int cpu = smp_processor_id(); switch (cause) { case 0x23: - return dcplb_protection_fault(); + return dcplb_protection_fault(cpu); case 0x2C: - return icplb_miss(); + return icplb_miss(cpu); case 0x26: - return dcplb_miss(); + return dcplb_miss(cpu); default: return 1; } } -void flush_switched_cplbs(void) +void flush_switched_cplbs(unsigned int cpu) { int i; unsigned long flags; - nr_cplb_flush++; + nr_cplb_flush[cpu]++; - local_irq_save(flags); + local_irq_save_hw(flags); disable_icplb(); for (i = first_switched_icplb; i < MAX_CPLBS; i++) { - icplb_tbl[i].data = 0; + icplb_tbl[cpu][i].data = 0; bfin_write32(ICPLB_DATA0 + i * 4, 0); } enable_icplb(); disable_dcplb(); for (i = first_switched_dcplb; i < MAX_CPLBS; i++) { - dcplb_tbl[i].data = 0; + dcplb_tbl[cpu][i].data = 0; bfin_write32(DCPLB_DATA0 + i * 4, 0); } enable_dcplb(); - local_irq_restore(flags); + local_irq_restore_hw(flags); } -void set_mask_dcplbs(unsigned long *masks) +void set_mask_dcplbs(unsigned long *masks, unsigned int cpu) { int i; unsigned long addr = (unsigned long)masks; @@ -351,12 +358,12 @@ void set_mask_dcplbs(unsigned long *masks) unsigned long flags; if (!masks) { - current_rwx_mask = masks; + current_rwx_mask[cpu] = masks; return; } - local_irq_save(flags); - current_rwx_mask = masks; + local_irq_save_hw(flags); + current_rwx_mask[cpu] = masks; d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_DCACHE @@ -368,12 +375,12 @@ void set_mask_dcplbs(unsigned long *masks) disable_dcplb(); for (i = first_mask_dcplb; i < first_switched_dcplb; i++) { - dcplb_tbl[i].addr = addr; - dcplb_tbl[i].data = d_data; + dcplb_tbl[cpu][i].addr = addr; + dcplb_tbl[cpu][i].data = d_data; bfin_write32(DCPLB_DATA0 + i * 4, d_data); bfin_write32(DCPLB_ADDR0 + i * 4, addr); addr += PAGE_SIZE; } enable_dcplb(); - local_irq_restore(flags); + local_irq_restore_hw(flags); } |