[RFC PATCH 06/17] ARM: kernel: save/restore generic infrastructure

Amit Kachhap amit.kachhap at linaro.org
Thu Jul 28 12:22:38 EDT 2011


On 7 July 2011 21:20, Lorenzo Pieralisi <lorenzo.pieralisi at arm.com> wrote:
>
> This patch provides the code infrastructure needed to maintain
> a generic per-cpu architecture implementation of idle code.
>
> sr_platform.c :
>        - code manages patchset initialization and memory management
>
> sr_context.c:
>        - code initializes run-time context save/restore generic
>          support
>
> sr_power.c:
>        - provides the generic infrastructure to enter exit low
>          power modes and communicate with Power Control Unit (PCU)
>
> v7 support hinges on the basic infrastructure to provide per-cpu
> arch implementation basically through standard function pointers
> signatures.
>
> Preprocessor defines include size of data needed to save/restore
> L2 state. This define value should be moved to the respective
> subsystem (PL310) once the patchset IF to that subsystem is settled.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi at arm.com>
> ---
>  arch/arm/kernel/sr.h          |  162 +++++++++++++++++++++++++++++++++++++++++
>  arch/arm/kernel/sr_context.c  |   23 ++++++
>  arch/arm/kernel/sr_helpers.h  |   56 ++++++++++++++
>  arch/arm/kernel/sr_platform.c |   48 ++++++++++++
>  arch/arm/kernel/sr_power.c    |   26 +++++++
>  5 files changed, 315 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/kernel/sr.h
>  create mode 100644 arch/arm/kernel/sr_context.c
>  create mode 100644 arch/arm/kernel/sr_helpers.h
>  create mode 100644 arch/arm/kernel/sr_platform.c
>  create mode 100644 arch/arm/kernel/sr_power.c
>
> diff --git a/arch/arm/kernel/sr.h b/arch/arm/kernel/sr.h
> new file mode 100644
> index 0000000..6b24e53
> --- /dev/null
> +++ b/arch/arm/kernel/sr.h
> @@ -0,0 +1,162 @@
> +#define SR_NR_CLUSTERS 1
> +
> +#define STACK_SIZE 512
> +
> +#define CPU_A5                 0x4100c050
> +#define CPU_A8                 0x4100c080
> +#define CPU_A9                 0x410fc090
> +#define L2_DATA_SIZE           16
> +#define CONTEXT_SPACE_UNCACHED (2 * PAGE_SIZE)
> +#define PA(f) ((typeof(f) *)virt_to_phys((void *)f))
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <linux/types.h>
> +#include <linux/threads.h>
> +#include <linux/cpumask.h>
> +#include <asm/page.h>
> +
> +/*
> + * Structures we hide from the OS API
> + */
> +
> +struct sr_cpu_context {
> +       u32 flags;
> +       u32 saved_items;
> +       u32 *mmu_data;
> +};
> +
> +struct sr_cluster_context {
> +       u32 saved_items;
> +       u32 *l2_data;
> +};
> +
> +struct sr_main_table {
> +       pgd_t *os_mmu_context[SR_NR_CLUSTERS][CONFIG_NR_CPUS];
> +       cpumask_t cpu_idle_mask[SR_NR_CLUSTERS];
> +       pgd_t *fw_mmu_context;
> +       u32 num_clusters;
> +       struct sr_cluster       *cluster_table;
> +};
> +
> +
> +/*
> + * A cluster is a container for CPUs, typically either a single CPU or a
> + * coherent cluster.
> + * We assume the CPUs in the cluster can be switched off independently.
> + */
> +struct sr_cluster {
> +       u32 cpu_type;       /* A9mpcore, A5mpcore, etc                  */
> +       u32 num_cpus;
> +       struct sr_cluster_context *context;
> +       struct sr_cpu *cpu_table;
> +       u32 power_state;
> +       u32 cluster_down;
> +       void __iomem *scu_address;
> +       void *lock;
> +};
> +
> +struct sr_cpu {
> +       struct sr_cpu_context *context;
> +       u32 power_state;
> +};
> +
> +/*
> + * arch infrastructure
> + */
> +struct sr_arch {
> +       unsigned int            cpu_val;
> +       unsigned int            cpu_mask;
> +
> +       int (*init)(void);
> +
> +       int  (*save_context)(struct sr_cluster *, struct sr_cpu *,
> +                                          unsigned);
> +       int  (*restore_context)(struct sr_cluster *, struct sr_cpu *);
> +       int  (*enter_cstate)(unsigned cpu_index,
> +                                       struct sr_cpu *cpu,
> +                                       struct sr_cluster *cluster);
> +       int  (*leave_cstate)(unsigned, struct sr_cpu *,
> +                                       struct sr_cluster *);
> +       void (*reset)(void);
> +
> +};
> +
> +extern struct sr_arch *arch;
> +extern int lookup_arch(void);
> +
> +/*
> + * Global variables
> + */
> +extern struct sr_main_table main_table;
> +extern unsigned long idle_save_context;
> +extern unsigned long idle_restore_context;
> +extern unsigned long idle_mt;
> +extern void *context_memory_uncached;
> +
> +/*
> + * Context save/restore
> + */
> +typedef u32 (sr_save_context_t)
> +       (struct sr_cluster *,
> +       struct sr_cpu*, u32);
> +typedef u32 (sr_restore_context_t)
> +       (struct sr_cluster *,
> +       struct sr_cpu*);
> +
> +extern sr_save_context_t sr_save_context;
> +extern sr_restore_context_t sr_restore_context;
> +
> +
> +extern struct sr_arch *get_arch(void);
> +
> +
> +/*
> + * 1:1 mappings
> + */
> +
> +extern int linux_sr_setup_translation_tables(void);
> +
> +/*
> + * dumb memory allocator
> + */
> +
> +extern void *get_memory(unsigned int size);
> +
> +/*
> + * Entering/Leaving C-states function entries
> + */
> +
> +extern int sr_platform_enter_cstate(unsigned cpu_index, struct sr_cpu *cpu,
> +               struct sr_cluster *cluster);
> +extern int sr_platform_leave_cstate(unsigned cpu_index, struct sr_cpu *cpu,
> +               struct sr_cluster *cluster);
> +
> +/* save/restore main table */
> +extern struct sr_main_table main_table;
> +
> +/*
> + * Init functions
> + */
> +
> +extern int sr_platform_runtime_init(void);
> +extern int sr_platform_init(void);
> +extern int sr_context_init(void);
> +
> +
> +/*
> + * v7 specific
> + */
> +
> +extern char *cpu_v7_suspend_size;
> +extern void scu_cpu_mode(void __iomem *base, int state);
> +
> +/*
> + * These arrays keep suitable stack pointers for CPUs.
> + *
> + * The memory must be 8-byte aligned.
> + */
> +
> +extern unsigned long platform_cpu_stacks[CONFIG_NR_CPUS];
> +extern unsigned long platform_cpu_nc_stacks[CONFIG_NR_CPUS];
> +#endif
> diff --git a/arch/arm/kernel/sr_context.c b/arch/arm/kernel/sr_context.c
> new file mode 100644
> index 0000000..25eaa43
> --- /dev/null
> +++ b/arch/arm/kernel/sr_context.c
> @@ -0,0 +1,23 @@
> +/*
> + * Copyright (C) 2008-2011 ARM Limited
> + * Author(s): Jon Callan, Lorenzo Pieralisi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/cache.h>
> +#include <asm/cacheflush.h>
> +#include "sr.h"
> +
> +int  sr_context_init(void)
> +{
> +       idle_save_context = (unsigned long) arch->save_context;
> +       idle_restore_context = __pa(arch->restore_context);
> +       __cpuc_flush_dcache_area(&idle_restore_context, sizeof(unsigned long));
> +       outer_clean_range(__pa(&idle_restore_context),
> +                       __pa(&idle_restore_context + 1));
> +       return 0;
> +}
> diff --git a/arch/arm/kernel/sr_helpers.h b/arch/arm/kernel/sr_helpers.h
> new file mode 100644
> index 0000000..1ae3a9a
> --- /dev/null
> +++ b/arch/arm/kernel/sr_helpers.h
> @@ -0,0 +1,56 @@
> +/*
> + * Copyright (C) 2008-2011 ARM Limited
> + * Author(s): Jon Callan, Lorenzo Pieralisi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +static inline int sr_platform_get_cpu_index(void)
> +{
> +       unsigned int cpu;
> +       __asm__ __volatile__(
> +                       "mrc    p15, 0, %0, c0, c0, 5\n\t"
> +                       : "=r" (cpu));
> +       return cpu & 0xf;
> +}
> +
> +/*
> + * Placeholder for further extensions
> + */
> +static inline int sr_platform_get_cluster_index(void)
> +{
> +       return 0;
> +}
> +
> +static inline void __iomem *sr_platform_cbar(void)
> +{
> +       void __iomem *base;
> +       __asm__ __volatile__(
> +                       "mrc    p15, 4, %0, c15, c0, 0\n\t"
> +                       : "=r" (base));
> +       return base;
> +}
> +
> +#ifdef CONFIG_SMP
> +static inline void exit_coherency(void)
> +{
> +       unsigned int v;
> +       asm volatile (
> +               "mrc    p15, 0, %0, c1, c0, 1\n"
> +               "bic    %0, %0, %1\n"
> +               "mcr    p15, 0, %0, c1, c0, 1\n"
> +                : "=&r" (v)
> +                : "Ir" (0x40)
> +                : );

The above line gives compilation error with my toolchain.
Adding it as           : "cc");   fixes the error.


> +}
> +#else
> +static inline void exit_coherency(void) { }
> +#endif
> +
> +extern void default_sleep(void);
> +extern void sr_suspend(void *);
> +extern void sr_resume(void *, int);
> +extern void disable_clean_inv_dcache_v7_all(void);
> diff --git a/arch/arm/kernel/sr_platform.c b/arch/arm/kernel/sr_platform.c
> new file mode 100644
> index 0000000..530aa1b
> --- /dev/null
> +++ b/arch/arm/kernel/sr_platform.c
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (C) 2008-2011 ARM Limited
> + *
> + * Author(s): Jon Callan, Lorenzo Pieralisi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <asm/memory.h>
> +#include <asm/page.h>
> +#include <asm/sr_platform_api.h>
> +#include "sr.h"
> +
> +void *context_memory_uncached;
> +
> +/*
> + * Simple memory allocator function.
> + * Returns start address of allocated region
> + * Memory is zero-initialized.
> + */
> +
> +static unsigned int watermark;
> +
> +void *get_memory(unsigned int size)
> +{
> +       unsigned ret;
> +       void *vmem = NULL;
> +
> +       ret = watermark;
> +       watermark += size;
> +       BUG_ON(watermark >= CONTEXT_SPACE_UNCACHED);
> +       vmem = (context_memory_uncached + ret);
> +       watermark = ALIGN(watermark, sizeof(long long));
> +
> +       return vmem;
> +}
> +
> +int  sr_platform_init(void)
> +{
> +       memset(context_memory_uncached, 0, CONTEXT_SPACE_UNCACHED);
> +       return arch->init();
> +}
> diff --git a/arch/arm/kernel/sr_power.c b/arch/arm/kernel/sr_power.c
> new file mode 100644
> index 0000000..2585559
> --- /dev/null
> +++ b/arch/arm/kernel/sr_power.c
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright (C) 2008-2011 ARM Limited
> + *
> + * Author(s): Jon Callan, Lorenzo Pieralisi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include "sr.h"
> +
> +int sr_platform_enter_cstate(unsigned cpu_index,
> +                              struct sr_cpu *cpu,
> +                              struct sr_cluster *cluster)
> +{
> +       return arch->enter_cstate(cpu_index, cpu, cluster);
> +}
> +
> +int sr_platform_leave_cstate(unsigned cpu_index,
> +                              struct sr_cpu *cpu,
> +                              struct sr_cluster *cluster)
> +{
> +       return arch->leave_cstate(cpu_index, cpu, cluster);
> +}
> --
> 1.7.4.4
>
>



More information about the linux-arm-kernel mailing list