#endif
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K)
- //# ifdef _CACHE
+ # ifdef _CACHE
# define MULTI_CACHE 1
- //# else
- //# define _CACHE v6
- //# endif
+ # else
+ # define _CACHE v6
+ # endif
#endif
#if defined(CONFIG_CPU_V7)
- //# ifdef _CACHE
+ # ifdef _CACHE
# define MULTI_CACHE 1
- //# else
- //# define _CACHE v7
- //# endif
+ # else
+ # define _CACHE v7
+ # endif
#endif
#if !defined(_CACHE) && !defined(MULTI_CACHE)
#ifndef MULTI_CACHE
#define __cpuc_flush_icache_all __glue(_CACHE,_flush_icache_all)
#define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all)
+#define __cpuc_flush_kern_louis __glue(_CACHE,_flush_kern_cache_louis)
#define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all)
#define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range)
#define __cpuc_coherent_kern_range __glue(_CACHE,_coherent_kern_range)
process.o ptrace.o return_address.o sched_clock.o \
setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
- obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
+ obj-$(CONFIG_ATAGS) += atags_parse.o
+ obj-$(CONFIG_ATAGS_PROC) += atags_proc.o
+ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
- obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_OC_ETM) += etm.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
else
test-kprobes-objs += kprobes-test-arm.o
endif
- obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o
obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o
obj-$(CONFIG_IWMMXT) += iwmmxt.o
- obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
- obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
+ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
obj-$(CONFIG_DEBUG_LL) += debug.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o
+
extra-y := $(head-y) vmlinux.lds
#include <asm/thread_info.h>
#include <asm/pgtable.h>
- #ifdef CONFIG_DEBUG_LL
- #include <mach/debug-macro.S>
+ #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING)
+ #include CONFIG_DEBUG_LL_INCLUDE
#endif
/*
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
- setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
- @ and irqs disabled
+#ifdef CONFIG_ARM_VIRT_EXT
+ bl __hyp_stub_install
+#endif
+ @ ensure svc mode and all interrupts masked
+ safe_svcmode_maskall r9
+
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
* the processor type - there is no need to check the machine type
* as it has already been validated by the primary processor.
*/
- setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
+#ifdef CONFIG_ARM_VIRT_EXT
+ bl __hyp_stub_install
+#endif
+ safe_svcmode_maskall r9
+
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type
movs r10, r5 @ invalid processor?
#include <linux/init.h>
#include <linux/kexec.h>
#include <linux/of_fdt.h>
- #include <linux/root_dev.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
- #include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/memblock.h>
#include <linux/bug.h>
#include <asm/traps.h>
#include <asm/unwind.h>
#include <asm/memblock.h>
+#include <asm/virt.h>
- #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
- #include "compat.h"
- #endif
#include "atags.h"
#include "tcm.h"
- #ifndef MEM_SIZE
- #define MEM_SIZE (16*1024*1024)
- #endif
#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
char fpe_type[8];
static char __initdata cmd_line[COMMAND_LINE_SIZE];
struct machine_desc *machine_desc __initdata;
- static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
}
early_param("mem", early_mem);
- static void __init
- setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
- {
- #ifdef CONFIG_BLK_DEV_RAM
- extern int rd_size, rd_image_start, rd_prompt, rd_doload;
-
- rd_image_start = image_start;
- rd_prompt = prompt;
- rd_doload = doload;
-
- if (rd_sz)
- rd_size = rd_sz;
- #endif
- }
-
static void __init request_standard_resources(struct machine_desc *mdesc)
{
struct memblock_region *region;
request_resource(&ioport_resource, &lp2);
}
- /*
- * Tag parsing.
- *
- * This is the new way of passing data to the kernel at boot time. Rather
- * than passing a fixed inflexible structure to the kernel, we pass a list
- * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
- * tag for the list to be recognised (to distinguish the tagged list from
- * a param_struct). The list is terminated with a zero-length tag (this tag
- * is not parsed in any way).
- */
- static int __init parse_tag_core(const struct tag *tag)
- {
- if (tag->hdr.size > 2) {
- if ((tag->u.core.flags & 1) == 0)
- root_mountflags &= ~MS_RDONLY;
- ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
- }
- return 0;
- }
-
- __tagtable(ATAG_CORE, parse_tag_core);
-
- static int __init parse_tag_mem32(const struct tag *tag)
- {
- return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
- }
-
- __tagtable(ATAG_MEM, parse_tag_mem32);
-
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
struct screen_info screen_info = {
.orig_video_lines = 30,
.orig_video_isVGA = 1,
.orig_video_points = 8
};
-
- static int __init parse_tag_videotext(const struct tag *tag)
- {
- screen_info.orig_x = tag->u.videotext.x;
- screen_info.orig_y = tag->u.videotext.y;
- screen_info.orig_video_page = tag->u.videotext.video_page;
- screen_info.orig_video_mode = tag->u.videotext.video_mode;
- screen_info.orig_video_cols = tag->u.videotext.video_cols;
- screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
- screen_info.orig_video_lines = tag->u.videotext.video_lines;
- screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
- screen_info.orig_video_points = tag->u.videotext.video_points;
- return 0;
- }
-
- __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
- #endif
-
- static int __init parse_tag_ramdisk(const struct tag *tag)
- {
- setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
- (tag->u.ramdisk.flags & 2) == 0,
- tag->u.ramdisk.start, tag->u.ramdisk.size);
- return 0;
- }
-
- __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
-
- static int __init parse_tag_serialnr(const struct tag *tag)
- {
- system_serial_low = tag->u.serialnr.low;
- system_serial_high = tag->u.serialnr.high;
- return 0;
- }
-
- __tagtable(ATAG_SERIAL, parse_tag_serialnr);
-
- static int __init parse_tag_revision(const struct tag *tag)
- {
- system_rev = tag->u.revision.rev;
- return 0;
- }
-
- __tagtable(ATAG_REVISION, parse_tag_revision);
-
- static int __init parse_tag_cmdline(const struct tag *tag)
- {
- #if defined(CONFIG_CMDLINE_EXTEND)
- strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
- strlcat(default_command_line, tag->u.cmdline.cmdline,
- COMMAND_LINE_SIZE);
- #elif defined(CONFIG_CMDLINE_FORCE)
- pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
- #else
- strlcpy(default_command_line, tag->u.cmdline.cmdline,
- COMMAND_LINE_SIZE);
#endif
- return 0;
- }
-
- __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
-
- /*
- * Scan the tag table for this tag, and call its parse function.
- * The tag table is built by the linker from all the __tagtable
- * declarations.
- */
- static int __init parse_tag(const struct tag *tag)
- {
- extern struct tagtable __tagtable_begin, __tagtable_end;
- struct tagtable *t;
-
- for (t = &__tagtable_begin; t < &__tagtable_end; t++)
- if (tag->hdr.tag == t->tag) {
- t->parse(tag);
- break;
- }
-
- return t < &__tagtable_end;
- }
-
- /*
- * Parse all tags in the list, checking both the global and architecture
- * specific tag tables.
- */
- static void __init parse_tags(const struct tag *t)
- {
- for (; t->hdr.size; t = tag_next(t))
- if (!parse_tag(t))
- printk(KERN_WARNING
- "Ignoring unrecognised tag 0x%08x\n",
- t->hdr.tag);
- }
-
- /*
- * This holds our defaults.
- */
- static struct init_tags {
- struct tag_header hdr1;
- struct tag_core core;
- struct tag_header hdr2;
- struct tag_mem32 mem;
- struct tag_header hdr3;
- } init_tags __initdata = {
- { tag_size(tag_core), ATAG_CORE },
- { 1, PAGE_SIZE, 0xff },
- { tag_size(tag_mem32), ATAG_MEM },
- { MEM_SIZE },
- { 0, ATAG_NONE }
- };
static int __init customize_machine(void)
{
static inline void reserve_crashkernel(void) {}
#endif /* CONFIG_KEXEC */
- static void __init squash_mem_tags(struct tag *tag)
- {
- for (; tag->hdr.size; tag = tag_next(tag))
- if (tag->hdr.tag == ATAG_MEM)
- tag->hdr.tag = ATAG_NONE;
- }
-
- static struct machine_desc * __init setup_machine_tags(unsigned int nr)
- {
- struct tag *tags = (struct tag *)&init_tags;
- struct machine_desc *mdesc = NULL, *p;
- char *from = default_command_line;
-
- init_tags.mem.start = PHYS_OFFSET;
-
- /*
- * locate machine in the list of supported machines.
- */
- for_each_machine_desc(p)
- if (nr == p->nr) {
- printk("Machine: %s\n", p->name);
- mdesc = p;
- break;
- }
-
- if (!mdesc) {
- early_print("\nError: unrecognized/unsupported machine ID"
- " (r1 = 0x%08x).\n\n", nr);
- dump_machine_table(); /* does not return */
- }
-
- if (__atags_pointer)
- tags = phys_to_virt(__atags_pointer);
- else if (mdesc->atag_offset)
- tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
-
- #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
- /*
- * If we have the old style parameters, convert them to
- * a tag list.
- */
- if (tags->hdr.tag != ATAG_CORE)
- convert_to_tag_list(tags);
- #endif
-
- if (tags->hdr.tag != ATAG_CORE) {
- #if defined(CONFIG_OF)
- /*
- * If CONFIG_OF is set, then assume this is a reasonably
- * modern system that should pass boot parameters
- */
- early_print("Warning: Neither atags nor dtb found\n");
- #endif
- tags = (struct tag *)&init_tags;
- }
-
- if (mdesc->fixup)
- mdesc->fixup(tags, &from, &meminfo);
-
- if (tags->hdr.tag == ATAG_CORE) {
- if (meminfo.nr_banks != 0)
- squash_mem_tags(tags);
- save_atags(tags);
- parse_tags(tags);
- }
-
- /* parse_early_param needs a boot_command_line */
- strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
-
- return mdesc;
- }
-
static int __init meminfo_cmp(const void *_a, const void *_b)
{
const struct membank *a = _a, *b = _b;
return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
}
+void __init hyp_mode_check(void)
+{
+#ifdef CONFIG_ARM_VIRT_EXT
+ if (is_hyp_mode_available()) {
+ pr_info("CPU: All CPU(s) started in HYP mode.\n");
+ pr_info("CPU: Virtualization extensions available.\n");
+ } else if (is_hyp_mode_mismatched()) {
+ pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
+ __boot_cpu_mode & MODE_MASK);
+ pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
+ } else
+ pr_info("CPU: All CPU(s) started in SVC mode.\n");
+#endif
+}
+
void __init setup_arch(char **cmdline_p)
{
struct machine_desc *mdesc;
setup_processor();
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
- mdesc = setup_machine_tags(machine_arch_type);
+ mdesc = setup_machine_tags(__atags_pointer, machine_arch_type);
machine_desc = mdesc;
machine_name = mdesc->name;
unflatten_device_tree();
#ifdef CONFIG_SMP
- if (is_smp())
+ if (is_smp()) {
+ smp_set_ops(mdesc->smp);
smp_init_cpus();
+ }
#endif
+
+ if (!is_smp())
+ hyp_mode_check();
+
reserve_crashkernel();
tcm_init();
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/cpu.h>
- #include <linux/smp.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/clockchips.h>
#include <linux/completion.h>
+ #include <linux/cpufreq.h>
#include <linux/atomic.h>
+ #include <asm/smp.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/ptrace.h>
#include <asm/localtimer.h>
#include <asm/smp_plat.h>
+#include <asm/virt.h>
+ #include <asm/mach/arch.h>
/*
* as from 2.5, kernels no longer have an init_tasks structure
*/
struct secondary_data secondary_data;
+ /*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+ volatile int __cpuinitdata pen_release = -1;
+
enum ipi_msg_type {
- IPI_TIMER = 2,
+ IPI_WAKEUP,
+ IPI_TIMER,
IPI_RESCHEDULE,
IPI_CALL_FUNC,
IPI_CALL_FUNC_SINGLE,
static DECLARE_COMPLETION(cpu_running);
+ static struct smp_operations smp_ops;
+
+ void __init smp_set_ops(struct smp_operations *ops)
+ {
+ if (ops)
+ smp_ops = *ops;
+ };
+
int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
{
int ret;
return ret;
}
+ /* platform specific SMP operations */
+ void __init smp_init_cpus(void)
+ {
+ if (smp_ops.smp_init_cpus)
+ smp_ops.smp_init_cpus();
+ }
+
+ static void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+ {
+ if (smp_ops.smp_prepare_cpus)
+ smp_ops.smp_prepare_cpus(max_cpus);
+ }
+
+ static void __cpuinit platform_secondary_init(unsigned int cpu)
+ {
+ if (smp_ops.smp_secondary_init)
+ smp_ops.smp_secondary_init(cpu);
+ }
+
+ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+ {
+ if (smp_ops.smp_boot_secondary)
+ return smp_ops.smp_boot_secondary(cpu, idle);
+ return -ENOSYS;
+ }
+
#ifdef CONFIG_HOTPLUG_CPU
static void percpu_timer_stop(void);
+ static int platform_cpu_kill(unsigned int cpu)
+ {
+ if (smp_ops.cpu_kill)
+ return smp_ops.cpu_kill(cpu);
+ return 1;
+ }
+
+ static void platform_cpu_die(unsigned int cpu)
+ {
+ if (smp_ops.cpu_die)
+ smp_ops.cpu_die(cpu);
+ }
+
+ static int platform_cpu_disable(unsigned int cpu)
+ {
+ if (smp_ops.cpu_disable)
+ return smp_ops.cpu_disable(cpu);
+
+ /*
+ * By default, allow disabling all CPUs except the first one,
+ * since this is special on a lot of platforms, e.g. because
+ * of clock tick interrupts.
+ */
+ return cpu == 0 ? -EPERM : 0;
+ }
/*
* __cpu_disable runs on the processor to be shutdown.
*/
- int __cpu_disable(void)
+ int __cpuinit __cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
int ret;
/*
* Flush user cache and TLB mappings, and then remove this CPU
* from the vm mask set of all processes.
+ *
+ * Caches are flushed to the Level of Unification Inner Shareable
+ * to write-back dirty lines to unified caches shared by all CPUs.
*/
- flush_cache_all();
+ flush_cache_louis();
local_flush_tlb_all();
clear_tasks_mm_cpumask(cpu);
* called on the thread which is asking for a CPU to be shutdown -
* waits until shutdown has completed, or it is timed out.
*/
- void __cpu_die(unsigned int cpu)
+ void __cpuinit __cpu_die(unsigned int cpu)
{
if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
pr_err("CPU%u: cpu didn't die\n", cpu);
num_online_cpus(),
bogosum / (500000/HZ),
(bogosum / (5000/HZ)) % 100);
+
+ hyp_mode_check();
}
void __init smp_prepare_boot_cpu(void)
}
static const char *ipi_types[NR_IPI] = {
- #define S(x,s) [x - IPI_TIMER] = s
+ #define S(x,s) [x] = s
+ S(IPI_WAKEUP, "CPU wakeup interrupts"),
S(IPI_TIMER, "Timer broadcast interrupts"),
S(IPI_RESCHEDULE, "Rescheduling interrupts"),
S(IPI_CALL_FUNC, "Function call interrupts"),
unsigned int cpu = smp_processor_id();
struct pt_regs *old_regs = set_irq_regs(regs);
- if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI)
- __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]);
+ if (ipinr < NR_IPI)
+ __inc_irq_stat(cpu, ipi_irqs[ipinr]);
switch (ipinr) {
+ case IPI_WAKEUP:
+ break;
+
case IPI_TIMER:
irq_enter();
ipi_timer();
{
return -EINVAL;
}
+
+ #ifdef CONFIG_CPU_FREQ
+
+ static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
+ static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
+ static unsigned long global_l_p_j_ref;
+ static unsigned long global_l_p_j_ref_freq;
+
+ static int cpufreq_callback(struct notifier_block *nb,
+ unsigned long val, void *data)
+ {
+ struct cpufreq_freqs *freq = data;
+ int cpu = freq->cpu;
+
+ if (freq->flags & CPUFREQ_CONST_LOOPS)
+ return NOTIFY_OK;
+
+ if (!per_cpu(l_p_j_ref, cpu)) {
+ per_cpu(l_p_j_ref, cpu) =
+ per_cpu(cpu_data, cpu).loops_per_jiffy;
+ per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+ if (!global_l_p_j_ref) {
+ global_l_p_j_ref = loops_per_jiffy;
+ global_l_p_j_ref_freq = freq->old;
+ }
+ }
+
+ if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+ (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+ loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
+ global_l_p_j_ref_freq,
+ freq->new);
+ per_cpu(cpu_data, cpu).loops_per_jiffy =
+ cpufreq_scale(per_cpu(l_p_j_ref, cpu),
+ per_cpu(l_p_j_ref_freq, cpu),
+ freq->new);
+ }
+ return NOTIFY_OK;
+ }
+
+ static struct notifier_block cpufreq_notifier = {
+ .notifier_call = cpufreq_callback,
+ };
+
+ static int __init register_cpufreq_notifier(void)
+ {
+ return cpufreq_register_notifier(&cpufreq_notifier,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+ core_initcall(register_cpufreq_notifier);
+
+ #endif
mov pc, lr
ENDPROC(v7_flush_icache_all)
+ /*
+ * v7_flush_dcache_louis()
+ *
+ * Flush the D-cache up to the Level of Unification Inner Shareable
+ *
+ * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
+ */
+
+ENTRY(v7_flush_dcache_louis)
+ dmb @ ensure ordering with previous memory accesses
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr, r0 = clidr
+ ands r3, r0, #0xe00000 @ extract LoUIS from clidr
+ mov r3, r3, lsr #20 @ r3 = LoUIS * 2
+ moveq pc, lr @ return if level == 0
+ mov r10, #0 @ r10 (starting level) = 0
+ b flush_levels @ start flushing cache levels
+ENDPROC(v7_flush_dcache_louis)
+
/*
* v7_flush_dcache_all()
*
mov r3, r3, lsr #23 @ left align loc bit field
beq finished @ if loc is 0, then no need to clean
mov r10, #0 @ start clean at cache level 0
-loop1:
+flush_levels:
add r2, r10, r10, lsr #1 @ work out 3x current cache level
mov r1, r0, lsr r2 @ extract cache type bits from clidr
and r1, r1, #7 @ mask of the bits for current cache only
clz r5, r4 @ find bit position of way size increment
ldr r7, =0x7fff
ands r7, r7, r1, lsr #13 @ extract max number of the index size
-loop2:
+loop1:
mov r9, r4 @ create working copy of max way size
-loop3:
+loop2:
ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11
THUMB( lsl r6, r9, r5 )
THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
THUMB( orr r11, r11, r6 ) @ factor index number into r11
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
subs r9, r9, #1 @ decrement the way
- bge loop3
- subs r7, r7, #1 @ decrement the index
bge loop2
+ subs r7, r7, #1 @ decrement the index
+ bge loop1
skip:
add r10, r10, #2 @ increment cache number
cmp r3, r10
- bgt loop1
+ bgt flush_levels
finished:
mov r10, #0 @ swith back to cache level 0
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
mov pc, lr
ENDPROC(v7_flush_kern_cache_all)
+ /*
+ * v7_flush_kern_cache_louis(void)
+ *
+ * Flush the data cache up to Level of Unification Inner Shareable.
+ * Invalidate the I-cache to the point of unification.
+ */
+ENTRY(v7_flush_kern_cache_louis)
+ ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
+ bl v7_flush_dcache_louis
+ mov r0, #0
+ ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable
+ ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate
+ ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
+ mov pc, lr
+ENDPROC(v7_flush_kern_cache_louis)
+
/*
* v7_flush_cache_all()
*
* isn't mapped, fail with -EFAULT.
*/
9001:
+ #ifdef CONFIG_ARM_ERRATA_775420
+ dsb
+ #endif
mov r0, #-EFAULT
mov pc, lr
UNWIND(.fnend )