diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/atags_parse.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 48 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 5 | ||||
-rw-r--r-- | arch/arm/kernel/entry-ftrace.S | 100 | ||||
-rw-r--r-- | arch/arm/kernel/ftrace.c | 37 | ||||
-rw-r--r-- | arch/arm/kernel/machine_kexec.c | 11 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_v6.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 16 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 78 | ||||
-rw-r--r-- | arch/arm/kernel/topology.c | 221 | ||||
-rw-r--r-- | arch/arm/kernel/vdso.c | 18 |
12 files changed, 278 insertions, 264 deletions
diff --git a/arch/arm/kernel/atags_parse.c b/arch/arm/kernel/atags_parse.c index 68c6ae0b9e4c..98fbfd235ac8 100644 --- a/arch/arm/kernel/atags_parse.c +++ b/arch/arm/kernel/atags_parse.c @@ -18,6 +18,7 @@ */ #include <linux/init.h> +#include <linux/initrd.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/root_dev.h> @@ -91,8 +92,6 @@ __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); #ifdef CONFIG_BLK_DEV_RAM static int __init parse_tag_ramdisk(const struct tag *tag) { - extern int rd_size, rd_image_start, rd_prompt, rd_doload; - rd_image_start = tag->u.ramdisk.start; rd_doload = (tag->u.ramdisk.flags & 1) == 0; rd_prompt = (tag->u.ramdisk.flags & 2) == 0; diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index b259956365a0..c1809fb549dd 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -458,10 +458,14 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, int nr, busnr; for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { - sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL); - if (WARN(!sys, "PCI: unable to allocate sys data!")) + struct pci_host_bridge *bridge; + + bridge = pci_alloc_host_bridge(sizeof(struct pci_sys_data)); + if (WARN(!bridge, "PCI: unable to allocate bridge!")) break; + sys = pci_host_bridge_priv(bridge); + sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; @@ -473,34 +477,44 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, ret = hw->setup(nr, sys); if (ret > 0) { - struct pci_host_bridge *host_bridge; ret = pcibios_init_resource(nr, sys, hw->io_optional); if (ret) { - kfree(sys); + pci_free_host_bridge(bridge); break; } + bridge->map_irq = pcibios_map_irq; + bridge->swizzle_irq = pcibios_swizzle; + if (hw->scan) - sys->bus = hw->scan(nr, sys); - else - sys->bus = pci_scan_root_bus_msi(parent, - sys->busnr, hw->ops, sys, - &sys->resources, hw->msi_ctrl); - - if (WARN(!sys->bus, "PCI: unable to scan bus!")) { - kfree(sys); + ret = hw->scan(nr, bridge); + else { + list_splice_init(&sys->resources, + &bridge->windows); + bridge->dev.parent = parent; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = hw->ops; + bridge->msi = hw->msi_ctrl; + bridge->align_resource = + hw->align_resource; + + ret = pci_scan_root_bus_bridge(bridge); + } + + if (WARN(ret < 0, "PCI: unable to scan bus!")) { + pci_free_host_bridge(bridge); break; } + sys->bus = bridge->bus; + busnr = sys->bus->busn_res.end + 1; list_add(&sys->node, head); - - host_bridge = pci_find_host_bridge(sys->bus); - host_bridge->align_resource = hw->align_resource; } else { - kfree(sys); + pci_free_host_bridge(bridge); if (ret < 0) break; } @@ -519,8 +533,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw) if (hw->postinit) hw->postinit(); - pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); - list_for_each_entry(sys, &head, node) { struct pci_bus *bus = sys->bus; diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 9f157e7c51e7..c731f0d2b2af 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -797,7 +797,10 @@ ENTRY(__switch_to) #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) ldr r7, [r2, #TI_TASK] ldr r8, =__stack_chk_guard - ldr r7, [r7, #TSK_STACK_CANARY] + .if (TSK_STACK_CANARY > IMM12_MASK) + add r7, r7, #TSK_STACK_CANARY & ~IMM12_MASK + .endif + ldr r7, [r7, #TSK_STACK_CANARY & IMM12_MASK] #endif #ifdef CONFIG_CPU_USE_DOMAINS mcr p15, 0, r6, c3, c0, 0 @ Set domain register diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index c73c4030ca5d..efcd9f25a14b 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -92,12 +92,95 @@ 2: mcount_exit .endm +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + +.macro __ftrace_regs_caller + + sub sp, sp, #8 @ space for PC and CPSR OLD_R0, + @ OLD_R0 will overwrite previous LR + + add ip, sp, #12 @ move in IP the value of SP as it was + @ before the push {lr} of the mcount mechanism + + str lr, [sp, #0] @ store LR instead of PC + + ldr lr, [sp, #8] @ get previous LR + + str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR + + stmdb sp!, {ip, lr} + stmdb sp!, {r0-r11, lr} + + @ stack content at this point: + @ 0 4 48 52 56 60 64 68 72 + @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | + + mov r3, sp @ struct pt_regs* + + ldr r2, =function_trace_op + ldr r2, [r2] @ pointer to the current + @ function tracing op + + ldr r1, [sp, #S_LR] @ lr of instrumented func + + ldr lr, [sp, #S_PC] @ get LR + + mcount_adjust_addr r0, lr @ instrumented function + + .globl ftrace_regs_call +ftrace_regs_call: + bl ftrace_stub + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + .globl ftrace_graph_regs_call +ftrace_graph_regs_call: + mov r0, r0 +#endif + + @ pop saved regs + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8] @ restore PC + ldr lr, [sp, #4] @ restore LR + ldr sp, [sp, #0] @ restore SP + mov pc, ip @ return +.endm + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +.macro __ftrace_graph_regs_caller + + sub r0, fp, #4 @ lr of instrumented routine (parent) + + @ called from __ftrace_regs_caller + ldr r1, [sp, #S_PC] @ instrumented routine (func) + mcount_adjust_addr r1, r1 + + mov r2, fp @ frame pointer + bl prepare_ftrace_return + + @ pop registers saved in ftrace_regs_caller + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8] @ restore PC + ldr lr, [sp, #4] @ restore LR + ldr sp, [sp, #0] @ restore SP + mov pc, ip @ return + +.endm +#endif +#endif + .macro __ftrace_caller suffix mcount_enter mcount_get_lr r1 @ lr of instrumented func mcount_adjust_addr r0, lr @ instrumented function +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + ldr r2, =function_trace_op + ldr r2, [r2] @ pointer to the current + @ function tracing op + mov r3, #0 @ regs is NULL +#endif + .globl ftrace_call\suffix ftrace_call\suffix: bl ftrace_stub @@ -212,6 +295,15 @@ UNWIND(.fnstart) __ftrace_caller UNWIND(.fnend) ENDPROC(ftrace_caller) + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +ENTRY(ftrace_regs_caller) +UNWIND(.fnstart) + __ftrace_regs_caller +UNWIND(.fnend) +ENDPROC(ftrace_regs_caller) +#endif + #endif #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -220,6 +312,14 @@ UNWIND(.fnstart) __ftrace_graph_caller UNWIND(.fnend) ENDPROC(ftrace_graph_caller) + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +ENTRY(ftrace_graph_regs_caller) +UNWIND(.fnstart) + __ftrace_graph_regs_caller +UNWIND(.fnend) +ENDPROC(ftrace_graph_regs_caller) +#endif #endif .purgem mcount_enter diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 833c991075a1..5617932a83df 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -141,6 +141,15 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ret = ftrace_modify_code(pc, 0, new, false); +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + if (!ret) { + pc = (unsigned long)&ftrace_regs_call; + new = ftrace_call_replace(pc, (unsigned long)func); + + ret = ftrace_modify_code(pc, 0, new, false); + } +#endif + #ifdef CONFIG_OLD_MCOUNT if (!ret) { pc = (unsigned long)&ftrace_call_old; @@ -159,11 +168,29 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned long ip = rec->ip; old = ftrace_nop_replace(rec); + + new = ftrace_call_replace(ip, adjust_address(rec, addr)); + + return ftrace_modify_code(rec->ip, old, new, true); +} + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, + unsigned long addr) +{ + unsigned long new, old; + unsigned long ip = rec->ip; + + old = ftrace_call_replace(ip, adjust_address(rec, old_addr)); + new = ftrace_call_replace(ip, adjust_address(rec, addr)); return ftrace_modify_code(rec->ip, old, new, true); } +#endif + int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { @@ -231,6 +258,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, extern unsigned long ftrace_graph_call; extern unsigned long ftrace_graph_call_old; extern void ftrace_graph_caller_old(void); +extern unsigned long ftrace_graph_regs_call; +extern void ftrace_graph_regs_caller(void); static int __ftrace_modify_caller(unsigned long *callsite, void (*func) (void), bool enable) @@ -253,6 +282,14 @@ static int ftrace_modify_graph_caller(bool enable) ftrace_graph_caller, enable); +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + if (!ret) + ret = __ftrace_modify_caller(&ftrace_graph_regs_call, + ftrace_graph_regs_caller, + enable); +#endif + + #ifdef CONFIG_OLD_MCOUNT if (!ret) ret = __ftrace_modify_caller(&ftrace_graph_call_old, diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 15495887ca14..fe1419eeb932 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -30,7 +30,6 @@ extern unsigned long kexec_boot_atags; static atomic_t waiting_for_crash_ipi; -static unsigned long dt_mem; /* * Provide a dummy crash_notes definition while crash dump arrives to arm. * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. @@ -42,6 +41,9 @@ int machine_kexec_prepare(struct kimage *image) __be32 header; int i, err; + image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET + + KEXEC_ARM_ATAGS_OFFSET; + /* * Validate that if the current HW supports SMP, then the SW supports * and implements CPU hotplug for the current HW. If not, we won't be @@ -66,8 +68,8 @@ int machine_kexec_prepare(struct kimage *image) if (err) return err; - if (be32_to_cpu(header) == OF_DT_HEADER) - dt_mem = current_segment->mem; + if (header == cpu_to_be32(OF_DT_HEADER)) + image->arch.kernel_r2 = current_segment->mem; } return 0; } @@ -165,8 +167,7 @@ void machine_kexec(struct kimage *image) kexec_start_address = image->start; kexec_indirection_page = page_list; kexec_mach_type = machine_arch_type; - kexec_boot_atags = dt_mem ?: image->start - KEXEC_ARM_ZIMAGE_OFFSET - + KEXEC_ARM_ATAGS_OFFSET; + kexec_boot_atags = image->arch.kernel_r2; /* copy our kernel relocation code to the control code page */ reboot_entry = fncpy(reboot_code_buffer, diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index 96b7a477a8db..8226d0b71fd3 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -552,7 +552,7 @@ static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu) return 0; } -static struct of_device_id armv6_pmu_of_device_ids[] = { +static const struct of_device_id armv6_pmu_of_device_ids[] = { {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init}, {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init}, {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init}, diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 939e8b58c59d..d96714e1858c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -123,10 +123,10 @@ void __show_regs(struct pt_regs *regs) print_symbol("PC is at %s\n", instruction_pointer(regs)); print_symbol("LR is at %s\n", regs->ARM_lr); - printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" - "sp : %08lx ip : %08lx fp : %08lx\n", - regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, - regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); + printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n", + regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr); + printk("sp : %08lx ip : %08lx fp : %08lx\n", + regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); printk("r10: %08lx r9 : %08lx r8 : %08lx\n", regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); @@ -404,9 +404,17 @@ static unsigned long sigpage_addr(const struct mm_struct *mm, static struct page *signal_page; extern struct page *get_signal_page(void); +static int sigpage_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + current->mm->context.sigpage = new_vma->vm_start; + return 0; +} + static const struct vm_special_mapping sigpage_mapping = { .name = "[sigpage]", .pages = &signal_page, + .mremap = sigpage_mremap, }; int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 4e80bf7420d4..8e9a3e40d949 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -987,6 +987,9 @@ static void __init reserve_crashkernel(void) if (crash_base <= 0) { unsigned long long crash_max = idmap_to_phys((u32)~0); + unsigned long long lowmem_max = __pa(high_memory - 1) + 1; + if (crash_max > lowmem_max) + crash_max = lowmem_max; crash_base = memblock_find_in_range(CRASH_ALIGN, crash_max, crash_size, CRASH_ALIGN); if (!crash_base) { diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 3a48b54c6405..e2de50bf8742 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -41,8 +41,10 @@ static int preserve_crunch_context(struct crunch_sigframe __user *frame) return __copy_to_user(frame, kframe, sizeof(*frame)); } -static int restore_crunch_context(struct crunch_sigframe __user *frame) +static int restore_crunch_context(char __user **auxp) { + struct crunch_sigframe __user *frame = + (struct crunch_sigframe __user *)*auxp; char kbuf[sizeof(*frame) + 8]; struct crunch_sigframe *kframe; @@ -53,6 +55,7 @@ static int restore_crunch_context(struct crunch_sigframe __user *frame) if (kframe->magic != CRUNCH_MAGIC || kframe->size != CRUNCH_STORAGE_SIZE) return -1; + *auxp += CRUNCH_STORAGE_SIZE; crunch_task_restore(current_thread_info(), &kframe->storage); return 0; } @@ -60,21 +63,39 @@ static int restore_crunch_context(struct crunch_sigframe __user *frame) #ifdef CONFIG_IWMMXT -static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) +static int preserve_iwmmxt_context(struct iwmmxt_sigframe __user *frame) { char kbuf[sizeof(*frame) + 8]; struct iwmmxt_sigframe *kframe; + int err = 0; /* the iWMMXt context must be 64 bit aligned */ kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); - kframe->magic = IWMMXT_MAGIC; - kframe->size = IWMMXT_STORAGE_SIZE; - iwmmxt_task_copy(current_thread_info(), &kframe->storage); - return __copy_to_user(frame, kframe, sizeof(*frame)); + + if (test_thread_flag(TIF_USING_IWMMXT)) { + kframe->magic = IWMMXT_MAGIC; + kframe->size = IWMMXT_STORAGE_SIZE; + iwmmxt_task_copy(current_thread_info(), &kframe->storage); + + err = __copy_to_user(frame, kframe, sizeof(*frame)); + } else { + /* + * For bug-compatibility with older kernels, some space + * has to be reserved for iWMMXt even if it's not used. + * Set the magic and size appropriately so that properly + * written userspace can skip it reliably: + */ + __put_user_error(DUMMY_MAGIC, &frame->magic, err); + __put_user_error(IWMMXT_STORAGE_SIZE, &frame->size, err); + } + + return err; } -static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) +static int restore_iwmmxt_context(char __user **auxp) { + struct iwmmxt_sigframe __user *frame = + (struct iwmmxt_sigframe __user *)*auxp; char kbuf[sizeof(*frame) + 8]; struct iwmmxt_sigframe *kframe; @@ -82,10 +103,28 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); if (__copy_from_user(kframe, frame, sizeof(*frame))) return -1; - if (kframe->magic != IWMMXT_MAGIC || - kframe->size != IWMMXT_STORAGE_SIZE) + + /* + * For non-iWMMXt threads: a single iwmmxt_sigframe-sized dummy + * block is discarded for compatibility with setup_sigframe() if + * present, but we don't mandate its presence. If some other + * magic is here, it's not for us: + */ + if (!test_thread_flag(TIF_USING_IWMMXT) && + kframe->magic != DUMMY_MAGIC) + return 0; + + if (kframe->size != IWMMXT_STORAGE_SIZE) return -1; - iwmmxt_task_restore(current_thread_info(), &kframe->storage); + + if (test_thread_flag(TIF_USING_IWMMXT)) { + if (kframe->magic != IWMMXT_MAGIC) + return -1; + + iwmmxt_task_restore(current_thread_info(), &kframe->storage); + } + + *auxp += IWMMXT_STORAGE_SIZE; return 0; } @@ -108,8 +147,10 @@ static int preserve_vfp_context(struct vfp_sigframe __user *frame) return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc); } -static int restore_vfp_context(struct vfp_sigframe __user *frame) +static int restore_vfp_context(char __user **auxp) { + struct vfp_sigframe __user *frame = + (struct vfp_sigframe __user *)*auxp; unsigned long magic; unsigned long size; int err = 0; @@ -122,6 +163,7 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame) if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) return -EINVAL; + *auxp += size; return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc); } @@ -142,7 +184,7 @@ struct rt_sigframe { static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) { - struct aux_sigframe __user *aux; + char __user *aux; sigset_t set; int err; @@ -170,18 +212,18 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) err |= !valid_user_regs(regs); - aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; + aux = (char __user *) sf->uc.uc_regspace; #ifdef CONFIG_CRUNCH if (err == 0) - err |= restore_crunch_context(&aux->crunch); + err |= restore_crunch_context(&aux); #endif #ifdef CONFIG_IWMMXT - if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) - err |= restore_iwmmxt_context(&aux->iwmmxt); + if (err == 0) + err |= restore_iwmmxt_context(&aux); #endif #ifdef CONFIG_VFP if (err == 0) - err |= restore_vfp_context(&aux->vfp); + err |= restore_vfp_context(&aux); #endif return err; @@ -287,7 +329,7 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) err |= preserve_crunch_context(&aux->crunch); #endif #ifdef CONFIG_IWMMXT - if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) + if (err == 0) err |= preserve_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index f8a3ab82e77f..bf949a763dbe 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -11,6 +11,7 @@ * for more details. */ +#include <linux/arch_topology.h> #include <linux/cpu.h> #include <linux/cpufreq.h> #include <linux/cpumask.h> @@ -44,77 +45,6 @@ * to run the rebalance_domains for all idle cores and the cpu_capacity can be * updated during this sequence. */ -static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE; -static DEFINE_MUTEX(cpu_scale_mutex); - -unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu) -{ - return per_cpu(cpu_scale, cpu); -} - -static void set_capacity_scale(unsigned int cpu, unsigned long capacity) -{ - per_cpu(cpu_scale, cpu) = capacity; -} - -#ifdef CONFIG_PROC_SYSCTL -static ssize_t cpu_capacity_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - - return sprintf(buf, "%lu\n", - arch_scale_cpu_capacity(NULL, cpu->dev.id)); -} - -static ssize_t cpu_capacity_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - int this_cpu = cpu->dev.id, i; - unsigned long new_capacity; - ssize_t ret; - - if (count) { - ret = kstrtoul(buf, 0, &new_capacity); - if (ret) - return ret; - if (new_capacity > SCHED_CAPACITY_SCALE) - return -EINVAL; - - mutex_lock(&cpu_scale_mutex); - for_each_cpu(i, &cpu_topology[this_cpu].core_sibling) - set_capacity_scale(i, new_capacity); - mutex_unlock(&cpu_scale_mutex); - } - - return count; -} - -static DEVICE_ATTR_RW(cpu_capacity); - -static int register_cpu_capacity_sysctl(void) -{ - int i; - struct device *cpu; - - for_each_possible_cpu(i) { - cpu = get_cpu_device(i); - if (!cpu) { - pr_err("%s: too early to get CPU%d device!\n", - __func__, i); - continue; - } - device_create_file(cpu, &dev_attr_cpu_capacity); - } - - return 0; -} -subsys_initcall(register_cpu_capacity_sysctl); -#endif #ifdef CONFIG_OF struct cpu_efficiency { @@ -143,145 +73,6 @@ static unsigned long *__cpu_capacity; static unsigned long middle_capacity = 1; static bool cap_from_dt = true; -static u32 *raw_capacity; -static bool cap_parsing_failed; -static u32 capacity_scale; - -static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu) -{ - int ret = 1; - u32 cpu_capacity; - - if (cap_parsing_failed) - return !ret; - - ret = of_property_read_u32(cpu_node, - "capacity-dmips-mhz", - &cpu_capacity); - if (!ret) { - if (!raw_capacity) { - raw_capacity = kcalloc(num_possible_cpus(), - sizeof(*raw_capacity), - GFP_KERNEL); - if (!raw_capacity) { - pr_err("cpu_capacity: failed to allocate memory for raw capacities\n"); - cap_parsing_failed = true; - return !ret; - } - } - capacity_scale = max(cpu_capacity, capacity_scale); - raw_capacity[cpu] = cpu_capacity; - pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n", - cpu_node->full_name, raw_capacity[cpu]); - } else { - if (raw_capacity) { - pr_err("cpu_capacity: missing %s raw capacity\n", - cpu_node->full_name); - pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n"); - } - cap_parsing_failed = true; - kfree(raw_capacity); - } - - return !ret; -} - -static void normalize_cpu_capacity(void) -{ - u64 capacity; - int cpu; - - if (!raw_capacity || cap_parsing_failed) - return; - - pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale); - mutex_lock(&cpu_scale_mutex); - for_each_possible_cpu(cpu) { - capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT) - / capacity_scale; - set_capacity_scale(cpu, capacity); - pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n", - cpu, arch_scale_cpu_capacity(NULL, cpu)); - } - mutex_unlock(&cpu_scale_mutex); -} - -#ifdef CONFIG_CPU_FREQ -static cpumask_var_t cpus_to_visit; -static bool cap_parsing_done; -static void parsing_done_workfn(struct work_struct *work); -static DECLARE_WORK(parsing_done_work, parsing_done_workfn); - -static int -init_cpu_capacity_callback(struct notifier_block *nb, - unsigned long val, - void *data) -{ - struct cpufreq_policy *policy = data; - int cpu; - - if (cap_parsing_failed || cap_parsing_done) - return 0; - - switch (val) { - case CPUFREQ_NOTIFY: - pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n", - cpumask_pr_args(policy->related_cpus), - cpumask_pr_args(cpus_to_visit)); - cpumask_andnot(cpus_to_visit, - cpus_to_visit, - policy->related_cpus); - for_each_cpu(cpu, policy->related_cpus) { - raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) * - policy->cpuinfo.max_freq / 1000UL; - capacity_scale = max(raw_capacity[cpu], capacity_scale); - } - if (cpumask_empty(cpus_to_visit)) { - normalize_cpu_capacity(); - kfree(raw_capacity); - pr_debug("cpu_capacity: parsing done\n"); - cap_parsing_done = true; - schedule_work(&parsing_done_work); - } - } - return 0; -} - -static struct notifier_block init_cpu_capacity_notifier = { - .notifier_call = init_cpu_capacity_callback, -}; - -static int __init register_cpufreq_notifier(void) -{ - if (cap_parsing_failed) - return -EINVAL; - - if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) { - pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n"); - return -ENOMEM; - } - cpumask_copy(cpus_to_visit, cpu_possible_mask); - - return cpufreq_register_notifier(&init_cpu_capacity_notifier, - CPUFREQ_POLICY_NOTIFIER); -} -core_initcall(register_cpufreq_notifier); - -static void parsing_done_workfn(struct work_struct *work) -{ - cpufreq_unregister_notifier(&init_cpu_capacity_notifier, - CPUFREQ_POLICY_NOTIFIER); -} - -#else -static int __init free_raw_capacity(void) -{ - kfree(raw_capacity); - - return 0; -} -core_initcall(free_raw_capacity); -#endif /* * Iterate all CPUs' descriptor in DT and compute the efficiency @@ -320,7 +111,7 @@ static void __init parse_dt_topology(void) continue; } - if (parse_cpu_capacity(cn, cpu)) { + if (topology_parse_cpu_capacity(cn, cpu)) { of_node_put(cn); continue; } @@ -368,8 +159,8 @@ static void __init parse_dt_topology(void) middle_capacity = ((max_capacity / 3) >> (SCHED_CAPACITY_SHIFT-1)) + 1; - if (cap_from_dt && !cap_parsing_failed) - normalize_cpu_capacity(); + if (cap_from_dt) + topology_normalize_cpu_scale(); } /* @@ -382,10 +173,10 @@ static void update_cpu_capacity(unsigned int cpu) if (!cpu_capacity(cpu) || cap_from_dt) return; - set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity); + topology_set_cpu_scale(cpu, cpu_capacity(cpu) / middle_capacity); pr_info("CPU%u: update cpu_capacity %lu\n", - cpu, arch_scale_cpu_capacity(NULL, cpu)); + cpu, topology_get_cpu_scale(NULL, cpu)); } #else diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index 53cf86cf2d1a..a4d6dc0f2427 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -54,8 +54,26 @@ static const struct vm_special_mapping vdso_data_mapping = { .pages = &vdso_data_page, }; +static int vdso_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + unsigned long new_size = new_vma->vm_end - new_vma->vm_start; + unsigned long vdso_size; + + /* without VVAR page */ + vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT; + + if (vdso_size != new_size) + return -EINVAL; + + current->mm->context.vdso = new_vma->vm_start; + + return 0; +} + static struct vm_special_mapping vdso_text_mapping __ro_after_init = { .name = "[vdso]", + .mremap = vdso_mremap, }; struct elfinfo { |