#include #include #include #include #include #include #include #include #include #include #include #include #define UNLOCK_ALL 0x00000000 /* allocation in any way */ #define LOCK_ALL (~UNLOCK_ALL) #define MAX_NR_WAYS 16 u32 nr_unlocked_way[MAX_NR_WAYS+1] = { 0xFFFFFFFF, /* all ways are locked. usable = 0*/ 0xFFFFFFFE, /* way ~0 unlocked. usable = 1 */ 0xFFFFFFFC, 0xFFFFFFF8, 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, 0xFFFF0000, /* way ~15 unlocked. usable = 16 */ }; static void __iomem *cache_base; static void __iomem *lockreg_d; static void __iomem *lockreg_i; static u32 cache_id; struct mutex actlr_mutex; struct mutex l2x0_prefetch_mutex; struct mutex lockdown_proc; static int min_usable_ways = 0; static int max_usable_ways = 16; static int zero = 0; static int one = 1; #define ld_d_reg(cpu) ({ int __cpu = cpu; \ void __iomem *__v = cache_base + L2X0_LOCKDOWN_WAY_D_BASE + \ __cpu * L2X0_LOCKDOWN_STRIDE; __v; }) #define ld_i_reg(cpu) ({ int __cpu = cpu; \ void __iomem *__v = cache_base + L2X0_LOCKDOWN_WAY_I_BASE + \ __cpu * L2X0_LOCKDOWN_STRIDE; __v; }) int l2_usable_ways; int lock_all; int nr_lockregs; static void print_lockdown_registers(void) { int i; for (i = 0; i < nr_lockregs; i++) { printk("Lockdown Data CPU %2d: 0x%8x\n", i, readl_relaxed(ld_d_reg(i))); printk("Lockdown Inst CPU %2d: 0x%8x\n", i, readl_relaxed(ld_i_reg(i))); } } static void test_lockdown(void *ignore) { int i; printk("Start lockdown test on CPU %d.\n", smp_processor_id()); for (i = 0; i < nr_lockregs; i++) { printk("CPU %2d data reg: 0x%8p\n", i, ld_d_reg(i)); printk("CPU %2d inst reg: 0x%8p\n", i, ld_i_reg(i)); } printk("Lockdown initial state:\n"); print_lockdown_registers(); printk("---\n"); for (i = 0; i < nr_lockregs; i++) { writel_relaxed(1, ld_d_reg(i)); writel_relaxed(2, ld_i_reg(i)); } printk("Lockdown all data=1 instr=2:\n"); print_lockdown_registers(); printk("---\n"); for (i = 0; i < nr_lockregs; i++) { writel_relaxed((1 << i), ld_d_reg(i)); writel_relaxed(((1 << 8) >> i), ld_i_reg(i)); } printk("Lockdown varies:\n"); print_lockdown_registers(); printk("---\n"); for (i = 0; i < nr_lockregs; i++) { writel_relaxed(UNLOCK_ALL, ld_d_reg(i)); writel_relaxed(UNLOCK_ALL, ld_i_reg(i)); } printk("Lockdown all zero:\n"); print_lockdown_registers(); printk("End lockdown test.\n"); } void litmus_setup_lockdown(void __iomem *base, u32 id) { cache_base = base; cache_id = id; lockreg_d = cache_base + L2X0_LOCKDOWN_WAY_D_BASE; lockreg_i = cache_base + L2X0_LOCKDOWN_WAY_I_BASE; if (L2X0_CACHE_ID_PART_L310 == (cache_id & L2X0_CACHE_ID_PART_MASK)) { nr_lockregs = 8; } else { printk("Unknown cache ID!\n"); nr_lockregs = 1; } mutex_init(&actlr_mutex); mutex_init(&l2x0_prefetch_mutex); mutex_init(&lockdown_proc); test_lockdown(NULL); } int lock_all_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int ret = 0, i; mutex_lock(&lockdown_proc); flush_cache_all(); ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); if (ret) goto out; if (write && lock_all == 1) { for (i = 0; i < nr_lockregs; i++) { writel_relaxed(nr_unlocked_way[0], ld_d_reg(i)); writel_relaxed(nr_unlocked_way[0], ld_i_reg(i)); } print_lockdown_registers(); } out: mutex_unlock(&lockdown_proc); return ret; } int l2_usable_ways_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int ret = 0, i = 0; mutex_lock(&lockdown_proc); flush_cache_all(); ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); if (ret) goto out; TRACE_CUR("l2_usable_ways : %d\n", l2_usable_ways); if (write) { //for (i = 0; i < nr_lockregs; i++) { writel_relaxed(nr_unlocked_way[l2_usable_ways], ld_d_reg(i)); writel_relaxed(nr_unlocked_way[l2_usable_ways], ld_i_reg(i)); //} print_lockdown_registers(); } out: mutex_unlock(&lockdown_proc); return ret; } static struct ctl_table cache_table[] = { { .procname = "l2_usable_ways", .mode = 0666, .proc_handler = l2_usable_ways_handler, .data = &l2_usable_ways, .maxlen = sizeof(l2_usable_ways), .extra1 = &min_usable_ways, .extra2 = &max_usable_ways, }, { .procname = "lock_all", .mode = 0666, .proc_handler = lock_all_handler, .data = &lock_all, .maxlen = sizeof(lock_all), .extra1 = &zero, .extra2 = &one, }, { } }; static struct ctl_table litmus_dir_table[] = { { .procname = "litmus", .mode = 0555, .child = cache_table, }, { } }; static struct ctl_table_header *litmus_sysctls; static int __init litmus_sysctl_init(void) { int ret = 0; printk(KERN_INFO "Registering LITMUS^RT proc sysctl.\n"); litmus_sysctls = register_sysctl_table(litmus_dir_table); if (!litmus_sysctls) { printk(KERN_WARNING "Could not register LITMUS^RT sysctl.\n"); ret = -EFAULT; goto out; } l2_usable_ways = 16; out: return ret; } module_init(litmus_sysctl_init);