cregit-Linux how code gets into the kernel

Release 4.14 arch/blackfin/kernel/cplb-mpu/cplbmgr.c

/*
 * Blackfin CPLB exception handling for when MPU in on
 *
 * Copyright 2008-2009 Analog Devices Inc.
 *
 * Licensed under the GPL-2 or later.
 */

#include <linux/module.h>
#include <linux/mm.h>

#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/cplb.h>
#include <asm/cplbinit.h>
#include <asm/mmu_context.h>

/*
 * 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[NR_CPUS];



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];

#ifdef CONFIG_EXCPT_IRQ_SYSC_L1

#define MGR_ATTR __attribute__((l1_text))
#else

#define MGR_ATTR
#endif

/*
 * Given the contents of the status register, return the index of the
 * CPLB that caused the fault.
 */

static inline int faulting_cplb_index(int status) { int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF); return 30 - signbits; }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt25100.00%1100.00%
Total25100.00%1100.00%

/* * Given the contents of the status register and the DCPLB_DATA contents, * return true if a write access should be permitted. */
static inline int write_permitted(int status, unsigned long data) { if (status & FAULT_USERSUPV) return !!(data & CPLB_SUPV_WR); else return !!(data & CPLB_USER_WR); }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt39100.00%1100.00%
Total39100.00%1100.00%

/* Counters to implement round-robin replacement. */ static int icplb_rr_index[NR_CPUS], dcplb_rr_index[NR_CPUS]; /* * Find an ICPLB entry to be evicted and return its index. */
MGR_ATTR static int evict_one_icplb(unsigned int cpu) { int i; for (i = first_switched_icplb; i < MAX_CPLBS; i++) if ((icplb_tbl[cpu][i].data & CPLB_VALID) == 0) return i; i = first_switched_icplb + icplb_rr_index[cpu]; if (i >= MAX_CPLBS) { i -= MAX_CPLBS - first_switched_icplb; icplb_rr_index[cpu] -= MAX_CPLBS - first_switched_icplb; } icplb_rr_index[cpu]++; return i; }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt7382.02%133.33%
Graf Yang1516.85%133.33%
Barry Song11.12%133.33%
Total89100.00%3100.00%


MGR_ATTR static int evict_one_dcplb(unsigned int cpu) { int i; for (i = first_switched_dcplb; i < MAX_CPLBS; i++) if ((dcplb_tbl[cpu][i].data & CPLB_VALID) == 0) return i; i = first_switched_dcplb + dcplb_rr_index[cpu]; if (i >= MAX_CPLBS) { i -= MAX_CPLBS - first_switched_dcplb; dcplb_rr_index[cpu] -= MAX_CPLBS - first_switched_dcplb; } dcplb_rr_index[cpu]++; return i; }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt7382.02%133.33%
Graf Yang1516.85%133.33%
Barry Song11.12%133.33%
Total89100.00%3100.00%


MGR_ATTR static noinline int dcplb_miss(unsigned int cpu) { unsigned long addr = bfin_read_DCPLB_FAULT_ADDR(); int status = bfin_read_DCPLB_STATUS(); unsigned long *mask; int idx; unsigned long d_data; nr_dcplb_miss[cpu]++; d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_EXTMEM_DCACHEABLE if (bfin_addr_dcacheable(addr)) { d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; # ifdef CONFIG_BFIN_EXTMEM_WRITETHROUGH d_data |= CPLB_L1_AOW | CPLB_WT; # endif } #endif if (L2_LENGTH && addr >= L2_START && addr < L2_START + L2_LENGTH) { addr = L2_START; d_data = L2_DMEMORY; } else if (addr >= physical_mem_end) { if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { #if defined(CONFIG_ROMFS_ON_MTD) && defined(CONFIG_MTD_ROM) mask = current_rwx_mask[cpu]; if (mask) { int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT; int idx = page >> 5; int bit = 1 << (page & 31); if (mask[idx] & bit) d_data |= CPLB_USER_RD; } #endif } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) { addr &= ~(1 * 1024 * 1024 - 1); d_data &= ~PAGE_SIZE_4KB; d_data |= PAGE_SIZE_1MB; } else return CPLB_PROT_VIOL; } else if (addr >= _ramend) { d_data |= CPLB_USER_RD | CPLB_USER_WR; if (reserved_mem_dcache_on) d_data |= CPLB_L1_CHBL; } else { mask = current_rwx_mask[cpu]; if (mask) { int page = addr >> PAGE_SHIFT; int idx = page >> 5; int bit = 1 << (page & 31); if (mask[idx] & bit) d_data |= CPLB_USER_RD; mask += page_mask_nelts; if (mask[idx] & bit) d_data |= CPLB_USER_WR; } } idx = evict_one_dcplb(cpu); addr &= PAGE_MASK; dcplb_tbl[cpu][idx].addr = addr; dcplb_tbl[cpu][idx].data = d_data; _disable_dcplb(); bfin_write32(DCPLB_DATA0 + idx * 4, d_data); bfin_write32(DCPLB_ADDR0 + idx * 4, addr); _enable_dcplb(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt23456.25%321.43%
Barry Song7217.31%428.57%
Mike Frysinger5112.26%214.29%
Jie Zhang286.73%214.29%
Graf Yang215.05%17.14%
Sonic Zhang81.92%17.14%
Yi Li20.48%17.14%
Total416100.00%14100.00%


MGR_ATTR 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[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[cpu]++; /* * First, try to find a CPLB that matches this address. If we * find one, then the fact that we're in the miss handler means * that the instruction crosses a page boundary. */ for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) { 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; } } } i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_EXTMEM_ICACHEABLE /* * Normal RAM, and possibly the reserved memory area, are * cacheable. */ if (addr < _ramend || (addr < physical_mem_end && reserved_mem_icache_on)) i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; #endif if (L2_LENGTH && addr >= L2_START && addr < L2_START + L2_LENGTH) { addr = L2_START; i_data = L2_IMEMORY; } else if (addr >= physical_mem_end) { if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { if (!(status & FAULT_USERSUPV)) { unsigned long *mask = current_rwx_mask[cpu]; if (mask) { int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT; int idx = page >> 5; int bit = 1 << (page & 31); mask += 2 * page_mask_nelts; if (mask[idx] & bit) i_data |= CPLB_USER_RD; } } } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH && (status & FAULT_USERSUPV)) { addr &= ~(1 * 1024 * 1024 - 1); i_data &= ~PAGE_SIZE_4KB; i_data |= PAGE_SIZE_1MB; } else return CPLB_PROT_VIOL; } else if (addr >= _ramend) { i_data |= CPLB_USER_RD; if (reserved_mem_icache_on) i_data |= CPLB_L1_CHBL; } else { /* * Two cases to distinguish - a supervisor access must * necessarily be for a module page; we grant it * unconditionally (could do better here in the future). * Otherwise, check the x bitmap of the current process. */ if (!(status & FAULT_USERSUPV)) { unsigned long *mask = current_rwx_mask[cpu]; if (mask) { int page = addr >> PAGE_SHIFT; int idx = page >> 5; int bit = 1 << (page & 31); mask += 2 * page_mask_nelts; if (mask[idx] & bit) i_data |= CPLB_USER_RD; } } } idx = evict_one_icplb(cpu); addr &= PAGE_MASK; icplb_tbl[cpu][idx].addr = addr; icplb_tbl[cpu][idx].data = i_data; _disable_icplb(); bfin_write32(ICPLB_DATA0 + idx * 4, i_data); bfin_write32(ICPLB_ADDR0 + idx * 4, addr); _enable_icplb(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt29759.40%220.00%
Barry Song9519.00%330.00%
Mike Frysinger438.60%110.00%
Graf Yang295.80%110.00%
Jie Zhang265.20%110.00%
Sonic Zhang81.60%110.00%
Yi Li20.40%110.00%
Total500100.00%10100.00%


MGR_ATTR static noinline int dcplb_protection_fault(unsigned int cpu) { int status = bfin_read_DCPLB_STATUS(); nr_dcplb_prot[cpu]++; if (status & FAULT_RW) { int idx = faulting_cplb_index(status); unsigned long data = dcplb_tbl[cpu][idx].data; if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) && write_permitted(status, data)) { data |= CPLB_DIRTY; dcplb_tbl[cpu][idx].data = data; bfin_write32(DCPLB_DATA0 + idx * 4, data); return 0; } } return CPLB_PROT_VIOL; }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt9988.39%133.33%
Graf Yang1210.71%133.33%
Barry Song10.89%133.33%
Total112100.00%3100.00%


MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs) { int cause = seqstat & 0x3f; unsigned int cpu = raw_smp_processor_id(); switch (cause) { case 0x23: return dcplb_protection_fault(cpu); case 0x2C: return icplb_miss(cpu); case 0x26: return dcplb_miss(cpu); default: return 1; } }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt4873.85%125.00%
Graf Yang1523.08%125.00%
Yi Li11.54%125.00%
Barry Song11.54%125.00%
Total65100.00%4100.00%


void flush_switched_cplbs(unsigned int cpu) { int i; unsigned long flags; nr_cplb_flush[cpu]++; flags = hard_local_irq_save(); _disable_icplb(); for (i = first_switched_icplb; i < MAX_CPLBS; i++) { 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[cpu][i].data = 0; bfin_write32(DCPLB_DATA0 + i * 4, 0); } _enable_dcplb(); hard_local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt10083.33%350.00%
Graf Yang1210.00%116.67%
David Howells43.33%116.67%
Yi Li43.33%116.67%
Total120100.00%6100.00%


void set_mask_dcplbs(unsigned long *masks, unsigned int cpu) { int i; unsigned long addr = (unsigned long)masks; unsigned long d_data; unsigned long flags; if (!masks) { current_rwx_mask[cpu] = masks; return; } flags = hard_local_irq_save(); current_rwx_mask[cpu] = masks; if (L2_LENGTH && addr >= L2_START && addr < L2_START + L2_LENGTH) { addr = L2_START; d_data = L2_DMEMORY; } else { d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_EXTMEM_DCACHEABLE d_data |= CPLB_L1_CHBL; # ifdef CONFIG_BFIN_EXTMEM_WRITETHROUGH d_data |= CPLB_L1_AOW | CPLB_WT; # endif #endif } _disable_dcplb(); for (i = first_mask_dcplb; i < first_switched_dcplb; i++) { 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(); hard_local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt14473.85%233.33%
Jie Zhang2914.87%116.67%
Graf Yang168.21%116.67%
David Howells42.05%116.67%
Yi Li21.03%116.67%
Total195100.00%6100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Bernd Schmidt118067.62%628.57%
Barry Song18510.60%419.05%
Graf Yang1619.23%14.76%
Mike Frysinger975.56%314.29%
Jie Zhang834.76%29.52%
Sonic Zhang160.92%14.76%
Yi Li140.80%29.52%
David Howells80.46%14.76%
Robin Getz10.06%14.76%
Total1745100.00%21100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.