From e942ce81fb8d18ecbbba3ebf8b6a98048e7cfe0b Mon Sep 17 00:00:00 2001 From: Gary King Date: Tue, 23 Mar 2010 19:15:12 -0700 Subject: arm tegra: update platsmp to follow kernel code style squash hotplug code into platsmp file, to limit overall spaghettiness Change-Id: I6704323837ad545564a0dcfd47894835f2adeb1a Reviewed-on: http://git-master/r/948 Reviewed-by: Gary King Tested-by: Gary King --- arch/arm/mach-tegra/Makefile | 5 +- arch/arm/mach-tegra/hotplug.c | 49 ------ arch/arm/mach-tegra/platsmp.c | 355 ++++++++++++++++-------------------------- 3 files changed, 131 insertions(+), 278 deletions(-) delete mode 100644 arch/arm/mach-tegra/hotplug.c diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 5b4c352e0d4e..7116e76c5263 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -27,6 +27,7 @@ obj-y += tegra_exports.o # Linux CPU frequency scaling interface obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o # Dynamic voltage and frequency scaling support obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += idle-t2.o @@ -38,13 +39,9 @@ obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -# CPU hotplug support -ifeq ($(CONFIG_HOTPLUG_CPU),y) -obj-y += hotplug.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += power-t2.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += power-context-t2.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += power-lp.o -endif # System DMA obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c deleted file mode 100644 index efda7b72d762..000000000000 --- a/arch/arm/mach-tegra/hotplug.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * arch/arm/mach-tegra/hotplug.c - * - * CPU hotplug support for Tegra SoCs - * - * Copyright (c) 2009, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include - - -static DECLARE_COMPLETION(cpu_killed); - -extern void cpu_ap20_do_lp2(void); - -int platform_cpu_kill(unsigned int cpu) -{ - return wait_for_completion_timeout(&cpu_killed, 5000); -} - -void platform_cpu_die(unsigned int cpu) -{ - flush_cache_all(); - preempt_enable_no_resched(); - complete(&cpu_killed); - cpu_ap20_do_lp2(); -} - -int mach_cpu_disable(unsigned int cpu) -{ - return (cpu==0) ? -EPERM : 0; -} diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index bea6c3e176cc..3bd0300dc9b3 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -3,7 +3,7 @@ * * SMP management routines for SMP Tegra SoCs * - * Copyright (c) 2009, NVIDIA Corporation. + * Copyright (c) 2010, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,259 +24,164 @@ #include #include #include - -#include "mach/nvrm_linux.h" -#include "nvrm_module.h" -#include "nvrm_init.h" -#include "nvrm_drf.h" -#include "nvrm_hardware_access.h" -#include "nvcommon.h" -#include "ap20/arscu.h" -#include "ap20/arevp.h" -#include "ap20/arclk_rst.h" -#include "ap20/arfic_proc_if.h" -#include "ap20/arflow_ctlr.h" +#include +#include static DEFINE_SPINLOCK(boot_lock); - extern void exit_lp2(void); +extern void tegra_secondary_startup(void); + +#define SCU_CONTROL_0 0x0 +#define SCU_CONFIG_0 0x4 + +#define EVP_CPU_RESET_VECTOR_0 0x100 + +/* takes cpu out of reset */ +#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR_0 0x344 +#define CPU_RESET(cpu) (0x1011ul<<(cpu)) + +/* used as mask to enable clock to cpu */ +#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 0x4c +#define CPU_CLK_STOP(cpu) (0x1<<(8+cpu)) -static inline volatile NvU8 *TegraScuAddress(void) +/* write 0 to take cpu out of flow controlled state */ +#define FLOW_CTRL_HALT_CPUx_EVENTS(cpu) ((cpu)?((cpu-1)*0x8 + 0x14) : 0x0) + +static DECLARE_BITMAP(cpu_init_bits, CONFIG_NR_CPUS) __read_mostly; +const struct cpumask *const cpu_init_mask = to_cpumask(cpu_init_bits); +#define cpu_init_map (*(cpumask_t *)cpu_init_mask) + +static u32 orig_reset; + +void platform_secondary_init(unsigned int cpu) { - NvRmPhysAddr Pa; - NvU32 Len; - volatile NvU8 *pScu = NULL; - NvRmModuleGetBaseAddress(s_hRmGlobal, - NVRM_MODULE_ID(NvRmPrivModuleID_ArmPerif, 0), &Pa, &Len); - - if (Pa==0xffffffffUL || !Len) { - printk("TegraSMP: No SCU present\n"); - return NULL; - } - - NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE, - NvOsMemAttribute_Uncached, (void**)&pScu); - return pScu; + if (cpumask_test_cpu(cpu, cpu_init_mask)) + return; + + trace_hardirqs_off(); + spin_lock(&boot_lock); + cpu_set(cpu, cpu_init_map); + spin_unlock(&boot_lock); + + gic_cpu_init(0, IO_ADDRESS(TEGRA_GIC_PROC_IF_BASE)); } -#if 0 -#define TegraCoreCount() 1 -#else -static unsigned int __init TegraCoreCount(void) +void __init smp_init_cpus() { - volatile NvU8 *pScu = TegraScuAddress(); - unsigned int Cores = 1; - if (pScu) { - Cores = NV_READ32(pScu + SCU_CONFIG_0); - Cores = NV_DRF_VAL(SCU, CONFIG, CPU_NUM, Cores) + 1; - } - - if (Cores>NR_CPUS) { - printk("TegraSMP: Kernel configured for fewer NR_CPUS than hardware\n"); - Cores = NR_CPUS; - } - return Cores; + unsigned int cfg; + unsigned int cpus; + void __iomem *evp = IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE); + + cfg = __raw_readl(IO_ADDRESS(TEGRA_SCU_BASE) + SCU_CONFIG_0); + + cpus = min_t(unsigned int, NR_CPUS, (cfg & 3) + 1); + + while (cpus--) + cpu_set(cpus, cpu_possible_map); + + orig_reset = __raw_readl(evp + EVP_CPU_RESET_VECTOR_0); } -#endif -void platform_secondary_init(unsigned int cpu) +void __init smp_prepare_cpus(unsigned int max) { - NvRmPhysAddr Pa; - NvU32 Len; - volatile NvU8* pArm = NULL; - static unsigned int first_init = 1; - - if (first_init == 0) - return; - - trace_hardirqs_off(); - - spin_lock(&boot_lock); - spin_unlock(&boot_lock); - - NvRmModuleGetBaseAddress(s_hRmGlobal, - NVRM_MODULE_ID(NvRmPrivModuleID_ArmPerif,0), &Pa, &Len); - BUG_ON(Pa==-1UL || !Len); - NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE, - NvOsMemAttribute_Uncached, (void**)&pArm); - BUG_ON(!pArm); - - gic_cpu_init(0, (void __iomem*)pArm + FIC_PROC_IF_CONTROL_0); - - first_init = 0; + unsigned int cpu; + + smp_store_cpu_info(smp_processor_id()); + for_each_possible_cpu(cpu) + cpu_set(cpu, cpu_present_map); + + if (num_present_cpus()>1) { + u32 ctrl; + + percpu_timer_setup(); + ctrl = __raw_readl(IO_ADDRESS(TEGRA_SCU_BASE) + SCU_CONTROL_0); + ctrl |= 1; + __raw_writel(ctrl, IO_ADDRESS(TEGRA_SCU_BASE) + SCU_CONTROL_0); + } } -void __init smp_init_cpus(void) +static inline void bwritel(unsigned long v, void __iomem *a) { - unsigned int i; - unsigned int Cores = TegraCoreCount(); - - for (i=0; i 1) - { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); + if (r==boot) { + pr_err("failed to initialize CPU %u\n", cpu); + return -EIO; + } - NvU32 v = NV_READ32(pScu + SCU_CONTROL_0); - v = NV_FLD_SET_DRF_NUM(SCU, CONTROL, SCU_ENABLE, 1, v); - NV_WRITE32(pScu + SCU_CONTROL_0, v); - } + return 0; } -#define CHECK_ADDR(P,L,N) \ - do { \ - if ((P)==-1UL || !(L)) \ - { \ - printk("TegraSMP: No %s module present\n", #N); \ - return -ENOSYS; \ - } \ - } while (0); +#ifdef CONFIG_HOTPLUG_CPU -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static DECLARE_COMPLETION(cpu_killed); +extern void cpu_ap20_do_lp2(void); + +int platform_cpu_kill(unsigned int cpu) { - volatile NvU8 *pEvp = NULL; - volatile NvU8 *pFlowCtrl = NULL; - volatile NvU8 *pClkRst = NULL; - NvUPtr BootFunc; - NvRmPhysAddr Pa; - NvU32 Len; - NvU32 HaltAddr; - NvU32 ResetVal; - NvU32 ClkEnable; - NvU32 OldReset; - NvU32 v, Msg; - extern void tegra_secondary_startup(void); -#ifdef CONFIG_HOTPLUG_CPU - extern void TegraHotplugStartup(void); - static NvU32 EnabledCores = 0; -#endif - unsigned long timeout; - - spin_lock(&boot_lock); - - /* Map exception vector, flow controller and clock & reset module */ - NvRmModuleGetBaseAddress(s_hRmGlobal, - NVRM_MODULE_ID(NvRmModuleID_ExceptionVector, 0), &Pa, &Len); - CHECK_ADDR(Pa, Len, EVP); - NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE, - NvOsMemAttribute_Uncached, (void**)&pEvp); - NvRmModuleGetBaseAddress(s_hRmGlobal, - NVRM_MODULE_ID(NvRmModuleID_FlowCtrl, 0), &Pa, &Len); - CHECK_ADDR(Pa, Len, FlowCtrl); - NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE, - NvOsMemAttribute_Uncached, (void**)&pFlowCtrl); - NvRmModuleGetBaseAddress(s_hRmGlobal, - NVRM_MODULE_ID(NvRmPrivModuleID_ClockAndReset,0), &Pa, &Len); - CHECK_ADDR(Pa, Len, ClockReset); - NvRmPhysicalMemMap(Pa, Len, NVOS_MEM_READ_WRITE, - NvOsMemAttribute_Uncached, (void**)&pClkRst); - - if (!pClkRst || !pFlowCtrl || !pEvp) - { - printk("TegraSMP: Unable to map necessary modules for SMP start-up\n"); - return -ENOSYS; - } - - ResetVal = - NV_DRF_NUM(CLK_RST_CONTROLLER, RST_CPU_CMPLX_CLR, CLR_CPURESET0, 1)| - NV_DRF_NUM(CLK_RST_CONTROLLER, RST_CPU_CMPLX_CLR, CLR_DBGRESET0, 1)| - NV_DRF_NUM(CLK_RST_CONTROLLER, RST_CPU_CMPLX_CLR, CLR_DERESET0, 1); - ResetVal <<= cpu; - - switch (cpu) { - case 0: - // Kernel should never call this, since master CPU will always be up - HaltAddr = FLOW_CTLR_HALT_CPU_EVENTS_0; - ClkEnable = - ~NV_DRF_NUM(CLK_RST_CONTROLLER, CLK_CPU_CMPLX, CPU0_CLK_STP, 1); - break; - case 1: - HaltAddr = FLOW_CTLR_HALT_CPU1_EVENTS_0; - ClkEnable = - ~NV_DRF_NUM(CLK_RST_CONTROLLER, CLK_CPU_CMPLX, CPU1_CLK_STP, 1); - break; - default: - panic("Unsupported cpu ID: %u\n", cpu); - } + return wait_for_completion_timeout(&cpu_killed, 5000); +} -#ifdef CONFIG_HOTPLUG_CPU - if (EnabledCores & (1<