From 63dafe5728e7354bc3f15bd49f13f1f9a433e8fb Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Sat, 14 Jan 2006 16:57:39 -0600 Subject: [PATCH] powerpc: Updated Initial MPC8540 ADS port with OF Flat Dev Updated patch for support for mpc8540_ads in arch/powerpc with a flat OF device tree. This patch does not yet support PCI or I2C. Signed-off-by: Becky Bruce Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/Kconfig') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index df338c5cc91..8aa39d073df 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -121,6 +121,12 @@ config PPC_83xx select 83xx select PPC_FPU +config PPC_85xx + bool "Freescale 85xx" + select E500 + select FSL_SOC + select 85xx + config 40x bool "AMCC 40x" @@ -133,8 +139,6 @@ config 8xx config E200 bool "Freescale e200" -config E500 - bool "Freescale e500" endchoice config POWER4_ONLY @@ -162,6 +166,13 @@ config 6xx config 83xx bool +# this is temp to handle compat with arch=ppc +config 85xx + bool + +config E500 + bool + config PPC_FPU bool default y if PPC64 @@ -211,6 +222,7 @@ config ALTIVEC config SPE bool "SPE Support" depends on E200 || E500 + default y ---help--- This option enables kernel support for the Signal Processing Extensions (SPE) to the PowerPC processor. The kernel currently @@ -728,13 +740,12 @@ config GENERIC_ISA_DMA config PPC_I8259 bool - default y if 85xx default n config PPC_INDIRECT_PCI bool depends on PCI - default y if 40x || 44x || 85xx + default y if 40x || 44x default n config EISA @@ -751,8 +762,8 @@ config MCA bool config PCI - bool "PCI support" if 40x || CPM2 || PPC_83xx || 85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) - default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !85xx + bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) + default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx && !PPC_85xx default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS default PCI_QSPAN if !4xx && !CPM2 && 8xx help -- cgit v1.2.3-70-g09d2 From f4fc4a5b74cff2a487222f05704a2bd01953d250 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 16 Jan 2006 10:53:22 -0600 Subject: [PATCH] powerpc: Add CONFIG_DEFAULT_UIMAGE to build a uImage by default for a board Embedded boards that u-boot require a kernel image in the uImage format. This allows a given board to specify it wants a uImage built by default. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 6 ++++++ arch/powerpc/Makefile | 1 + 2 files changed, 7 insertions(+) (limited to 'arch/powerpc/Kconfig') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 8aa39d073df..fb0dcb994b8 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -83,6 +83,12 @@ config GENERIC_TBSYNC default y if PPC32 && SMP default n +config DEFAULT_UIMAGE + bool + help + Used to allow a board to specify it wants a uImage built by default + default n + menu "Processor support" choice prompt "Processor Type" diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 44dd82b791d..15fc3e98ac5 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -142,6 +142,7 @@ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ # Default to zImage, override when needed defaultimage-y := zImage defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux +defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage KBUILD_IMAGE := $(defaultimage-y) all: $(KBUILD_IMAGE) -- cgit v1.2.3-70-g09d2 From c6622f63db86fcbd41bf6fe05ddf2e00c1e51ced Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 24 Feb 2006 10:06:59 +1100 Subject: powerpc: Implement accurate task and CPU time accounting This implements accurate task and cpu time accounting for 64-bit powerpc kernels. Instead of accounting a whole jiffy of time to a task on a timer interrupt because that task happened to be running at the time, we now account time in units of timebase ticks according to the actual time spent by the task in user mode and kernel mode. We also count the time spent processing hardware and software interrupts accurately. This is conditional on CONFIG_VIRT_CPU_ACCOUNTING. If that is not set, we do tick-based approximate accounting as before. To get this accurate information, we read either the PURR (processor utilization of resources register) on POWER5 machines, or the timebase on other machines on * each entry to the kernel from usermode * each exit to usermode * transitions between process context, hard irq context and soft irq context in kernel mode * context switches. On POWER5 systems with shared-processor logical partitioning we also read both the PURR and the timebase at each timer interrupt and context switch in order to determine how much time has been taken by the hypervisor to run other partitions ("steal" time). Unfortunately, since we need values of the PURR on both threads at the same time to accurately calculate the steal time, and since we can only calculate steal time on a per-core basis, the apportioning of the steal time between idle time (time which we ceded to the hypervisor in the idle loop) and actual stolen time is somewhat approximate at the moment. This is all based quite heavily on what s390 does, and it uses the generic interfaces that were added by the s390 developers, i.e. account_system_time(), account_user_time(), etc. This patch doesn't add any new interfaces between the kernel and userspace, and doesn't change the units in which time is reported to userspace by things such as /proc/stat, /proc//stat, getrusage(), times(), etc. Internally the various task and cpu times are stored in timebase units, but they are converted to USER_HZ units (1/100th of a second) when reported to userspace. Some precision is therefore lost but there should not be any accumulating error, since the internal accumulation is at full precision. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 15 +++ arch/powerpc/kernel/asm-offsets.c | 3 + arch/powerpc/kernel/entry_64.S | 7 +- arch/powerpc/kernel/head_64.S | 9 ++ arch/powerpc/kernel/irq.c | 30 +++-- arch/powerpc/kernel/process.c | 7 +- arch/powerpc/kernel/smp.c | 4 +- arch/powerpc/kernel/time.c | 236 +++++++++++++++++++++++++++++++++++++- include/asm-powerpc/cputable.h | 4 +- include/asm-powerpc/cputime.h | 202 ++++++++++++++++++++++++++++++++ include/asm-powerpc/irq.h | 6 +- include/asm-powerpc/paca.h | 5 + include/asm-powerpc/ppc_asm.h | 42 +++++++ include/asm-powerpc/system.h | 4 + include/asm-powerpc/time.h | 15 +++ include/asm-ppc/time.h | 5 + 16 files changed, 577 insertions(+), 17 deletions(-) (limited to 'arch/powerpc/Kconfig') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index fb0dcb994b8..d112aed2999 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -250,6 +250,21 @@ config PPC_STD_MMU_32 def_bool y depends on PPC_STD_MMU && PPC32 +config VIRT_CPU_ACCOUNTING + bool "Deterministic task and CPU time accounting" + depends on PPC64 + default y + help + Select this option to enable more accurate task and CPU time + accounting. This is done by reading a CPU counter on each + kernel entry and exit and on transitions within the kernel + between system, softirq and hardirq state, so there is a + small performance impact. This also enables accounting of + stolen time on logically-partitioned systems running on + IBM POWER5-based machines. + + If in doubt, say Y here. + config SMP depends on PPC_STD_MMU bool "Symmetric multi-processing support" diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 840aad43a98..18810ac55bc 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -137,6 +137,9 @@ int main(void) DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); DEFINE(PACALPPACAPTR, offsetof(struct paca_struct, lppaca_ptr)); DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); + DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr)); + DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time)); + DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0)); DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 79a0c910f0d..8f606c1889f 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -61,6 +61,7 @@ system_call_common: std r12,_MSR(r1) std r0,GPR0(r1) std r10,GPR1(r1) + ACCOUNT_CPU_USER_ENTRY(r10, r11) std r2,GPR2(r1) std r3,GPR3(r1) std r4,GPR4(r1) @@ -168,8 +169,9 @@ syscall_error_cont: stdcx. r0,0,r1 /* to clear the reservation */ andi. r6,r8,MSR_PR ld r4,_LINK(r1) - beq- 1f /* only restore r13 if */ - ld r13,GPR13(r1) /* returning to usermode */ + beq- 1f + ACCOUNT_CPU_USER_EXIT(r11, r12) + ld r13,GPR13(r1) /* only restore r13 if returning to usermode */ 1: ld r2,GPR2(r1) li r12,MSR_RI andc r11,r10,r12 @@ -536,6 +538,7 @@ restore: * userspace */ beq 1f + ACCOUNT_CPU_USER_EXIT(r3, r4) REST_GPR(13, r1) 1: ld r3,_CTR(r1) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 2b21ec49928..be3ae773357 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -277,6 +277,7 @@ exception_marker: std r10,0(r1); /* make stack chain pointer */ \ std r0,GPR0(r1); /* save r0 in stackframe */ \ std r10,GPR1(r1); /* save r1 in stackframe */ \ + ACCOUNT_CPU_USER_ENTRY(r9, r10); \ std r2,GPR2(r1); /* save r2 in stackframe */ \ SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ @@ -844,6 +845,14 @@ fast_exception_return: ld r11,_NIP(r1) andi. r3,r12,MSR_RI /* check if RI is set */ beq- unrecov_fer + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + andi. r3,r12,MSR_PR + beq 2f + ACCOUNT_CPU_USER_EXIT(r3, r4) +2: +#endif + ld r3,_CCR(r1) ld r4,_LINK(r1) ld r5,_CTR(r1) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index edb2b00edbd..24dc8117b82 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -369,6 +369,7 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq) return NO_IRQ; } +#endif /* CONFIG_PPC64 */ #ifdef CONFIG_IRQSTACKS struct thread_info *softirq_ctx[NR_CPUS]; @@ -392,10 +393,24 @@ void irq_ctx_init(void) } } +static inline void do_softirq_onstack(void) +{ + struct thread_info *curtp, *irqtp; + + curtp = current_thread_info(); + irqtp = softirq_ctx[smp_processor_id()]; + irqtp->task = curtp->task; + call_do_softirq(irqtp); + irqtp->task = NULL; +} + +#else +#define do_softirq_onstack() __do_softirq() +#endif /* CONFIG_IRQSTACKS */ + void do_softirq(void) { unsigned long flags; - struct thread_info *curtp, *irqtp; if (in_interrupt()) return; @@ -403,19 +418,18 @@ void do_softirq(void) local_irq_save(flags); if (local_softirq_pending()) { - curtp = current_thread_info(); - irqtp = softirq_ctx[smp_processor_id()]; - irqtp->task = curtp->task; - call_do_softirq(irqtp); - irqtp->task = NULL; + account_system_vtime(current); + local_bh_disable(); + do_softirq_onstack(); + account_system_vtime(current); + __local_bh_enable(); } local_irq_restore(flags); } EXPORT_SYMBOL(do_softirq); -#endif /* CONFIG_IRQSTACKS */ - +#ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { distribute_irqs = 0; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index dd774c3c930..1770a066c21 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -45,9 +45,9 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include -#include #endif extern unsigned long _get_SP(void); @@ -328,6 +328,11 @@ struct task_struct *__switch_to(struct task_struct *prev, #endif local_irq_save(flags); + + account_system_vtime(current); + account_process_vtime(current); + calculate_steal_time(); + last = _switch(old_thread, new_thread); local_irq_restore(flags); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 13595a64f01..805eaedbc30 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -541,7 +541,7 @@ int __devinit start_secondary(void *unused) smp_ops->take_timebase(); if (system_state > SYSTEM_BOOTING) - per_cpu(last_jiffy, cpu) = get_tb(); + snapshot_timebase(); spin_lock(&call_lock); cpu_set(cpu, cpu_online_map); @@ -573,6 +573,8 @@ void __init smp_cpus_done(unsigned int max_cpus) set_cpus_allowed(current, old_mask); + snapshot_timebases(); + dump_numa_cpu_topology(); } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 2a7ddc57937..0b34db28916 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -135,6 +136,220 @@ unsigned long tb_last_stamp; */ DEFINE_PER_CPU(unsigned long, last_jiffy); +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +/* + * Factors for converting from cputime_t (timebase ticks) to + * jiffies, milliseconds, seconds, and clock_t (1/USER_HZ seconds). + * These are all stored as 0.64 fixed-point binary fractions. + */ +u64 __cputime_jiffies_factor; +u64 __cputime_msec_factor; +u64 __cputime_sec_factor; +u64 __cputime_clockt_factor; + +static void calc_cputime_factors(void) +{ + struct div_result res; + + div128_by_32(HZ, 0, tb_ticks_per_sec, &res); + __cputime_jiffies_factor = res.result_low; + div128_by_32(1000, 0, tb_ticks_per_sec, &res); + __cputime_msec_factor = res.result_low; + div128_by_32(1, 0, tb_ticks_per_sec, &res); + __cputime_sec_factor = res.result_low; + div128_by_32(USER_HZ, 0, tb_ticks_per_sec, &res); + __cputime_clockt_factor = res.result_low; +} + +/* + * Read the PURR on systems that have it, otherwise the timebase. + */ +static u64 read_purr(void) +{ + if (cpu_has_feature(CPU_FTR_PURR)) + return mfspr(SPRN_PURR); + return mftb(); +} + +/* + * Account time for a transition between system, hard irq + * or soft irq state. + */ +void account_system_vtime(struct task_struct *tsk) +{ + u64 now, delta; + unsigned long flags; + + local_irq_save(flags); + now = read_purr(); + delta = now - get_paca()->startpurr; + get_paca()->startpurr = now; + if (!in_interrupt()) { + delta += get_paca()->system_time; + get_paca()->system_time = 0; + } + account_system_time(tsk, 0, delta); + local_irq_restore(flags); +} + +/* + * Transfer the user and system times accumulated in the paca + * by the exception entry and exit code to the generic process + * user and system time records. + * Must be called with interrupts disabled. + */ +void account_process_vtime(struct task_struct *tsk) +{ + cputime_t utime; + + utime = get_paca()->user_time; + get_paca()->user_time = 0; + account_user_time(tsk, utime); +} + +static void account_process_time(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + account_process_vtime(current); + run_local_timers(); + if (rcu_pending(cpu)) + rcu_check_callbacks(cpu, user_mode(regs)); + scheduler_tick(); + run_posix_cpu_timers(current); +} + +#ifdef CONFIG_PPC_SPLPAR +/* + * Stuff for accounting stolen time. + */ +struct cpu_purr_data { + int initialized; /* thread is running */ + u64 tb0; /* timebase at origin time */ + u64 purr0; /* PURR at origin time */ + u64 tb; /* last TB value read */ + u64 purr; /* last PURR value read */ + u64 stolen; /* stolen time so far */ + spinlock_t lock; +}; + +static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data); + +static void snapshot_tb_and_purr(void *data) +{ + struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); + + p->tb0 = mftb(); + p->purr0 = mfspr(SPRN_PURR); + p->tb = p->tb0; + p->purr = 0; + wmb(); + p->initialized = 1; +} + +/* + * Called during boot when all cpus have come up. + */ +void snapshot_timebases(void) +{ + int cpu; + + if (!cpu_has_feature(CPU_FTR_PURR)) + return; + for_each_cpu(cpu) + spin_lock_init(&per_cpu(cpu_purr_data, cpu).lock); + on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1); +} + +void calculate_steal_time(void) +{ + u64 tb, purr, t0; + s64 stolen; + struct cpu_purr_data *p0, *pme, *phim; + int cpu; + + if (!cpu_has_feature(CPU_FTR_PURR)) + return; + cpu = smp_processor_id(); + pme = &per_cpu(cpu_purr_data, cpu); + if (!pme->initialized) + return; /* this can happen in early boot */ + p0 = &per_cpu(cpu_purr_data, cpu & ~1); + phim = &per_cpu(cpu_purr_data, cpu ^ 1); + spin_lock(&p0->lock); + tb = mftb(); + purr = mfspr(SPRN_PURR) - pme->purr0; + if (!phim->initialized || !cpu_online(cpu ^ 1)) { + stolen = (tb - pme->tb) - (purr - pme->purr); + } else { + t0 = pme->tb0; + if (phim->tb0 < t0) + t0 = phim->tb0; + stolen = phim->tb - t0 - phim->purr - purr - p0->stolen; + } + if (stolen > 0) { + account_steal_time(current, stolen); + p0->stolen += stolen; + } + pme->tb = tb; + pme->purr = purr; + spin_unlock(&p0->lock); +} + +/* + * Must be called before the cpu is added to the online map when + * a cpu is being brought up at runtime. + */ +static void snapshot_purr(void) +{ + int cpu; + u64 purr; + struct cpu_purr_data *p0, *pme, *phim; + unsigned long flags; + + if (!cpu_has_feature(CPU_FTR_PURR)) + return; + cpu = smp_processor_id(); + pme = &per_cpu(cpu_purr_data, cpu); + p0 = &per_cpu(cpu_purr_data, cpu & ~1); + phim = &per_cpu(cpu_purr_data, cpu ^ 1); + spin_lock_irqsave(&p0->lock, flags); + pme->tb = pme->tb0 = mftb(); + purr = mfspr(SPRN_PURR); + if (!phim->initialized) { + pme->purr = 0; + pme->purr0 = purr; + } else { + /* set p->purr and p->purr0 for no change in p0->stolen */ + pme->purr = phim->tb - phim->tb0 - phim->purr - p0->stolen; + pme->purr0 = purr - pme->purr; + } + pme->initialized = 1; + spin_unlock_irqrestore(&p0->lock, flags); +} + +#endif /* CONFIG_PPC_SPLPAR */ + +#else /* ! CONFIG_VIRT_CPU_ACCOUNTING */ +#define calc_cputime_factors() +#define account_process_time(regs) update_process_times(user_mode(regs)) +#define calculate_steal_time() do { } while (0) +#endif + +#if !(defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)) +#define snapshot_purr() do { } while (0) +#endif + +/* + * Called when a cpu comes up after the system has finished booting, + * i.e. as a result of a hotplug cpu action. + */ +void snapshot_timebase(void) +{ + __get_cpu_var(last_jiffy) = get_tb(); + snapshot_purr(); +} + void __delay(unsigned long loops) { unsigned long start; @@ -382,6 +597,7 @@ static void iSeries_tb_recal(void) new_tb_ticks_per_jiffy, sign, tick_diff ); tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; tb_ticks_per_sec = new_tb_ticks_per_sec; + calc_cputime_factors(); div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres ); do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; tb_to_xs = divres.result_low; @@ -430,6 +646,7 @@ void timer_interrupt(struct pt_regs * regs) irq_enter(); profile_tick(CPU_PROFILING, regs); + calculate_steal_time(); #ifdef CONFIG_PPC_ISERIES get_lppaca()->int_dword.fields.decr_int = 0; @@ -451,7 +668,7 @@ void timer_interrupt(struct pt_regs * regs) * is the case. */ if (!cpu_is_offline(cpu)) - update_process_times(user_mode(regs)); + account_process_time(regs); /* * No need to check whether cpu is offline here; boot_cpuid @@ -508,13 +725,27 @@ void wakeup_decrementer(void) void __init smp_space_timers(unsigned int max_cpus) { int i; + unsigned long half = tb_ticks_per_jiffy / 2; unsigned long offset = tb_ticks_per_jiffy / max_cpus; unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid); /* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */ previous_tb -= tb_ticks_per_jiffy; + /* + * The stolen time calculation for POWER5 shared-processor LPAR + * systems works better if the two threads' timebase interrupts + * are staggered by half a jiffy with respect to each other. + */ for_each_cpu(i) { - if (i != boot_cpuid) { + if (i == boot_cpuid) + continue; + if (i == (boot_cpuid ^ 1)) + per_cpu(last_jiffy, i) = + per_cpu(last_jiffy, boot_cpuid) - half; + else if (i & 1) + per_cpu(last_jiffy, i) = + per_cpu(last_jiffy, i ^ 1) + half; + else { previous_tb += offset; per_cpu(last_jiffy, i) = previous_tb; } @@ -706,6 +937,7 @@ void __init time_init(void) tb_ticks_per_sec = ppc_tb_freq; tb_ticks_per_usec = ppc_tb_freq / 1000000; tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); + calc_cputime_factors(); /* * Calculate the length of each tick in ns. It will not be diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 90d005bb4d1..99d12ff6346 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -117,6 +117,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000) #define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000) #define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000) +#define CPU_FTR_PURR ASM_CONST(0x0000400000000000) #else /* ensure on 32b processors the flags are available for compiling but * don't do anything */ @@ -132,6 +133,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0) #define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0) #define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0) +#define CPU_FTR_PURR ASM_CONST(0x0) #endif #ifndef __ASSEMBLY__ @@ -316,7 +318,7 @@ enum { CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | - CPU_FTR_MMCRA_SIHV, + CPU_FTR_MMCRA_SIHV | CPU_FTR_PURR, CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | diff --git a/include/asm-powerpc/cputime.h b/include/asm-powerpc/cputime.h index 6d68ad7e0ea..a21185d4788 100644 --- a/include/asm-powerpc/cputime.h +++ b/include/asm-powerpc/cputime.h @@ -1 +1,203 @@ +/* + * Definitions for measuring cputime on powerpc machines. + * + * Copyright (C) 2006 Paul Mackerras, IBM Corp. + * + * 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. + * + * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in + * the same units as the timebase. Otherwise we measure cpu time + * in jiffies using the generic definitions. + */ + +#ifndef __POWERPC_CPUTIME_H +#define __POWERPC_CPUTIME_H + +#ifndef CONFIG_VIRT_CPU_ACCOUNTING #include +#else + +#include +#include +#include +#include +#include + +typedef u64 cputime_t; +typedef u64 cputime64_t; + +#define cputime_zero ((cputime_t)0) +#define cputime_max ((~((cputime_t)0) >> 1) - 1) +#define cputime_add(__a, __b) ((__a) + (__b)) +#define cputime_sub(__a, __b) ((__a) - (__b)) +#define cputime_div(__a, __n) ((__a) / (__n)) +#define cputime_halve(__a) ((__a) >> 1) +#define cputime_eq(__a, __b) ((__a) == (__b)) +#define cputime_gt(__a, __b) ((__a) > (__b)) +#define cputime_ge(__a, __b) ((__a) >= (__b)) +#define cputime_lt(__a, __b) ((__a) < (__b)) +#define cputime_le(__a, __b) ((__a) <= (__b)) + +#define cputime64_zero ((cputime64_t)0) +#define cputime64_add(__a, __b) ((__a) + (__b)) +#define cputime_to_cputime64(__ct) (__ct) + +#ifdef __KERNEL__ + +/* + * Convert cputime <-> jiffies + */ +extern u64 __cputime_jiffies_factor; + +static inline unsigned long cputime_to_jiffies(const cputime_t ct) +{ + return mulhdu(ct, __cputime_jiffies_factor); +} + +static inline cputime_t jiffies_to_cputime(const unsigned long jif) +{ + cputime_t ct; + unsigned long sec; + + /* have to be a little careful about overflow */ + ct = jif % HZ; + sec = jif / HZ; + if (ct) { + ct *= tb_ticks_per_sec; + do_div(ct, HZ); + } + if (sec) + ct += (cputime_t) sec * tb_ticks_per_sec; + return ct; +} + +static inline u64 cputime64_to_jiffies64(const cputime_t ct) +{ + return mulhdu(ct, __cputime_jiffies_factor); +} + +/* + * Convert cputime <-> milliseconds + */ +extern u64 __cputime_msec_factor; + +static inline unsigned long cputime_to_msecs(const cputime_t ct) +{ + return mulhdu(ct, __cputime_msec_factor); +} + +static inline cputime_t msecs_to_cputime(const unsigned long ms) +{ + cputime_t ct; + unsigned long sec; + + /* have to be a little careful about overflow */ + ct = ms % 1000; + sec = ms / 1000; + if (ct) { + ct *= tb_ticks_per_sec; + do_div(ct, 1000); + } + if (sec) + ct += (cputime_t) sec * tb_ticks_per_sec; + return ct; +} + +/* + * Convert cputime <-> seconds + */ +extern u64 __cputime_sec_factor; + +static inline unsigned long cputime_to_secs(const cputime_t ct) +{ + return mulhdu(ct, __cputime_sec_factor); +} + +static inline cputime_t secs_to_cputime(const unsigned long sec) +{ + return (cputime_t) sec * tb_ticks_per_sec; +} + +/* + * Convert cputime <-> timespec + */ +static inline void cputime_to_timespec(const cputime_t ct, struct timespec *p) +{ + u64 x = ct; + unsigned int frac; + + frac = do_div(x, tb_ticks_per_sec); + p->tv_sec = x; + x = (u64) frac * 1000000000; + do_div(x, tb_ticks_per_sec); + p->tv_nsec = x; +} + +static inline cputime_t timespec_to_cputime(const struct timespec *p) +{ + cputime_t ct; + + ct = (u64) p->tv_nsec * tb_ticks_per_sec; + do_div(ct, 1000000000); + return ct + (u64) p->tv_sec * tb_ticks_per_sec; +} + +/* + * Convert cputime <-> timeval + */ +static inline void cputime_to_timeval(const cputime_t ct, struct timeval *p) +{ + u64 x = ct; + unsigned int frac; + + frac = do_div(x, tb_ticks_per_sec); + p->tv_sec = x; + x = (u64) frac * 1000000; + do_div(x, tb_ticks_per_sec); + p->tv_usec = x; +} + +static inline cputime_t timeval_to_cputime(const struct timeval *p) +{ + cputime_t ct; + + ct = (u64) p->tv_usec * tb_ticks_per_sec; + do_div(ct, 1000000); + return ct + (u64) p->tv_sec * tb_ticks_per_sec; +} + +/* + * Convert cputime <-> clock_t (units of 1/USER_HZ seconds) + */ +extern u64 __cputime_clockt_factor; + +static inline unsigned long cputime_to_clock_t(const cputime_t ct) +{ + return mulhdu(ct, __cputime_clockt_factor); +} + +static inline cputime_t clock_t_to_cputime(const unsigned long clk) +{ + cputime_t ct; + unsigned long sec; + + /* have to be a little careful about overflow */ + ct = clk % USER_HZ; + sec = clk / USER_HZ; + if (ct) { + ct *= tb_ticks_per_sec; + do_div(ct, USER_HZ); + } + if (sec) + ct += (cputime_t) sec * tb_ticks_per_sec; + return ct; +} + +#define cputime64_to_clock_t(ct) cputime_to_clock_t((cputime_t)(ct)) + +#endif /* __KERNEL__ */ +#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ +#endif /* __POWERPC_CPUTIME_H */ diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 8eb7e857ec4..51f87d9993b 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -479,6 +479,10 @@ extern int distribute_irqs; struct irqaction; struct pt_regs; +#define __ARCH_HAS_DO_SOFTIRQ + +extern void __do_softirq(void); + #ifdef CONFIG_IRQSTACKS /* * Per-cpu stacks for handling hard and soft interrupts. @@ -491,8 +495,6 @@ extern void call_do_softirq(struct thread_info *tp); extern int call___do_IRQ(int irq, struct pt_regs *regs, struct thread_info *tp); -#define __ARCH_HAS_DO_SOFTIRQ - #else #define irq_ctx_init() diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index ec94b51074f..4465b95ebef 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -96,6 +96,11 @@ struct paca_struct { u64 saved_r1; /* r1 save for RTAS calls */ u64 saved_msr; /* MSR saved here by enter_rtas */ u8 proc_enabled; /* irq soft-enable flag */ + + /* Stuff for accurate time accounting */ + u64 user_time; /* accumulated usermode TB ticks */ + u64 system_time; /* accumulated system TB ticks */ + u64 startpurr; /* PURR/TB value snapshot */ }; extern struct paca_struct paca[]; diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index ab8688d3902..dd1c0a913d5 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -14,6 +14,48 @@ #define SZL (BITS_PER_LONG/8) +/* + * Stuff for accurate CPU time accounting. + * These macros handle transitions between user and system state + * in exception entry and exit and accumulate time to the + * user_time and system_time fields in the paca. + */ + +#ifndef CONFIG_VIRT_CPU_ACCOUNTING +#define ACCOUNT_CPU_USER_ENTRY(ra, rb) +#define ACCOUNT_CPU_USER_EXIT(ra, rb) +#else +#define ACCOUNT_CPU_USER_ENTRY(ra, rb) \ + beq 2f; /* if from kernel mode */ \ +BEGIN_FTR_SECTION; \ + mfspr ra,SPRN_PURR; /* get processor util. reg */ \ +END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ +BEGIN_FTR_SECTION; \ + mftb ra; /* or get TB if no PURR */ \ +END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \ + ld rb,PACA_STARTPURR(r13); \ + std ra,PACA_STARTPURR(r13); \ + subf rb,rb,ra; /* subtract start value */ \ + ld ra,PACA_USER_TIME(r13); \ + add ra,ra,rb; /* add on to user time */ \ + std ra,PACA_USER_TIME(r13); \ +2: + +#define ACCOUNT_CPU_USER_EXIT(ra, rb) \ +BEGIN_FTR_SECTION; \ + mfspr ra,SPRN_PURR; /* get processor util. reg */ \ +END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ +BEGIN_FTR_SECTION; \ + mftb ra; /* or get TB if no PURR */ \ +END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \ + ld rb,PACA_STARTPURR(r13); \ + std ra,PACA_STARTPURR(r13); \ + subf rb,rb,ra; /* subtract start value */ \ + ld ra,PACA_SYSTEM_TIME(r13); \ + add ra,ra,rb; /* add on to user time */ \ + std ra,PACA_SYSTEM_TIME(r13); +#endif + /* * Macros for storing registers into and loading registers from * exception frames. diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index d9bf53653b1..41b7a5b3d70 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -424,5 +424,9 @@ static inline void create_function_call(unsigned long addr, void * func) create_branch(addr, func_addr, BRANCH_SET_LINK); } +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +extern void account_system_vtime(struct task_struct *); +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SYSTEM_H */ diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index baddc9ab57a..912118db13a 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -41,6 +41,7 @@ extern time_t last_rtc_update; extern void generic_calibrate_decr(void); extern void wakeup_decrementer(void); +extern void snapshot_timebase(void); /* Some sane defaults: 125 MHz timebase, 1GHz processor */ extern unsigned long ppc_proc_freq; @@ -221,5 +222,19 @@ struct cpu_usage { DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +extern void account_process_vtime(struct task_struct *tsk); +#else +#define account_process_vtime(tsk) do { } while (0) +#endif + +#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR) +extern void calculate_steal_time(void); +extern void snapshot_timebases(void); +#else +#define calculate_steal_time() do { } while (0) +#define snapshot_timebases() do { } while (0) +#endif + #endif /* __KERNEL__ */ #endif /* __PPC64_TIME_H */ diff --git a/include/asm-ppc/time.h b/include/asm-ppc/time.h index 321fb75b5f2..c86112323c9 100644 --- a/include/asm-ppc/time.h +++ b/include/asm-ppc/time.h @@ -153,5 +153,10 @@ extern __inline__ unsigned binary_tbl(void) { ({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) unsigned mulhwu_scale_factor(unsigned, unsigned); + +#define account_process_vtime(tsk) do { } while (0) +#define calculate_steal_time() do { } while (0) +#define snapshot_timebases() do { } while (0) + #endif /* __ASM_TIME_H__ */ #endif /* __KERNEL__ */ -- cgit v1.2.3-70-g09d2 From cd9c99d7e5f75e137c2ea0cf693773d63c8d945c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 10 Mar 2006 15:01:08 +1100 Subject: [PATCH] powerpc: Clarify wording for CRASH_DUMP Kconfig option The wording of the CRASH_DUMP Kconfig option is not very clear. It gives you a kernel that can be used _as_ the kdump kernel, not a kernel that can boot into a kdump kernel. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/Kconfig') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a834f9e0bbb..dfba81719de 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -580,7 +580,7 @@ config KEXEC strongly in flux, so no good recommendation can be made. config CRASH_DUMP - bool "kernel crash dumps (EXPERIMENTAL)" + bool "Build a kdump crash kernel (EXPERIMENTAL)" depends on PPC_MULTIPLATFORM && PPC64 && EXPERIMENTAL help Build a kernel suitable for use as a kdump capture kernel. -- cgit v1.2.3-70-g09d2 From e779b2f95f3786cd9cfc804cd6f04f7267d75541 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 26 Mar 2006 01:39:33 -0800 Subject: [PATCH] bitops: powerpc: use generic bitops - remove __{,test_and_}{set,clear,change}_bit() and test_bit() - remove generic_fls64() - remove generic_hweight{64,32,16,8}() - remove sched_find_first_bit() Signed-off-by: Akinobu Mita Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/Kconfig | 4 ++ include/asm-powerpc/bitops.h | 105 ++----------------------------------------- 2 files changed, 8 insertions(+), 101 deletions(-) (limited to 'arch/powerpc/Kconfig') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index fae42da7468..a433b7126d3 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -37,6 +37,10 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config GENERIC_HWEIGHT + bool + default y + config GENERIC_CALIBRATE_DELAY bool default y diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h index bf6941a810b..d1c2a440566 100644 --- a/include/asm-powerpc/bitops.h +++ b/include/asm-powerpc/bitops.h @@ -184,72 +184,7 @@ static __inline__ void set_bits(unsigned long mask, unsigned long *addr) : "cc"); } -/* Non-atomic versions */ -static __inline__ int test_bit(unsigned long nr, - __const__ volatile unsigned long *addr) -{ - return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); -} - -static __inline__ void __set_bit(unsigned long nr, - volatile unsigned long *addr) -{ - unsigned long mask = BITOP_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); - - *p |= mask; -} - -static __inline__ void __clear_bit(unsigned long nr, - volatile unsigned long *addr) -{ - unsigned long mask = BITOP_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); - - *p &= ~mask; -} - -static __inline__ void __change_bit(unsigned long nr, - volatile unsigned long *addr) -{ - unsigned long mask = BITOP_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); - - *p ^= mask; -} - -static __inline__ int __test_and_set_bit(unsigned long nr, - volatile unsigned long *addr) -{ - unsigned long mask = BITOP_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); - unsigned long old = *p; - - *p = old | mask; - return (old & mask) != 0; -} - -static __inline__ int __test_and_clear_bit(unsigned long nr, - volatile unsigned long *addr) -{ - unsigned long mask = BITOP_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); - unsigned long old = *p; - - *p = old & ~mask; - return (old & mask) != 0; -} - -static __inline__ int __test_and_change_bit(unsigned long nr, - volatile unsigned long *addr) -{ - unsigned long mask = BITOP_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); - unsigned long old = *p; - - *p = old ^ mask; - return (old & mask) != 0; -} +#include /* * Return the zero-based bit position (LE, not IBM bit numbering) of @@ -310,16 +245,9 @@ static __inline__ int fls(unsigned int x) asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); return 32 - lz; } -#define fls64(x) generic_fls64(x) +#include -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ -#define hweight64(x) generic_hweight64(x) -#define hweight32(x) generic_hweight32(x) -#define hweight16(x) generic_hweight16(x) -#define hweight8(x) generic_hweight8(x) +#include #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) unsigned long find_next_zero_bit(const unsigned long *addr, @@ -397,32 +325,7 @@ unsigned long find_next_zero_le_bit(const unsigned long *addr, #define minix_find_first_zero_bit(addr,size) \ find_first_zero_le_bit((unsigned long *)addr, size) -/* - * Every architecture must define this function. It's the fastest - * way of searching a 140-bit bitmap where the first 100 bits are - * unlikely to be set. It's guaranteed that at least one of the 140 - * bits is cleared. - */ -static inline int sched_find_first_bit(const unsigned long *b) -{ -#ifdef CONFIG_PPC64 - if (unlikely(b[0])) - return __ffs(b[0]); - if (unlikely(b[1])) - return __ffs(b[1]) + 64; - return __ffs(b[2]) + 128; -#else - if (unlikely(b[0])) - return __ffs(b[0]); - if (unlikely(b[1])) - return __ffs(b[1]) + 32; - if (unlikely(b[2])) - return __ffs(b[2]) + 64; - if (b[3]) - return __ffs(b[3]) + 96; - return __ffs(b[4]) + 128; -#endif -} +#include #endif /* __KERNEL__ */ -- cgit v1.2.3-70-g09d2 From 9b781727fd1062671afa144b93e8c69b14bcac4d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 27 Mar 2006 19:15:26 +1100 Subject: powerpc: Move cpu_setup_6xx.S and temp.c over to arch/powerpc Also renamed temp.c to tau_6xx.c (for thermal assist unit) and updated the Kconfig option description and help text for CONFIG_TAU. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 4 +- arch/powerpc/kernel/Makefile | 3 +- arch/powerpc/kernel/cpu_setup_6xx.S | 474 ++++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/tau_6xx.c | 271 +++++++++++++++++++++ arch/ppc/kernel/Makefile | 4 - arch/ppc/kernel/cpu_setup_6xx.S | 474 ------------------------------------ arch/ppc/kernel/temp.c | 271 --------------------- 7 files changed, 749 insertions(+), 752 deletions(-) create mode 100644 arch/powerpc/kernel/cpu_setup_6xx.S create mode 100644 arch/powerpc/kernel/tau_6xx.c delete mode 100644 arch/ppc/kernel/cpu_setup_6xx.S delete mode 100644 arch/ppc/kernel/temp.c (limited to 'arch/powerpc/Kconfig') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a433b7126d3..2cdc35ce804 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -491,7 +491,7 @@ config PPC601_SYNC_FIX If in doubt, say Y here. config TAU - bool "Thermal Management Support" + bool "On-chip CPU temperature sensor support" depends on 6xx help G3 and G4 processors have an on-chip temperature sensor called the @@ -500,7 +500,7 @@ config TAU on-die temperature in /proc/cpuinfo if the cpu supports it. Unfortunately, on some chip revisions, this sensor is very inaccurate - and in some cases, does not work at all, so don't assume the cpu + and in many cases, does not work at all, so don't assume the cpu temp is actually what /proc/cpuinfo says it is. config TAU_INT diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index e7fddf1e42c..754c227835b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -34,7 +34,8 @@ obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o +obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o +obj-$(CONFIG_TAU) += tau_6xx.o ifeq ($(CONFIG_PPC_MERGE),y) diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S new file mode 100644 index 00000000000..55ed7716636 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_6xx.S @@ -0,0 +1,474 @@ +/* + * This file contains low level CPU setup functions. + * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +_GLOBAL(__setup_cpu_603) + b setup_common_caches +_GLOBAL(__setup_cpu_604) + mflr r4 + bl setup_common_caches + bl setup_604_hid0 + mtlr r4 + blr +_GLOBAL(__setup_cpu_750) + mflr r4 + bl __init_fpu_registers + bl setup_common_caches + bl setup_750_7400_hid0 + mtlr r4 + blr +_GLOBAL(__setup_cpu_750cx) + mflr r4 + bl __init_fpu_registers + bl setup_common_caches + bl setup_750_7400_hid0 + bl setup_750cx + mtlr r4 + blr +_GLOBAL(__setup_cpu_750fx) + mflr r4 + bl __init_fpu_registers + bl setup_common_caches + bl setup_750_7400_hid0 + bl setup_750fx + mtlr r4 + blr +_GLOBAL(__setup_cpu_7400) + mflr r4 + bl __init_fpu_registers + bl setup_7400_workarounds + bl setup_common_caches + bl setup_750_7400_hid0 + mtlr r4 + blr +_GLOBAL(__setup_cpu_7410) + mflr r4 + bl __init_fpu_registers + bl setup_7410_workarounds + bl setup_common_caches + bl setup_750_7400_hid0 + li r3,0 + mtspr SPRN_L2CR2,r3 + mtlr r4 + blr +_GLOBAL(__setup_cpu_745x) + mflr r4 + bl setup_common_caches + bl setup_745x_specifics + mtlr r4 + blr + +/* Enable caches for 603's, 604, 750 & 7400 */ +setup_common_caches: + mfspr r11,SPRN_HID0 + andi. r0,r11,HID0_DCE + ori r11,r11,HID0_ICE|HID0_DCE + ori r8,r11,HID0_ICFI + bne 1f /* don't invalidate the D-cache */ + ori r8,r8,HID0_DCI /* unless it wasn't enabled */ +1: sync + mtspr SPRN_HID0,r8 /* enable and invalidate caches */ + sync + mtspr SPRN_HID0,r11 /* enable caches */ + sync + isync + blr + +/* 604, 604e, 604ev, ... + * Enable superscalar execution & branch history table + */ +setup_604_hid0: + mfspr r11,SPRN_HID0 + ori r11,r11,HID0_SIED|HID0_BHTE + ori r8,r11,HID0_BTCD + sync + mtspr SPRN_HID0,r8 /* flush branch target address cache */ + sync /* on 604e/604r */ + mtspr SPRN_HID0,r11 + sync + isync + blr + +/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some + * erratas we work around here. + * Moto MPC710CE.pdf describes them, those are errata + * #3, #4 and #5 + * Note that we assume the firmware didn't choose to + * apply other workarounds (there are other ones documented + * in the .pdf). It appear that Apple firmware only works + * around #3 and with the same fix we use. We may want to + * check if the CPU is using 60x bus mode in which case + * the workaround for errata #4 is useless. Also, we may + * want to explicitely clear HID0_NOPDST as this is not + * needed once we have applied workaround #5 (though it's + * not set by Apple's firmware at least). + */ +setup_7400_workarounds: + mfpvr r3 + rlwinm r3,r3,0,20,31 + cmpwi 0,r3,0x0207 + ble 1f + blr +setup_7410_workarounds: + mfpvr r3 + rlwinm r3,r3,0,20,31 + cmpwi 0,r3,0x0100 + bnelr +1: + mfspr r11,SPRN_MSSSR0 + /* Errata #3: Set L1OPQ_SIZE to 0x10 */ + rlwinm r11,r11,0,9,6 + oris r11,r11,0x0100 + /* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */ + oris r11,r11,0x0002 + /* Errata #5: Set DRLT_SIZE to 0x01 */ + rlwinm r11,r11,0,5,2 + oris r11,r11,0x0800 + sync + mtspr SPRN_MSSSR0,r11 + sync + isync + blr + +/* 740/750/7400/7410 + * Enable Store Gathering (SGE), Address Brodcast (ABE), + * Branch History Table (BHTE), Branch Target ICache (BTIC) + * Dynamic Power Management (DPM), Speculative (SPD) + * Clear Instruction cache throttling (ICTC) + */ +setup_750_7400_hid0: + mfspr r11,SPRN_HID0 + ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h +BEGIN_FTR_SECTION + xori r11,r11,HID0_BTIC +END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) +BEGIN_FTR_SECTION + xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */ +END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM) + li r3,HID0_SPD + andc r11,r11,r3 /* clear SPD: enable speculative */ + li r3,0 + mtspr SPRN_ICTC,r3 /* Instruction Cache Throttling off */ + isync + mtspr SPRN_HID0,r11 + sync + isync + blr + +/* 750cx specific + * Looks like we have to disable NAP feature for some PLL settings... + * (waiting for confirmation) + */ +setup_750cx: + mfspr r10, SPRN_HID1 + rlwinm r10,r10,4,28,31 + cmpwi cr0,r10,7 + cmpwi cr1,r10,9 + cmpwi cr2,r10,11 + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + cror 4*cr0+eq,4*cr0+eq,4*cr2+eq + bnelr + lwz r6,CPU_SPEC_FEATURES(r5) + li r7,CPU_FTR_CAN_NAP + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) + blr + +/* 750fx specific + */ +setup_750fx: + blr + +/* MPC 745x + * Enable Store Gathering (SGE), Branch Folding (FOLD) + * Branch History Table (BHTE), Branch Target ICache (BTIC) + * Dynamic Power Management (DPM), Speculative (SPD) + * Ensure our data cache instructions really operate. + * Timebase has to be running or we wouldn't have made it here, + * just ensure we don't disable it. + * Clear Instruction cache throttling (ICTC) + * Enable L2 HW prefetch + */ +setup_745x_specifics: + /* We check for the presence of an L3 cache setup by + * the firmware. If any, we disable NAP capability as + * it's known to be bogus on rev 2.1 and earlier + */ + mfspr r11,SPRN_L3CR + andis. r11,r11,L3CR_L3E@h + beq 1f + lwz r6,CPU_SPEC_FEATURES(r5) + andi. r0,r6,CPU_FTR_L3_DISABLE_NAP + beq 1f + li r7,CPU_FTR_CAN_NAP + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) +1: + mfspr r11,SPRN_HID0 + + /* All of the bits we have to set..... + */ + ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE + ori r11,r11,HID0_LRSTK | HID0_BTIC + oris r11,r11,HID0_DPM@h +BEGIN_FTR_SECTION + xori r11,r11,HID0_BTIC +END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) +BEGIN_FTR_SECTION + xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */ +END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM) + + /* All of the bits we have to clear.... + */ + li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI + andc r11,r11,r3 /* clear SPD: enable speculative */ + li r3,0 + + mtspr SPRN_ICTC,r3 /* Instruction Cache Throttling off */ + isync + mtspr SPRN_HID0,r11 + sync + isync + + /* Enable L2 HW prefetch, if L2 is enabled + */ + mfspr r3,SPRN_L2CR + andis. r3,r3,L2CR_L2E@h + beqlr + mfspr r3,SPRN_MSSCR0 + ori r3,r3,3 + sync + mtspr SPRN_MSSCR0,r3 + sync + isync + blr + +/* + * Initialize the FPU registers. This is needed to work around an errata + * in some 750 cpus where using a not yet initialized FPU register after + * power on reset may hang the CPU + */ +_GLOBAL(__init_fpu_registers) + mfmsr r10 + ori r11,r10,MSR_FP + mtmsr r11 + isync + addis r9,r3,empty_zero_page@ha + addi r9,r9,empty_zero_page@l + REST_32FPRS(0,r9) + sync + mtmsr r10 + isync + blr + + +/* Definitions for the table use to save CPU states */ +#define CS_HID0 0 +#define CS_HID1 4 +#define CS_HID2 8 +#define CS_MSSCR0 12 +#define CS_MSSSR0 16 +#define CS_ICTRL 20 +#define CS_LDSTCR 24 +#define CS_LDSTDB 28 +#define CS_SIZE 32 + + .data + .balign L1_CACHE_BYTES +cpu_state_storage: + .space CS_SIZE + .balign L1_CACHE_BYTES,0 + .text + +/* Called in normal context to backup CPU 0 state. This + * does not include cache settings. This function is also + * called for machine sleep. This does not include the MMU + * setup, BATs, etc... but rather the "special" registers + * like HID0, HID1, MSSCR0, etc... + */ +_GLOBAL(__save_cpu_setup) + /* Some CR fields are volatile, we back it up all */ + mfcr r7 + + /* Get storage ptr */ + lis r5,cpu_state_storage@h + ori r5,r5,cpu_state_storage@l + + /* Save HID0 (common to all CONFIG_6xx cpus) */ + mfspr r3,SPRN_HID0 + stw r3,CS_HID0(r5) + + /* Now deal with CPU type dependent registers */ + mfspr r3,SPRN_PVR + srwi r3,r3,16 + cmplwi cr0,r3,0x8000 /* 7450 */ + cmplwi cr1,r3,0x000c /* 7400 */ + cmplwi cr2,r3,0x800c /* 7410 */ + cmplwi cr3,r3,0x8001 /* 7455 */ + cmplwi cr4,r3,0x8002 /* 7457 */ + cmplwi cr5,r3,0x8003 /* 7447A */ + cmplwi cr6,r3,0x7000 /* 750FX */ + cmplwi cr7,r3,0x8004 /* 7448 */ + /* cr1 is 7400 || 7410 */ + cror 4*cr1+eq,4*cr1+eq,4*cr2+eq + /* cr0 is 74xx */ + cror 4*cr0+eq,4*cr0+eq,4*cr3+eq + cror 4*cr0+eq,4*cr0+eq,4*cr4+eq + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + cror 4*cr0+eq,4*cr0+eq,4*cr5+eq + cror 4*cr0+eq,4*cr0+eq,4*cr7+eq + bne 1f + /* Backup 74xx specific regs */ + mfspr r4,SPRN_MSSCR0 + stw r4,CS_MSSCR0(r5) + mfspr r4,SPRN_MSSSR0 + stw r4,CS_MSSSR0(r5) + beq cr1,1f + /* Backup 745x specific registers */ + mfspr r4,SPRN_HID1 + stw r4,CS_HID1(r5) + mfspr r4,SPRN_ICTRL + stw r4,CS_ICTRL(r5) + mfspr r4,SPRN_LDSTCR + stw r4,CS_LDSTCR(r5) + mfspr r4,SPRN_LDSTDB + stw r4,CS_LDSTDB(r5) +1: + bne cr6,1f + /* Backup 750FX specific registers */ + mfspr r4,SPRN_HID1 + stw r4,CS_HID1(r5) + /* If rev 2.x, backup HID2 */ + mfspr r3,SPRN_PVR + andi. r3,r3,0xff00 + cmpwi cr0,r3,0x0200 + bne 1f + mfspr r4,SPRN_HID2 + stw r4,CS_HID2(r5) +1: + mtcr r7 + blr + +/* Called with no MMU context (typically MSR:IR/DR off) to + * restore CPU state as backed up by the previous + * function. This does not include cache setting + */ +_GLOBAL(__restore_cpu_setup) + /* Some CR fields are volatile, we back it up all */ + mfcr r7 + + /* Get storage ptr */ + lis r5,(cpu_state_storage-KERNELBASE)@h + ori r5,r5,cpu_state_storage@l + + /* Restore HID0 */ + lwz r3,CS_HID0(r5) + sync + isync + mtspr SPRN_HID0,r3 + sync + isync + + /* Now deal with CPU type dependent registers */ + mfspr r3,SPRN_PVR + srwi r3,r3,16 + cmplwi cr0,r3,0x8000 /* 7450 */ + cmplwi cr1,r3,0x000c /* 7400 */ + cmplwi cr2,r3,0x800c /* 7410 */ + cmplwi cr3,r3,0x8001 /* 7455 */ + cmplwi cr4,r3,0x8002 /* 7457 */ + cmplwi cr5,r3,0x8003 /* 7447A */ + cmplwi cr6,r3,0x7000 /* 750FX */ + cmplwi cr7,r3,0x8004 /* 7448 */ + /* cr1 is 7400 || 7410 */ + cror 4*cr1+eq,4*cr1+eq,4*cr2+eq + /* cr0 is 74xx */ + cror 4*cr0+eq,4*cr0+eq,4*cr3+eq + cror 4*cr0+eq,4*cr0+eq,4*cr4+eq + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + cror 4*cr0+eq,4*cr0+eq,4*cr5+eq + cror 4*cr0+eq,4*cr0+eq,4*cr7+eq + bne 2f + /* Restore 74xx specific regs */ + lwz r4,CS_MSSCR0(r5) + sync + mtspr SPRN_MSSCR0,r4 + sync + isync + lwz r4,CS_MSSSR0(r5) + sync + mtspr SPRN_MSSSR0,r4 + sync + isync + bne cr2,1f + /* Clear 7410 L2CR2 */ + li r4,0 + mtspr SPRN_L2CR2,r4 +1: beq cr1,2f + /* Restore 745x specific registers */ + lwz r4,CS_HID1(r5) + sync + mtspr SPRN_HID1,r4 + isync + sync + lwz r4,CS_ICTRL(r5) + sync + mtspr SPRN_ICTRL,r4 + isync + sync + lwz r4,CS_LDSTCR(r5) + sync + mtspr SPRN_LDSTCR,r4 + isync + sync + lwz r4,CS_LDSTDB(r5) + sync + mtspr SPRN_LDSTDB,r4 + isync + sync +2: bne cr6,1f + /* Restore 750FX specific registers + * that is restore HID2 on rev 2.x and PLL config & switch + * to PLL 0 on all + */ + /* If rev 2.x, restore HID2 with low voltage bit cleared */ + mfspr r3,SPRN_PVR + andi. r3,r3,0xff00 + cmpwi cr0,r3,0x0200 + bne 4f + lwz r4,CS_HID2(r5) + rlwinm r4,r4,0,19,17 + mtspr SPRN_HID2,r4 + sync +4: + lwz r4,CS_HID1(r5) + rlwinm r5,r4,0,16,14 + mtspr SPRN_HID1,r5 + /* Wait for PLL to stabilize */ + mftbl r5 +3: mftbl r6 + sub r6,r6,r5 + cmplwi cr0,r6,10000 + ble 3b + /* Setup final PLL */ + mtspr SPRN_HID1,r4 +1: + mtcr r7 + blr + diff --git a/arch/powerpc/kernel/tau_6xx.c b/arch/powerpc/kernel/tau_6xx.c new file mode 100644 index 00000000000..26bd8ea35a4 --- /dev/null +++ b/arch/powerpc/kernel/tau_6xx.c @@ -0,0 +1,271 @@ +/* + * temp.c Thermal management for cpu's with Thermal Assist Units + * + * Written by Troy Benjegerdes + * + * TODO: + * dynamic power management to limit peak CPU temp (using ICTC) + * calibration??? + * + * Silly, crazy ideas: use cpu load (from scheduler) and ICTC to extend battery + * life in portables, and add a 'performance/watt' metric somewhere in /proc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static struct tau_temp +{ + int interrupts; + unsigned char low; + unsigned char high; + unsigned char grew; +} tau[NR_CPUS]; + +struct timer_list tau_timer; + +#undef DEBUG + +/* TODO: put these in a /proc interface, with some sanity checks, and maybe + * dynamic adjustment to minimize # of interrupts */ +/* configurable values for step size and how much to expand the window when + * we get an interrupt. These are based on the limit that was out of range */ +#define step_size 2 /* step size when temp goes out of range */ +#define window_expand 1 /* expand the window by this much */ +/* configurable values for shrinking the window */ +#define shrink_timer 2*HZ /* period between shrinking the window */ +#define min_window 2 /* minimum window size, degrees C */ + +void set_thresholds(unsigned long cpu) +{ +#ifdef CONFIG_TAU_INT + /* + * setup THRM1, + * threshold, valid bit, enable interrupts, interrupt when below threshold + */ + mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID); + + /* setup THRM2, + * threshold, valid bit, enable interrupts, interrupt when above threshhold + */ + mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE); +#else + /* same thing but don't enable interrupts */ + mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TID); + mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V); +#endif +} + +void TAUupdate(int cpu) +{ + unsigned thrm; + +#ifdef DEBUG + printk("TAUupdate "); +#endif + + /* if both thresholds are crossed, the step_sizes cancel out + * and the window winds up getting expanded twice. */ + if((thrm = mfspr(SPRN_THRM1)) & THRM1_TIV){ /* is valid? */ + if(thrm & THRM1_TIN){ /* crossed low threshold */ + if (tau[cpu].low >= step_size){ + tau[cpu].low -= step_size; + tau[cpu].high -= (step_size - window_expand); + } + tau[cpu].grew = 1; +#ifdef DEBUG + printk("low threshold crossed "); +#endif + } + } + if((thrm = mfspr(SPRN_THRM2)) & THRM1_TIV){ /* is valid? */ + if(thrm & THRM1_TIN){ /* crossed high threshold */ + if (tau[cpu].high <= 127-step_size){ + tau[cpu].low += (step_size - window_expand); + tau[cpu].high += step_size; + } + tau[cpu].grew = 1; +#ifdef DEBUG + printk("high threshold crossed "); +#endif + } + } + +#ifdef DEBUG + printk("grew = %d\n", tau[cpu].grew); +#endif + +#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */ + set_thresholds(cpu); +#endif + +} + +#ifdef CONFIG_TAU_INT +/* + * TAU interrupts - called when we have a thermal assist unit interrupt + * with interrupts disabled + */ + +void TAUException(struct pt_regs * regs) +{ + int cpu = smp_processor_id(); + + irq_enter(); + tau[cpu].interrupts++; + + TAUupdate(cpu); + + irq_exit(); +} +#endif /* CONFIG_TAU_INT */ + +static void tau_timeout(void * info) +{ + int cpu; + unsigned long flags; + int size; + int shrink; + + /* disabling interrupts *should* be okay */ + local_irq_save(flags); + cpu = smp_processor_id(); + +#ifndef CONFIG_TAU_INT + TAUupdate(cpu); +#endif + + size = tau[cpu].high - tau[cpu].low; + if (size > min_window && ! tau[cpu].grew) { + /* do an exponential shrink of half the amount currently over size */ + shrink = (2 + size - min_window) / 4; + if (shrink) { + tau[cpu].low += shrink; + tau[cpu].high -= shrink; + } else { /* size must have been min_window + 1 */ + tau[cpu].low += 1; +#if 1 /* debug */ + if ((tau[cpu].high - tau[cpu].low) != min_window){ + printk(KERN_ERR "temp.c: line %d, logic error\n", __LINE__); + } +#endif + } + } + + tau[cpu].grew = 0; + + set_thresholds(cpu); + + /* + * Do the enable every time, since otherwise a bunch of (relatively) + * complex sleep code needs to be added. One mtspr every time + * tau_timeout is called is probably not a big deal. + * + * Enable thermal sensor and set up sample interval timer + * need 20 us to do the compare.. until a nice 'cpu_speed' function + * call is implemented, just assume a 500 mhz clock. It doesn't really + * matter if we take too long for a compare since it's all interrupt + * driven anyway. + * + * use a extra long time.. (60 us @ 500 mhz) + */ + mtspr(SPRN_THRM3, THRM3_SITV(500*60) | THRM3_E); + + local_irq_restore(flags); +} + +static void tau_timeout_smp(unsigned long unused) +{ + + /* schedule ourselves to be run again */ + mod_timer(&tau_timer, jiffies + shrink_timer) ; + on_each_cpu(tau_timeout, NULL, 1, 0); +} + +/* + * setup the TAU + * + * Set things up to use THRM1 as a temperature lower bound, and THRM2 as an upper bound. + * Start off at zero + */ + +int tau_initialized = 0; + +void __init TAU_init_smp(void * info) +{ + unsigned long cpu = smp_processor_id(); + + /* set these to a reasonable value and let the timer shrink the + * window */ + tau[cpu].low = 5; + tau[cpu].high = 120; + + set_thresholds(cpu); +} + +int __init TAU_init(void) +{ + /* We assume in SMP that if one CPU has TAU support, they + * all have it --BenH + */ + if (!cpu_has_feature(CPU_FTR_TAU)) { + printk("Thermal assist unit not available\n"); + tau_initialized = 0; + return 1; + } + + + /* first, set up the window shrinking timer */ + init_timer(&tau_timer); + tau_timer.function = tau_timeout_smp; + tau_timer.expires = jiffies + shrink_timer; + add_timer(&tau_timer); + + on_each_cpu(TAU_init_smp, NULL, 1, 0); + + printk("Thermal assist unit "); +#ifdef CONFIG_TAU_INT + printk("using interrupts, "); +#else + printk("using timers, "); +#endif + printk("shrink_timer: %d jiffies\n", shrink_timer); + tau_initialized = 1; + + return 0; +} + +__initcall(TAU_init); + +/* + * return current temp + */ + +u32 cpu_temp_both(unsigned long cpu) +{ + return ((tau[cpu].high << 16) | tau[cpu].low); +} + +int cpu_temp(unsigned long cpu) +{ + return ((tau[cpu].high + tau[cpu].low) / 2); +} + +int tau_interrupts(unsigned long cpu) +{ + return (tau[cpu].interrupts); +} diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 3d50a268683..d6a4863d4e7 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -13,7 +13,6 @@ extra-y += vmlinux.lds obj-y := entry.o traps.o time.o misc.o \ setup.o \ ppc_htab.o -obj-$(CONFIG_6xx) += cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o @@ -21,7 +20,6 @@ obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_RAPIDIO) += rio.o obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o -obj-$(CONFIG_TAU) += temp.o ifndef CONFIG_E200 obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o endif @@ -34,12 +32,10 @@ endif # These are here while we do the architecture merge else -obj-$(CONFIG_6xx) += cpu_setup_6xx.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o obj-$(CONFIG_KGDB) += ppc-stub.o -obj-$(CONFIG_TAU) += temp.o ifndef CONFIG_E200 obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o endif diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S deleted file mode 100644 index 55ed7716636..00000000000 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ /dev/null @@ -1,474 +0,0 @@ -/* - * This file contains low level CPU setup functions. - * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -_GLOBAL(__setup_cpu_603) - b setup_common_caches -_GLOBAL(__setup_cpu_604) - mflr r4 - bl setup_common_caches - bl setup_604_hid0 - mtlr r4 - blr -_GLOBAL(__setup_cpu_750) - mflr r4 - bl __init_fpu_registers - bl setup_common_caches - bl setup_750_7400_hid0 - mtlr r4 - blr -_GLOBAL(__setup_cpu_750cx) - mflr r4 - bl __init_fpu_registers - bl setup_common_caches - bl setup_750_7400_hid0 - bl setup_750cx - mtlr r4 - blr -_GLOBAL(__setup_cpu_750fx) - mflr r4 - bl __init_fpu_registers - bl setup_common_caches - bl setup_750_7400_hid0 - bl setup_750fx - mtlr r4 - blr -_GLOBAL(__setup_cpu_7400) - mflr r4 - bl __init_fpu_registers - bl setup_7400_workarounds - bl setup_common_caches - bl setup_750_7400_hid0 - mtlr r4 - blr -_GLOBAL(__setup_cpu_7410) - mflr r4 - bl __init_fpu_registers - bl setup_7410_workarounds - bl setup_common_caches - bl setup_750_7400_hid0 - li r3,0 - mtspr SPRN_L2CR2,r3 - mtlr r4 - blr -_GLOBAL(__setup_cpu_745x) - mflr r4 - bl setup_common_caches - bl setup_745x_specifics - mtlr r4 - blr - -/* Enable caches for 603's, 604, 750 & 7400 */ -setup_common_caches: - mfspr r11,SPRN_HID0 - andi. r0,r11,HID0_DCE - ori r11,r11,HID0_ICE|HID0_DCE - ori r8,r11,HID0_ICFI - bne 1f /* don't invalidate the D-cache */ - ori r8,r8,HID0_DCI /* unless it wasn't enabled */ -1: sync - mtspr SPRN_HID0,r8 /* enable and invalidate caches */ - sync - mtspr SPRN_HID0,r11 /* enable caches */ - sync - isync - blr - -/* 604, 604e, 604ev, ... - * Enable superscalar execution & branch history table - */ -setup_604_hid0: - mfspr r11,SPRN_HID0 - ori r11,r11,HID0_SIED|HID0_BHTE - ori r8,r11,HID0_BTCD - sync - mtspr SPRN_HID0,r8 /* flush branch target address cache */ - sync /* on 604e/604r */ - mtspr SPRN_HID0,r11 - sync - isync - blr - -/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some - * erratas we work around here. - * Moto MPC710CE.pdf describes them, those are errata - * #3, #4 and #5 - * Note that we assume the firmware didn't choose to - * apply other workarounds (there are other ones documented - * in the .pdf). It appear that Apple firmware only works - * around #3 and with the same fix we use. We may want to - * check if the CPU is using 60x bus mode in which case - * the workaround for errata #4 is useless. Also, we may - * want to explicitely clear HID0_NOPDST as this is not - * needed once we have applied workaround #5 (though it's - * not set by Apple's firmware at least). - */ -setup_7400_workarounds: - mfpvr r3 - rlwinm r3,r3,0,20,31 - cmpwi 0,r3,0x0207 - ble 1f - blr -setup_7410_workarounds: - mfpvr r3 - rlwinm r3,r3,0,20,31 - cmpwi 0,r3,0x0100 - bnelr -1: - mfspr r11,SPRN_MSSSR0 - /* Errata #3: Set L1OPQ_SIZE to 0x10 */ - rlwinm r11,r11,0,9,6 - oris r11,r11,0x0100 - /* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */ - oris r11,r11,0x0002 - /* Errata #5: Set DRLT_SIZE to 0x01 */ - rlwinm r11,r11,0,5,2 - oris r11,r11,0x0800 - sync - mtspr SPRN_MSSSR0,r11 - sync - isync - blr - -/* 740/750/7400/7410 - * Enable Store Gathering (SGE), Address Brodcast (ABE), - * Branch History Table (BHTE), Branch Target ICache (BTIC) - * Dynamic Power Management (DPM), Speculative (SPD) - * Clear Instruction cache throttling (ICTC) - */ -setup_750_7400_hid0: - mfspr r11,SPRN_HID0 - ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC - oris r11,r11,HID0_DPM@h -BEGIN_FTR_SECTION - xori r11,r11,HID0_BTIC -END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) -BEGIN_FTR_SECTION - xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */ -END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM) - li r3,HID0_SPD - andc r11,r11,r3 /* clear SPD: enable speculative */ - li r3,0 - mtspr SPRN_ICTC,r3 /* Instruction Cache Throttling off */ - isync - mtspr SPRN_HID0,r11 - sync - isync - blr - -/* 750cx specific - * Looks like we have to disable NAP feature for some PLL settings... - * (waiting for confirmation) - */ -setup_750cx: - mfspr r10, SPRN_HID1 - rlwinm r10,r10,4,28,31 - cmpwi cr0,r10,7 - cmpwi cr1,r10,9 - cmpwi cr2,r10,11 - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - cror 4*cr0+eq,4*cr0+eq,4*cr2+eq - bnelr - lwz r6,CPU_SPEC_FEATURES(r5) - li r7,CPU_FTR_CAN_NAP - andc r6,r6,r7 - stw r6,CPU_SPEC_FEATURES(r5) - blr - -/* 750fx specific - */ -setup_750fx: - blr - -/* MPC 745x - * Enable Store Gathering (SGE), Branch Folding (FOLD) - * Branch History Table (BHTE), Branch Target ICache (BTIC) - * Dynamic Power Management (DPM), Speculative (SPD) - * Ensure our data cache instructions really operate. - * Timebase has to be running or we wouldn't have made it here, - * just ensure we don't disable it. - * Clear Instruction cache throttling (ICTC) - * Enable L2 HW prefetch - */ -setup_745x_specifics: - /* We check for the presence of an L3 cache setup by - * the firmware. If any, we disable NAP capability as - * it's known to be bogus on rev 2.1 and earlier - */ - mfspr r11,SPRN_L3CR - andis. r11,r11,L3CR_L3E@h - beq 1f - lwz r6,CPU_SPEC_FEATURES(r5) - andi. r0,r6,CPU_FTR_L3_DISABLE_NAP - beq 1f - li r7,CPU_FTR_CAN_NAP - andc r6,r6,r7 - stw r6,CPU_SPEC_FEATURES(r5) -1: - mfspr r11,SPRN_HID0 - - /* All of the bits we have to set..... - */ - ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE - ori r11,r11,HID0_LRSTK | HID0_BTIC - oris r11,r11,HID0_DPM@h -BEGIN_FTR_SECTION - xori r11,r11,HID0_BTIC -END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC) -BEGIN_FTR_SECTION - xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */ -END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM) - - /* All of the bits we have to clear.... - */ - li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI - andc r11,r11,r3 /* clear SPD: enable speculative */ - li r3,0 - - mtspr SPRN_ICTC,r3 /* Instruction Cache Throttling off */ - isync - mtspr SPRN_HID0,r11 - sync - isync - - /* Enable L2 HW prefetch, if L2 is enabled - */ - mfspr r3,SPRN_L2CR - andis. r3,r3,L2CR_L2E@h - beqlr - mfspr r3,SPRN_MSSCR0 - ori r3,r3,3 - sync - mtspr SPRN_MSSCR0,r3 - sync - isync - blr - -/* - * Initialize the FPU registers. This is needed to work around an errata - * in some 750 cpus where using a not yet initialized FPU register after - * power on reset may hang the CPU - */ -_GLOBAL(__init_fpu_registers) - mfmsr r10 - ori r11,r10,MSR_FP - mtmsr r11 - isync - addis r9,r3,empty_zero_page@ha - addi r9,r9,empty_zero_page@l - REST_32FPRS(0,r9) - sync - mtmsr r10 - isync - blr - - -/* Definitions for the table use to save CPU states */ -#define CS_HID0 0 -#define CS_HID1 4 -#define CS_HID2 8 -#define CS_MSSCR0 12 -#define CS_MSSSR0 16 -#define CS_ICTRL 20 -#define CS_LDSTCR 24 -#define CS_LDSTDB 28 -#define CS_SIZE 32 - - .data - .balign L1_CACHE_BYTES -cpu_state_storage: - .space CS_SIZE - .balign L1_CACHE_BYTES,0 - .text - -/* Called in normal context to backup CPU 0 state. This - * does not include cache settings. This function is also - * called for machine sleep. This does not include the MMU - * setup, BATs, etc... but rather the "special" registers - * like HID0, HID1, MSSCR0, etc... - */ -_GLOBAL(__save_cpu_setup) - /* Some CR fields are volatile, we back it up all */ - mfcr r7 - - /* Get storage ptr */ - lis r5,cpu_state_storage@h - ori r5,r5,cpu_state_storage@l - - /* Save HID0 (common to all CONFIG_6xx cpus) */ - mfspr r3,SPRN_HID0 - stw r3,CS_HID0(r5) - - /* Now deal with CPU type dependent registers */ - mfspr r3,SPRN_PVR - srwi r3,r3,16 - cmplwi cr0,r3,0x8000 /* 7450 */ - cmplwi cr1,r3,0x000c /* 7400 */ - cmplwi cr2,r3,0x800c /* 7410 */ - cmplwi cr3,r3,0x8001 /* 7455 */ - cmplwi cr4,r3,0x8002 /* 7457 */ - cmplwi cr5,r3,0x8003 /* 7447A */ - cmplwi cr6,r3,0x7000 /* 750FX */ - cmplwi cr7,r3,0x8004 /* 7448 */ - /* cr1 is 7400 || 7410 */ - cror 4*cr1+eq,4*cr1+eq,4*cr2+eq - /* cr0 is 74xx */ - cror 4*cr0+eq,4*cr0+eq,4*cr3+eq - cror 4*cr0+eq,4*cr0+eq,4*cr4+eq - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - cror 4*cr0+eq,4*cr0+eq,4*cr5+eq - cror 4*cr0+eq,4*cr0+eq,4*cr7+eq - bne 1f - /* Backup 74xx specific regs */ - mfspr r4,SPRN_MSSCR0 - stw r4,CS_MSSCR0(r5) - mfspr r4,SPRN_MSSSR0 - stw r4,CS_MSSSR0(r5) - beq cr1,1f - /* Backup 745x specific registers */ - mfspr r4,SPRN_HID1 - stw r4,CS_HID1(r5) - mfspr r4,SPRN_ICTRL - stw r4,CS_ICTRL(r5) - mfspr r4,SPRN_LDSTCR - stw r4,CS_LDSTCR(r5) - mfspr r4,SPRN_LDSTDB - stw r4,CS_LDSTDB(r5) -1: - bne cr6,1f - /* Backup 750FX specific registers */ - mfspr r4,SPRN_HID1 - stw r4,CS_HID1(r5) - /* If rev 2.x, backup HID2 */ - mfspr r3,SPRN_PVR - andi. r3,r3,0xff00 - cmpwi cr0,r3,0x0200 - bne 1f - mfspr r4,SPRN_HID2 - stw r4,CS_HID2(r5) -1: - mtcr r7 - blr - -/* Called with no MMU context (typically MSR:IR/DR off) to - * restore CPU state as backed up by the previous - * function. This does not include cache setting - */ -_GLOBAL(__restore_cpu_setup) - /* Some CR fields are volatile, we back it up all */ - mfcr r7 - - /* Get storage ptr */ - lis r5,(cpu_state_storage-KERNELBASE)@h - ori r5,r5,cpu_state_storage@l - - /* Restore HID0 */ - lwz r3,CS_HID0(r5) - sync - isync - mtspr SPRN_HID0,r3 - sync - isync - - /* Now deal with CPU type dependent registers */ - mfspr r3,SPRN_PVR - srwi r3,r3,16 - cmplwi cr0,r3,0x8000 /* 7450 */ - cmplwi cr1,r3,0x000c /* 7400 */ - cmplwi cr2,r3,0x800c /* 7410 */ - cmplwi cr3,r3,0x8001 /* 7455 */ - cmplwi cr4,r3,0x8002 /* 7457 */ - cmplwi cr5,r3,0x8003 /* 7447A */ - cmplwi cr6,r3,0x7000 /* 750FX */ - cmplwi cr7,r3,0x8004 /* 7448 */ - /* cr1 is 7400 || 7410 */ - cror 4*cr1+eq,4*cr1+eq,4*cr2+eq - /* cr0 is 74xx */ - cror 4*cr0+eq,4*cr0+eq,4*cr3+eq - cror 4*cr0+eq,4*cr0+eq,4*cr4+eq - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - cror 4*cr0+eq,4*cr0+eq,4*cr5+eq - cror 4*cr0+eq,4*cr0+eq,4*cr7+eq - bne 2f - /* Restore 74xx specific regs */ - lwz r4,CS_MSSCR0(r5) - sync - mtspr SPRN_MSSCR0,r4 - sync - isync - lwz r4,CS_MSSSR0(r5) - sync - mtspr SPRN_MSSSR0,r4 - sync - isync - bne cr2,1f - /* Clear 7410 L2CR2 */ - li r4,0 - mtspr SPRN_L2CR2,r4 -1: beq cr1,2f - /* Restore 745x specific registers */ - lwz r4,CS_HID1(r5) - sync - mtspr SPRN_HID1,r4 - isync - sync - lwz r4,CS_ICTRL(r5) - sync - mtspr SPRN_ICTRL,r4 - isync - sync - lwz r4,CS_LDSTCR(r5) - sync - mtspr SPRN_LDSTCR,r4 - isync - sync - lwz r4,CS_LDSTDB(r5) - sync - mtspr SPRN_LDSTDB,r4 - isync - sync -2: bne cr6,1f - /* Restore 750FX specific registers - * that is restore HID2 on rev 2.x and PLL config & switch - * to PLL 0 on all - */ - /* If rev 2.x, restore HID2 with low voltage bit cleared */ - mfspr r3,SPRN_PVR - andi. r3,r3,0xff00 - cmpwi cr0,r3,0x0200 - bne 4f - lwz r4,CS_HID2(r5) - rlwinm r4,r4,0,19,17 - mtspr SPRN_HID2,r4 - sync -4: - lwz r4,CS_HID1(r5) - rlwinm r5,r4,0,16,14 - mtspr SPRN_HID1,r5 - /* Wait for PLL to stabilize */ - mftbl r5 -3: mftbl r6 - sub r6,r6,r5 - cmplwi cr0,r6,10000 - ble 3b - /* Setup final PLL */ - mtspr SPRN_HID1,r4 -1: - mtcr r7 - blr - diff --git a/arch/ppc/kernel/temp.c b/arch/ppc/kernel/temp.c deleted file mode 100644 index 26bd8ea35a4..00000000000 --- a/arch/ppc/kernel/temp.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * temp.c Thermal management for cpu's with Thermal Assist Units - * - * Written by Troy Benjegerdes - * - * TODO: - * dynamic power management to limit peak CPU temp (using ICTC) - * calibration??? - * - * Silly, crazy ideas: use cpu load (from scheduler) and ICTC to extend battery - * life in portables, and add a 'performance/watt' metric somewhere in /proc - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static struct tau_temp -{ - int interrupts; - unsigned char low; - unsigned char high; - unsigned char grew; -} tau[NR_CPUS]; - -struct timer_list tau_timer; - -#undef DEBUG - -/* TODO: put these in a /proc interface, with some sanity checks, and maybe - * dynamic adjustment to minimize # of interrupts */ -/* configurable values for step size and how much to expand the window when - * we get an interrupt. These are based on the limit that was out of range */ -#define step_size 2 /* step size when temp goes out of range */ -#define window_expand 1 /* expand the window by this much */ -/* configurable values for shrinking the window */ -#define shrink_timer 2*HZ /* period between shrinking the window */ -#define min_window 2 /* minimum window size, degrees C */ - -void set_thresholds(unsigned long cpu) -{ -#ifdef CONFIG_TAU_INT - /* - * setup THRM1, - * threshold, valid bit, enable interrupts, interrupt when below threshold - */ - mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID); - - /* setup THRM2, - * threshold, valid bit, enable interrupts, interrupt when above threshhold - */ - mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE); -#else - /* same thing but don't enable interrupts */ - mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TID); - mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V); -#endif -} - -void TAUupdate(int cpu) -{ - unsigned thrm; - -#ifdef DEBUG - printk("TAUupdate "); -#endif - - /* if both thresholds are crossed, the step_sizes cancel out - * and the window winds up getting expanded twice. */ - if((thrm = mfspr(SPRN_THRM1)) & THRM1_TIV){ /* is valid? */ - if(thrm & THRM1_TIN){ /* crossed low threshold */ - if (tau[cpu].low >= step_size){ - tau[cpu].low -= step_size; - tau[cpu].high -= (step_size - window_expand); - } - tau[cpu].grew = 1; -#ifdef DEBUG - printk("low threshold crossed "); -#endif - } - } - if((thrm = mfspr(SPRN_THRM2)) & THRM1_TIV){ /* is valid? */ - if(thrm & THRM1_TIN){ /* crossed high threshold */ - if (tau[cpu].high <= 127-step_size){ - tau[cpu].low += (step_size - window_expand); - tau[cpu].high += step_size; - } - tau[cpu].grew = 1; -#ifdef DEBUG - printk("high threshold crossed "); -#endif - } - } - -#ifdef DEBUG - printk("grew = %d\n", tau[cpu].grew); -#endif - -#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */ - set_thresholds(cpu); -#endif - -} - -#ifdef CONFIG_TAU_INT -/* - * TAU interrupts - called when we have a thermal assist unit interrupt - * with interrupts disabled - */ - -void TAUException(struct pt_regs * regs) -{ - int cpu = smp_processor_id(); - - irq_enter(); - tau[cpu].interrupts++; - - TAUupdate(cpu); - - irq_exit(); -} -#endif /* CONFIG_TAU_INT */ - -static void tau_timeout(void * info) -{ - int cpu; - unsigned long flags; - int size; - int shrink; - - /* disabling interrupts *should* be okay */ - local_irq_save(flags); - cpu = smp_processor_id(); - -#ifndef CONFIG_TAU_INT - TAUupdate(cpu); -#endif - - size = tau[cpu].high - tau[cpu].low; - if (size > min_window && ! tau[cpu].grew) { - /* do an exponential shrink of half the amount currently over size */ - shrink = (2 + size - min_window) / 4; - if (shrink) { - tau[cpu].low += shrink; - tau[cpu].high -= shrink; - } else { /* size must have been min_window + 1 */ - tau[cpu].low += 1; -#if 1 /* debug */ - if ((tau[cpu].high - tau[cpu].low) != min_window){ - printk(KERN_ERR "temp.c: line %d, logic error\n", __LINE__); - } -#endif - } - } - - tau[cpu].grew = 0; - - set_thresholds(cpu); - - /* - * Do the enable every time, since otherwise a bunch of (relatively) - * complex sleep code needs to be added. One mtspr every time - * tau_timeout is called is probably not a big deal. - * - * Enable thermal sensor and set up sample interval timer - * need 20 us to do the compare.. until a nice 'cpu_speed' function - * call is implemented, just assume a 500 mhz clock. It doesn't really - * matter if we take too long for a compare since it's all interrupt - * driven anyway. - * - * use a extra long time.. (60 us @ 500 mhz) - */ - mtspr(SPRN_THRM3, THRM3_SITV(500*60) | THRM3_E); - - local_irq_restore(flags); -} - -static void tau_timeout_smp(unsigned long unused) -{ - - /* schedule ourselves to be run again */ - mod_timer(&tau_timer, jiffies + shrink_timer) ; - on_each_cpu(tau_timeout, NULL, 1, 0); -} - -/* - * setup the TAU - * - * Set things up to use THRM1 as a temperature lower bound, and THRM2 as an upper bound. - * Start off at zero - */ - -int tau_initialized = 0; - -void __init TAU_init_smp(void * info) -{ - unsigned long cpu = smp_processor_id(); - - /* set these to a reasonable value and let the timer shrink the - * window */ - tau[cpu].low = 5; - tau[cpu].high = 120; - - set_thresholds(cpu); -} - -int __init TAU_init(void) -{ - /* We assume in SMP that if one CPU has TAU support, they - * all have it --BenH - */ - if (!cpu_has_feature(CPU_FTR_TAU)) { - printk("Thermal assist unit not available\n"); - tau_initialized = 0; - return 1; - } - - - /* first, set up the window shrinking timer */ - init_timer(&tau_timer); - tau_timer.function = tau_timeout_smp; - tau_timer.expires = jiffies + shrink_timer; - add_timer(&tau_timer); - - on_each_cpu(TAU_init_smp, NULL, 1, 0); - - printk("Thermal assist unit "); -#ifdef CONFIG_TAU_INT - printk("using interrupts, "); -#else - printk("using timers, "); -#endif - printk("shrink_timer: %d jiffies\n", shrink_timer); - tau_initialized = 1; - - return 0; -} - -__initcall(TAU_init); - -/* - * return current temp - */ - -u32 cpu_temp_both(unsigned long cpu) -{ - return ((tau[cpu].high << 16) | tau[cpu].low); -} - -int cpu_temp(unsigned long cpu) -{ - return ((tau[cpu].high + tau[cpu].low) / 2); -} - -int tau_interrupts(unsigned long cpu) -{ - return (tau[cpu].interrupts); -} -- cgit v1.2.3-70-g09d2