From 6f859c0e96f0737a543610a189d12420c569110f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Aug 2012 16:41:04 -0700 Subject: sparc64: Add detection for features new in SPARC-T4. Compare and branch, pause, and the various new cryptographic opcodes. We advertise the crypto opcodes to userspace using one hwcap bit, HWCAP_SPARC_CRYPTO. This essentially indicates that the %cfr register can be interrograted and used to determine exactly which crypto opcodes are available on the current cpu. We use the %cfr register to report all of the crypto opcodes available in the bootup CPU caps log message, and via /proc/cpuinfo. Signed-off-by: David S. Miller --- arch/sparc/include/asm/elf_64.h | 9 +++++++++ arch/sparc/include/asm/pstate.h | 14 ++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h index 7df8b7f544d4..370ca1e71ffb 100644 --- a/arch/sparc/include/asm/elf_64.h +++ b/arch/sparc/include/asm/elf_64.h @@ -86,6 +86,15 @@ #define AV_SPARC_IMA 0x00400000 /* integer multiply-add */ #define AV_SPARC_ASI_CACHE_SPARING \ 0x00800000 /* cache sparing ASIs available */ +#define AV_SPARC_PAUSE 0x01000000 /* PAUSE available */ +#define AV_SPARC_CBCOND 0x02000000 /* CBCOND insns available */ + +/* Solaris decided to enumerate every single crypto instruction type + * in the AT_HWCAP bits. This is wasteful, since if crypto is present, + * you still need to look in the CFR register to see if the opcode is + * really available. So we simply advertise only "crypto" support. + */ +#define HWCAP_SPARC_CRYPTO 0x04000000 /* CRYPTO insns available */ #define CORE_DUMP_USE_REGSET diff --git a/arch/sparc/include/asm/pstate.h b/arch/sparc/include/asm/pstate.h index a26a53777bb0..6dfa8f8c9749 100644 --- a/arch/sparc/include/asm/pstate.h +++ b/arch/sparc/include/asm/pstate.h @@ -88,4 +88,18 @@ #define VERS_MAXTL _AC(0x000000000000ff00,UL) /* Max Trap Level. */ #define VERS_MAXWIN _AC(0x000000000000001f,UL) /* Max RegWindow Idx.*/ +/* Compatability Feature Register (%asr26), SPARC-T4 and later */ +#define CFR_AES _AC(0x0000000000000001,UL) /* Supports AES opcodes */ +#define CFR_DES _AC(0x0000000000000002,UL) /* Supports DES opcodes */ +#define CFR_KASUMI _AC(0x0000000000000004,UL) /* Supports KASUMI opcodes */ +#define CFR_CAMELIA _AC(0x0000000000000008,UL) /* Supports CAMELIA opcodes */ +#define CFR_MD5 _AC(0x0000000000000010,UL) /* Supports MD5 opcodes */ +#define CFR_SHA1 _AC(0x0000000000000020,UL) /* Supports SHA1 opcodes */ +#define CFR_SHA256 _AC(0x0000000000000040,UL) /* Supports SHA256 opcodes */ +#define CFR_SHA512 _AC(0x0000000000000080,UL) /* Supports SHA512 opcodes */ +#define CFR_MPMUL _AC(0x0000000000000100,UL) /* Supports MPMUL opcodes */ +#define CFR_MONTMUL _AC(0x0000000000000200,UL) /* Supports MONTMUL opcodes */ +#define CFR_MONTSQR _AC(0x0000000000000400,UL) /* Supports MONTSQR opcodes */ +#define CFR_CRC32C _AC(0x0000000000000800,UL) /* Supports CRC32C opcodes */ + #endif /* !(_SPARC64_PSTATE_H) */ -- cgit v1.2.3 From 8c79bfa51101354853f0f5d3b02435cec429da51 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Aug 2012 20:35:41 -0700 Subject: sparc64: Add hypervisor interfaces for SPARC-T4 perf counter access. Unlike for previous chips, access to the perf-counter control registers are all hyper-privileged. Therefore, access to them must go through a hypervisor interface. Signed-off-by: David S. Miller --- arch/sparc/include/asm/hypervisor.h | 11 +++++++++++ arch/sparc/kernel/hvapi.c | 1 + arch/sparc/kernel/hvcalls.S | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h index 015a761eaa32..ca121f0fa3ec 100644 --- a/arch/sparc/include/asm/hypervisor.h +++ b/arch/sparc/include/asm/hypervisor.h @@ -2934,6 +2934,16 @@ extern unsigned long sun4v_reboot_data_set(unsigned long ra, unsigned long len); #endif +#define HV_FAST_VT_GET_PERFREG 0x184 +#define HV_FAST_VT_SET_PERFREG 0x185 + +#ifndef __ASSEMBLY__ +extern unsigned long sun4v_vt_get_perfreg(unsigned long reg_num, + unsigned long *reg_val); +extern unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, + unsigned long reg_val); +#endif + /* Function numbers for HV_CORE_TRAP. */ #define HV_CORE_SET_VER 0x00 #define HV_CORE_PUTCHAR 0x01 @@ -2964,6 +2974,7 @@ extern unsigned long sun4v_reboot_data_set(unsigned long ra, #define HV_GRP_NIU 0x0204 #define HV_GRP_VF_CPU 0x0205 #define HV_GRP_KT_CPU 0x0209 +#define HV_GRP_VT_CPU 0x020c #define HV_GRP_DIAG 0x0300 #ifndef __ASSEMBLY__ diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c index 8593672838fd..1032df43ec95 100644 --- a/arch/sparc/kernel/hvapi.c +++ b/arch/sparc/kernel/hvapi.c @@ -45,6 +45,7 @@ static struct api_info api_table[] = { { .group = HV_GRP_NIU, }, { .group = HV_GRP_VF_CPU, }, { .group = HV_GRP_KT_CPU, }, + { .group = HV_GRP_VT_CPU, }, { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API }, }; diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S index 58d60de4d65b..f3ab509b76a8 100644 --- a/arch/sparc/kernel/hvcalls.S +++ b/arch/sparc/kernel/hvcalls.S @@ -805,3 +805,19 @@ ENTRY(sun4v_reboot_data_set) retl nop ENDPROC(sun4v_reboot_data_set) + +ENTRY(sun4v_vt_get_perfreg) + mov %o1, %o4 + mov HV_FAST_VT_GET_PERFREG, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop +ENDPROC(sun4v_vt_get_perfreg) + +ENTRY(sun4v_vt_set_perfreg) + mov HV_FAST_VT_SET_PERFREG, %o5 + ta HV_FAST_TRAP + retl + nop +ENDPROC(sun4v_vt_set_perfreg) -- cgit v1.2.3 From 0bab20ba4c95f56355c24a0b9f03eb486c2a267d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Aug 2012 21:16:22 -0700 Subject: sparc64: Add 'reg_num' argument to pcr_ops methods. SPARC-T4 and later have multiple PCR registers, one for each PIC counter. Signed-off-by: David S. Miller --- arch/sparc/include/asm/pcr.h | 4 ++-- arch/sparc/kernel/nmi.c | 14 +++++++------- arch/sparc/kernel/pcr.c | 9 ++++++--- arch/sparc/kernel/perf_event.c | 14 +++++++------- 4 files changed, 22 insertions(+), 19 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/pcr.h b/arch/sparc/include/asm/pcr.h index 288d7beba051..55e23416eefc 100644 --- a/arch/sparc/include/asm/pcr.h +++ b/arch/sparc/include/asm/pcr.h @@ -2,8 +2,8 @@ #define __PCR_H struct pcr_ops { - u64 (*read)(void); - void (*write)(u64); + u64 (*read)(unsigned long); + void (*write)(unsigned long, u64); }; extern const struct pcr_ops *pcr_ops; diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index eb1c1f010a47..95df720a14a9 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -109,7 +109,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) touched = 1; else - pcr_ops->write(PCR_PIC_PRIV); + pcr_ops->write(0, PCR_PIC_PRIV); sum = local_cpu_data().irq0_irqs; if (__get_cpu_var(nmi_touch)) { @@ -127,7 +127,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) } if (__get_cpu_var(wd_enabled)) { write_pic(picl_value(nmi_hz)); - pcr_ops->write(pcr_enable); + pcr_ops->write(0, pcr_enable); } restore_hardirq_stack(orig_sp); @@ -166,7 +166,7 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) void stop_nmi_watchdog(void *unused) { - pcr_ops->write(PCR_PIC_PRIV); + pcr_ops->write(0, PCR_PIC_PRIV); __get_cpu_var(wd_enabled) = 0; atomic_dec(&nmi_active); } @@ -223,10 +223,10 @@ void start_nmi_watchdog(void *unused) __get_cpu_var(wd_enabled) = 1; atomic_inc(&nmi_active); - pcr_ops->write(PCR_PIC_PRIV); + pcr_ops->write(0, PCR_PIC_PRIV); write_pic(picl_value(nmi_hz)); - pcr_ops->write(pcr_enable); + pcr_ops->write(0, pcr_enable); } static void nmi_adjust_hz_one(void *unused) @@ -234,10 +234,10 @@ static void nmi_adjust_hz_one(void *unused) if (!__get_cpu_var(wd_enabled)) return; - pcr_ops->write(PCR_PIC_PRIV); + pcr_ops->write(0, PCR_PIC_PRIV); write_pic(picl_value(nmi_hz)); - pcr_ops->write(pcr_enable); + pcr_ops->write(0, pcr_enable); } void nmi_adjust_hz(unsigned int new_hz) diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index 0ce0dd2332aa..3d9ab5be23d8 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -60,16 +60,18 @@ void arch_irq_work_raise(void) const struct pcr_ops *pcr_ops; EXPORT_SYMBOL_GPL(pcr_ops); -static u64 direct_pcr_read(void) +static u64 direct_pcr_read(unsigned long reg_num) { u64 val; + WARN_ON_ONCE(reg_num != 0); read_pcr(val); return val; } -static void direct_pcr_write(u64 val) +static void direct_pcr_write(unsigned long reg_num, u64 val) { + WARN_ON_ONCE(reg_num != 0); write_pcr(val); } @@ -78,10 +80,11 @@ static const struct pcr_ops direct_pcr_ops = { .write = direct_pcr_write, }; -static void n2_pcr_write(u64 val) +static void n2_pcr_write(unsigned long reg_num, u64 val) { unsigned long ret; + WARN_ON_ONCE(reg_num != 0); if (val & PCR_N2_HTRACE) { ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val); if (ret != HV_EOK) diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 5713957dcb8a..e1c9848c39cb 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -564,7 +564,7 @@ static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_ val |= hwc->config; cpuc->pcr = val; - pcr_ops->write(cpuc->pcr); + pcr_ops->write(0, cpuc->pcr); } static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx) @@ -578,7 +578,7 @@ static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw val |= nop; cpuc->pcr = val; - pcr_ops->write(cpuc->pcr); + pcr_ops->write(0, cpuc->pcr); } static u32 read_pmc(int idx) @@ -736,7 +736,7 @@ static void sparc_pmu_enable(struct pmu *pmu) cpuc->pcr = pcr | cpuc->event[0]->hw.config_base; } - pcr_ops->write(cpuc->pcr); + pcr_ops->write(0, cpuc->pcr); } static void sparc_pmu_disable(struct pmu *pmu) @@ -755,7 +755,7 @@ static void sparc_pmu_disable(struct pmu *pmu) sparc_pmu->hv_bit | sparc_pmu->irq_bit); cpuc->pcr = val; - pcr_ops->write(cpuc->pcr); + pcr_ops->write(0, cpuc->pcr); } static int active_event_index(struct cpu_hw_events *cpuc, @@ -856,7 +856,7 @@ static void perf_stop_nmi_watchdog(void *unused) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); stop_nmi_watchdog(NULL); - cpuc->pcr = pcr_ops->read(); + cpuc->pcr = pcr_ops->read(0); } void perf_event_grab_pmc(void) @@ -1264,7 +1264,7 @@ void perf_event_print_debug(void) cpu = smp_processor_id(); - pcr = pcr_ops->read(); + pcr = pcr_ops->read(0); read_pic(pic); pr_info("\n"); @@ -1306,7 +1306,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, * overflow so we don't lose any events. */ if (sparc_pmu->irq_bit) - pcr_ops->write(cpuc->pcr); + pcr_ops->write(0, cpuc->pcr); for (i = 0; i < cpuc->n_events; i++) { struct perf_event *event = cpuc->event[i]; -- cgit v1.2.3 From 09d053c797f4a559af0647e4283b9b9ec0682d10 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Aug 2012 23:19:32 -0700 Subject: sparc64: Abstract away PIC register accesses. And, like for the PCR, allow indexing of different PIC register numbers. This also removes all of the non-__KERNEL__ bits from asm/perfctr.h, nothing kernel side should include it any more. Signed-off-by: David S. Miller --- arch/sparc/include/asm/pcr.h | 6 ++++-- arch/sparc/include/asm/perfctr.h | 30 --------------------------- arch/sparc/kernel/nmi.c | 21 +++++++++---------- arch/sparc/kernel/pcr.c | 45 ++++++++++++++++++++++++++++++++-------- arch/sparc/kernel/perf_event.c | 23 ++++++++++---------- 5 files changed, 61 insertions(+), 64 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/pcr.h b/arch/sparc/include/asm/pcr.h index 55e23416eefc..d53abf75198f 100644 --- a/arch/sparc/include/asm/pcr.h +++ b/arch/sparc/include/asm/pcr.h @@ -2,8 +2,10 @@ #define __PCR_H struct pcr_ops { - u64 (*read)(unsigned long); - void (*write)(unsigned long, u64); + u64 (*read_pcr)(unsigned long); + void (*write_pcr)(unsigned long, u64); + u64 (*read_pic)(unsigned long); + void (*write_pic)(unsigned long, u64); }; extern const struct pcr_ops *pcr_ops; diff --git a/arch/sparc/include/asm/perfctr.h b/arch/sparc/include/asm/perfctr.h index 3332d2cba6c1..214feefa577c 100644 --- a/arch/sparc/include/asm/perfctr.h +++ b/arch/sparc/include/asm/perfctr.h @@ -54,11 +54,6 @@ enum perfctr_opcode { PERFCTR_GETPCR }; -/* I don't want the kernel's namespace to be polluted with this - * stuff when this file is included. --DaveM - */ -#ifndef __KERNEL__ - #define PRIV 0x00000001 #define SYS 0x00000002 #define USR 0x00000004 @@ -168,29 +163,4 @@ struct vcounter_struct { unsigned long long vcnt1; }; -#else /* !(__KERNEL__) */ - -#ifndef CONFIG_SPARC32 - -/* Performance counter register access. */ -#define read_pcr(__p) __asm__ __volatile__("rd %%pcr, %0" : "=r" (__p)) -#define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p)) -#define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p)) - -/* Blackbird errata workaround. See commentary in - * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() - * for more information. - */ -#define write_pic(__p) \ - __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ - " nop\n\t" \ - ".align 64\n" \ - "99:wr %0, 0x0, %%pic\n\t" \ - "rd %%pic, %%g0" : : "r" (__p)) -#define reset_pic() write_pic(0) - -#endif /* !CONFIG_SPARC32 */ - -#endif /* !(__KERNEL__) */ - #endif /* !(PERF_COUNTER_API) */ diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 95df720a14a9..ef22b9bacf1d 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "kstack.h" @@ -109,7 +108,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) touched = 1; else - pcr_ops->write(0, PCR_PIC_PRIV); + pcr_ops->write_pcr(0, PCR_PIC_PRIV); sum = local_cpu_data().irq0_irqs; if (__get_cpu_var(nmi_touch)) { @@ -126,8 +125,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) __this_cpu_write(alert_counter, 0); } if (__get_cpu_var(wd_enabled)) { - write_pic(picl_value(nmi_hz)); - pcr_ops->write(0, pcr_enable); + pcr_ops->write_pic(0, picl_value(nmi_hz)); + pcr_ops->write_pcr(0, pcr_enable); } restore_hardirq_stack(orig_sp); @@ -166,7 +165,7 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) void stop_nmi_watchdog(void *unused) { - pcr_ops->write(0, PCR_PIC_PRIV); + pcr_ops->write_pcr(0, PCR_PIC_PRIV); __get_cpu_var(wd_enabled) = 0; atomic_dec(&nmi_active); } @@ -223,10 +222,10 @@ void start_nmi_watchdog(void *unused) __get_cpu_var(wd_enabled) = 1; atomic_inc(&nmi_active); - pcr_ops->write(0, PCR_PIC_PRIV); - write_pic(picl_value(nmi_hz)); + pcr_ops->write_pcr(0, PCR_PIC_PRIV); + pcr_ops->write_pic(0, picl_value(nmi_hz)); - pcr_ops->write(0, pcr_enable); + pcr_ops->write_pcr(0, pcr_enable); } static void nmi_adjust_hz_one(void *unused) @@ -234,10 +233,10 @@ static void nmi_adjust_hz_one(void *unused) if (!__get_cpu_var(wd_enabled)) return; - pcr_ops->write(0, PCR_PIC_PRIV); - write_pic(picl_value(nmi_hz)); + pcr_ops->write_pcr(0, PCR_PIC_PRIV); + pcr_ops->write_pic(0, picl_value(nmi_hz)); - pcr_ops->write(0, pcr_enable); + pcr_ops->write_pcr(0, pcr_enable); } void nmi_adjust_hz(unsigned int new_hz) diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index 3d9ab5be23d8..e82ae89666f0 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -14,7 +14,6 @@ #include #include #include -#include /* This code is shared between various users of the performance * counters. Users will be oprofile, pseudo-NMI watchdog, and the @@ -65,19 +64,45 @@ static u64 direct_pcr_read(unsigned long reg_num) u64 val; WARN_ON_ONCE(reg_num != 0); - read_pcr(val); + __asm__ __volatile__("rd %%pcr, %0" : "=r" (val)); return val; } static void direct_pcr_write(unsigned long reg_num, u64 val) { WARN_ON_ONCE(reg_num != 0); - write_pcr(val); + __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (val)); +} + +static u64 direct_pic_read(unsigned long reg_num) +{ + u64 val; + + WARN_ON_ONCE(reg_num != 0); + __asm__ __volatile__("rd %%pic, %0" : "=r" (val)); + return val; +} + +static void direct_pic_write(unsigned long reg_num, u64 val) +{ + WARN_ON_ONCE(reg_num != 0); + + /* Blackbird errata workaround. See commentary in + * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() + * for more information. + */ + __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" + " nop\n\t" + ".align 64\n" + "99:wr %0, 0x0, %%pic\n\t" + "rd %%pic, %%g0" : : "r" (val)); } static const struct pcr_ops direct_pcr_ops = { - .read = direct_pcr_read, - .write = direct_pcr_write, + .read_pcr = direct_pcr_read, + .write_pcr = direct_pcr_write, + .read_pic = direct_pic_read, + .write_pic = direct_pic_write, }; static void n2_pcr_write(unsigned long reg_num, u64 val) @@ -88,14 +113,16 @@ static void n2_pcr_write(unsigned long reg_num, u64 val) if (val & PCR_N2_HTRACE) { ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val); if (ret != HV_EOK) - write_pcr(val); + direct_pcr_write(reg_num, val); } else - write_pcr(val); + direct_pcr_write(reg_num, val); } static const struct pcr_ops n2_pcr_ops = { - .read = direct_pcr_read, - .write = n2_pcr_write, + .read_pcr = direct_pcr_read, + .write_pcr = n2_pcr_write, + .read_pic = direct_pic_read, + .write_pic = direct_pic_write, }; static unsigned long perf_hsvc_group; diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index e1c9848c39cb..dd12aa35805d 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "kernel.h" @@ -564,7 +563,7 @@ static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_ val |= hwc->config; cpuc->pcr = val; - pcr_ops->write(0, cpuc->pcr); + pcr_ops->write_pcr(0, cpuc->pcr); } static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx) @@ -578,14 +577,14 @@ static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw val |= nop; cpuc->pcr = val; - pcr_ops->write(0, cpuc->pcr); + pcr_ops->write_pcr(0, cpuc->pcr); } static u32 read_pmc(int idx) { u64 val; - read_pic(val); + val = pcr_ops->read_pic(0); if (idx == PIC_UPPER_INDEX) val >>= 32; @@ -603,10 +602,10 @@ static void write_pmc(int idx, u64 val) mask = ((u64) 0xffffffff) << shift; val <<= shift; - read_pic(pic); + pic = pcr_ops->read_pic(0); pic &= ~mask; pic |= val; - write_pic(pic); + pcr_ops->write_pic(0, pic); } static u64 sparc_perf_event_update(struct perf_event *event, @@ -736,7 +735,7 @@ static void sparc_pmu_enable(struct pmu *pmu) cpuc->pcr = pcr | cpuc->event[0]->hw.config_base; } - pcr_ops->write(0, cpuc->pcr); + pcr_ops->write_pcr(0, cpuc->pcr); } static void sparc_pmu_disable(struct pmu *pmu) @@ -755,7 +754,7 @@ static void sparc_pmu_disable(struct pmu *pmu) sparc_pmu->hv_bit | sparc_pmu->irq_bit); cpuc->pcr = val; - pcr_ops->write(0, cpuc->pcr); + pcr_ops->write_pcr(0, cpuc->pcr); } static int active_event_index(struct cpu_hw_events *cpuc, @@ -856,7 +855,7 @@ static void perf_stop_nmi_watchdog(void *unused) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); stop_nmi_watchdog(NULL); - cpuc->pcr = pcr_ops->read(0); + cpuc->pcr = pcr_ops->read_pcr(0); } void perf_event_grab_pmc(void) @@ -1264,8 +1263,8 @@ void perf_event_print_debug(void) cpu = smp_processor_id(); - pcr = pcr_ops->read(0); - read_pic(pic); + pcr = pcr_ops->read_pcr(0); + pic = pcr_ops->read_pic(0); pr_info("\n"); pr_info("CPU#%d: PCR[%016llx] PIC[%016llx]\n", @@ -1306,7 +1305,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, * overflow so we don't lose any events. */ if (sparc_pmu->irq_bit) - pcr_ops->write(0, cpuc->pcr); + pcr_ops->write_pcr(0, cpuc->pcr); for (i = 0; i < cpuc->n_events; i++) { struct perf_event *event = cpuc->event[i]; -- cgit v1.2.3 From 73a6b0538c131d489fe7a2581deddb72faca496b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Aug 2012 23:26:01 -0700 Subject: sparc64: Abstract away the NMI PIC counter computation. Signed-off-by: David S. Miller --- arch/sparc/include/asm/pcr.h | 15 +-------------- arch/sparc/kernel/nmi.c | 6 +++--- arch/sparc/kernel/pcr.c | 18 ++++++++++++++++-- 3 files changed, 20 insertions(+), 19 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/pcr.h b/arch/sparc/include/asm/pcr.h index d53abf75198f..4c71bec20659 100644 --- a/arch/sparc/include/asm/pcr.h +++ b/arch/sparc/include/asm/pcr.h @@ -6,6 +6,7 @@ struct pcr_ops { void (*write_pcr)(unsigned long, u64); u64 (*read_pic)(unsigned long); void (*write_pic)(unsigned long, u64); + u64 (*nmi_picl_value)(unsigned int nmi_hz); }; extern const struct pcr_ops *pcr_ops; @@ -29,20 +30,6 @@ extern void schedule_deferred_pcr_work(void); #define PCR_N2_SL1_SHIFT 27 #define PCR_N2_OV1 0x80000000 -extern unsigned int picl_shift; - -/* In order to commonize as much of the implementation as - * possible, we use PICH as our counter. Mostly this is - * to accommodate Niagara-1 which can only count insn cycles - * in PICH. - */ -static inline u64 picl_value(unsigned int nmi_hz) -{ - u32 delta = local_cpu_data().clock_tick / (nmi_hz << picl_shift); - - return ((u64)((0 - delta) & 0xffffffff)) << 32; -} - extern u64 pcr_enable; extern int pcr_arch_init(void); diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index ef22b9bacf1d..4c45158d4c88 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -125,7 +125,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) __this_cpu_write(alert_counter, 0); } if (__get_cpu_var(wd_enabled)) { - pcr_ops->write_pic(0, picl_value(nmi_hz)); + pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); pcr_ops->write_pcr(0, pcr_enable); } @@ -223,7 +223,7 @@ void start_nmi_watchdog(void *unused) atomic_inc(&nmi_active); pcr_ops->write_pcr(0, PCR_PIC_PRIV); - pcr_ops->write_pic(0, picl_value(nmi_hz)); + pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); pcr_ops->write_pcr(0, pcr_enable); } @@ -234,7 +234,7 @@ static void nmi_adjust_hz_one(void *unused) return; pcr_ops->write_pcr(0, PCR_PIC_PRIV); - pcr_ops->write_pic(0, picl_value(nmi_hz)); + pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); pcr_ops->write_pcr(0, pcr_enable); } diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index e82ae89666f0..494af3227f3b 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -27,7 +27,6 @@ (0xff << PCR_N2_MASK1_SHIFT)) u64 pcr_enable; -unsigned int picl_shift; /* Performance counter interrupts run unmasked at PIL level 15. * Therefore we can't do things like wakeups and other work @@ -98,11 +97,19 @@ static void direct_pic_write(unsigned long reg_num, u64 val) "rd %%pic, %%g0" : : "r" (val)); } +static u64 direct_picl_value(unsigned int nmi_hz) +{ + u32 delta = local_cpu_data().clock_tick / nmi_hz; + + return ((u64)((0 - delta) & 0xffffffff)) << 32; +} + static const struct pcr_ops direct_pcr_ops = { .read_pcr = direct_pcr_read, .write_pcr = direct_pcr_write, .read_pic = direct_pic_read, .write_pic = direct_pic_write, + .nmi_picl_value = direct_picl_value, }; static void n2_pcr_write(unsigned long reg_num, u64 val) @@ -118,11 +125,19 @@ static void n2_pcr_write(unsigned long reg_num, u64 val) direct_pcr_write(reg_num, val); } +static u64 n2_picl_value(unsigned int nmi_hz) +{ + u32 delta = local_cpu_data().clock_tick / (nmi_hz << 2); + + return ((u64)((0 - delta) & 0xffffffff)) << 32; +} + static const struct pcr_ops n2_pcr_ops = { .read_pcr = direct_pcr_read, .write_pcr = n2_pcr_write, .read_pic = direct_pic_read, .write_pic = direct_pic_write, + .nmi_picl_value = n2_picl_value, }; static unsigned long perf_hsvc_group; @@ -180,7 +195,6 @@ int __init pcr_arch_init(void) case hypervisor: pcr_ops = &n2_pcr_ops; pcr_enable = PCR_N2_ENABLE; - picl_shift = 2; break; case cheetah: -- cgit v1.2.3 From ce4a925c29208cf48084d9fa174d965a65246a8d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Aug 2012 23:31:59 -0700 Subject: sparc64: Abstract away the %pcr values used to enable/disable NMI We assumed PCR_PIC_PRIV can always be used to disable it, but that won't be true for SPARC-T4. This allows us also to get rid of some messy defines used in only one location. Signed-off-by: David S. Miller --- arch/sparc/include/asm/pcr.h | 4 ++-- arch/sparc/kernel/nmi.c | 14 +++++++------- arch/sparc/kernel/pcr.c | 37 +++++++++++++++++-------------------- 3 files changed, 26 insertions(+), 29 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/pcr.h b/arch/sparc/include/asm/pcr.h index 4c71bec20659..9ebc7f3840d1 100644 --- a/arch/sparc/include/asm/pcr.h +++ b/arch/sparc/include/asm/pcr.h @@ -7,6 +7,8 @@ struct pcr_ops { u64 (*read_pic)(unsigned long); void (*write_pic)(unsigned long, u64); u64 (*nmi_picl_value)(unsigned int nmi_hz); + u64 pcr_nmi_enable; + u64 pcr_nmi_disable; }; extern const struct pcr_ops *pcr_ops; @@ -30,8 +32,6 @@ extern void schedule_deferred_pcr_work(void); #define PCR_N2_SL1_SHIFT 27 #define PCR_N2_OV1 0x80000000 -extern u64 pcr_enable; - extern int pcr_arch_init(void); #endif /* __PCR_H */ diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 4c45158d4c88..6479256fd5a4 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -108,7 +108,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) touched = 1; else - pcr_ops->write_pcr(0, PCR_PIC_PRIV); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); sum = local_cpu_data().irq0_irqs; if (__get_cpu_var(nmi_touch)) { @@ -126,7 +126,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) } if (__get_cpu_var(wd_enabled)) { pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); - pcr_ops->write_pcr(0, pcr_enable); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_enable); } restore_hardirq_stack(orig_sp); @@ -165,7 +165,7 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) void stop_nmi_watchdog(void *unused) { - pcr_ops->write_pcr(0, PCR_PIC_PRIV); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); __get_cpu_var(wd_enabled) = 0; atomic_dec(&nmi_active); } @@ -222,10 +222,10 @@ void start_nmi_watchdog(void *unused) __get_cpu_var(wd_enabled) = 1; atomic_inc(&nmi_active); - pcr_ops->write_pcr(0, PCR_PIC_PRIV); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); - pcr_ops->write_pcr(0, pcr_enable); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_enable); } static void nmi_adjust_hz_one(void *unused) @@ -233,10 +233,10 @@ static void nmi_adjust_hz_one(void *unused) if (!__get_cpu_var(wd_enabled)) return; - pcr_ops->write_pcr(0, PCR_PIC_PRIV); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); - pcr_ops->write_pcr(0, pcr_enable); + pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_enable); } void nmi_adjust_hz(unsigned int new_hz) diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index 494af3227f3b..e408fc5d0c18 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -20,14 +20,6 @@ * perf_event support layer. */ -#define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE) -#define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \ - PCR_N2_TOE_OV1 | \ - (2 << PCR_N2_SL1_SHIFT) | \ - (0xff << PCR_N2_MASK1_SHIFT)) - -u64 pcr_enable; - /* Performance counter interrupts run unmasked at PIL level 15. * Therefore we can't do things like wakeups and other work * that expects IRQ disabling to be adhered to in locking etc. @@ -105,11 +97,13 @@ static u64 direct_picl_value(unsigned int nmi_hz) } static const struct pcr_ops direct_pcr_ops = { - .read_pcr = direct_pcr_read, - .write_pcr = direct_pcr_write, - .read_pic = direct_pic_read, - .write_pic = direct_pic_write, - .nmi_picl_value = direct_picl_value, + .read_pcr = direct_pcr_read, + .write_pcr = direct_pcr_write, + .read_pic = direct_pic_read, + .write_pic = direct_pic_write, + .nmi_picl_value = direct_picl_value, + .pcr_nmi_enable = (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE), + .pcr_nmi_disable = PCR_PIC_PRIV, }; static void n2_pcr_write(unsigned long reg_num, u64 val) @@ -133,11 +127,16 @@ static u64 n2_picl_value(unsigned int nmi_hz) } static const struct pcr_ops n2_pcr_ops = { - .read_pcr = direct_pcr_read, - .write_pcr = n2_pcr_write, - .read_pic = direct_pic_read, - .write_pic = direct_pic_write, - .nmi_picl_value = n2_picl_value, + .read_pcr = direct_pcr_read, + .write_pcr = n2_pcr_write, + .read_pic = direct_pic_read, + .write_pic = direct_pic_write, + .nmi_picl_value = n2_picl_value, + .pcr_nmi_enable = (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | + PCR_N2_TOE_OV1 | + (2 << PCR_N2_SL1_SHIFT) | + (0xff << PCR_N2_MASK1_SHIFT)), + .pcr_nmi_disable = PCR_PIC_PRIV, }; static unsigned long perf_hsvc_group; @@ -194,13 +193,11 @@ int __init pcr_arch_init(void) switch (tlb_type) { case hypervisor: pcr_ops = &n2_pcr_ops; - pcr_enable = PCR_N2_ENABLE; break; case cheetah: case cheetah_plus: pcr_ops = &direct_pcr_ops; - pcr_enable = PCR_SUN4U_ENABLE; break; case spitfire: -- cgit v1.2.3 From 6faaeb8ea30e55c9fd7cf65d05f3ce44973d1d12 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 17 Aug 2012 00:20:39 -0700 Subject: sparc64: Add PCR ops for SPARC-T4. This is enough to get the NMIs working, more work is needed for perf events. Signed-off-by: David S. Miller --- arch/sparc/include/asm/asi.h | 4 ++- arch/sparc/include/asm/pcr.h | 13 +++++++ arch/sparc/kernel/pcr.c | 83 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 98 insertions(+), 2 deletions(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/asi.h b/arch/sparc/include/asm/asi.h index 61ebe7411ceb..cc0006dc5d4a 100644 --- a/arch/sparc/include/asm/asi.h +++ b/arch/sparc/include/asm/asi.h @@ -141,7 +141,8 @@ /* SpitFire and later extended ASIs. The "(III)" marker designates * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates * Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific - * ASIs, "(4V)" designates SUN4V specific ASIs. + * ASIs, "(4V)" designates SUN4V specific ASIs. "(NG4)" designates SPARC-T4 + * and later ASIs. */ #define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ #define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ @@ -243,6 +244,7 @@ #define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/ #define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ #define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */ +#define ASI_PIC 0xb0 /* (NG4) PIC registers */ #define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ #define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ #define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ diff --git a/arch/sparc/include/asm/pcr.h b/arch/sparc/include/asm/pcr.h index 9ebc7f3840d1..942bb17f60cd 100644 --- a/arch/sparc/include/asm/pcr.h +++ b/arch/sparc/include/asm/pcr.h @@ -32,6 +32,19 @@ extern void schedule_deferred_pcr_work(void); #define PCR_N2_SL1_SHIFT 27 #define PCR_N2_OV1 0x80000000 +#define PCR_N4_OV 0x00000001 /* PIC overflow */ +#define PCR_N4_TOE 0x00000002 /* Trap On Event */ +#define PCR_N4_UTRACE 0x00000004 /* Trace user events */ +#define PCR_N4_STRACE 0x00000008 /* Trace supervisor events */ +#define PCR_N4_HTRACE 0x00000010 /* Trace hypervisor events */ +#define PCR_N4_MASK 0x000007e0 /* Event mask */ +#define PCR_N4_MASK_SHIFT 5 +#define PCR_N4_SL 0x0000f800 /* Event Select */ +#define PCR_N4_SL_SHIFT 11 +#define PCR_N4_PICNPT 0x00010000 /* PIC non-privileged trap */ +#define PCR_N4_PICNHT 0x00020000 /* PIC non-hypervisor trap */ +#define PCR_N4_NTC 0x00040000 /* Next-To-Commit wrap */ + extern int pcr_arch_init(void); #endif /* __PCR_H */ diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index e408fc5d0c18..269af58497aa 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -13,6 +13,7 @@ #include #include #include +#include #include /* This code is shared between various users of the performance @@ -139,6 +140,57 @@ static const struct pcr_ops n2_pcr_ops = { .pcr_nmi_disable = PCR_PIC_PRIV, }; +static u64 n4_pcr_read(unsigned long reg_num) +{ + unsigned long val; + + (void) sun4v_vt_get_perfreg(reg_num, &val); + + return val; +} + +static void n4_pcr_write(unsigned long reg_num, u64 val) +{ + (void) sun4v_vt_set_perfreg(reg_num, val); +} + +static u64 n4_pic_read(unsigned long reg_num) +{ + unsigned long val; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (val) + : "r" (reg_num * 0x8UL), "i" (ASI_PIC)); + + return val; +} + +static void n4_pic_write(unsigned long reg_num, u64 val) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* no outputs */ + : "r" (val), "r" (reg_num * 0x8UL), "i" (ASI_PIC)); +} + +static u64 n4_picl_value(unsigned int nmi_hz) +{ + u32 delta = local_cpu_data().clock_tick / (nmi_hz << 2); + + return ((u64)((0 - delta) & 0xffffffff)); +} + +static const struct pcr_ops n4_pcr_ops = { + .read_pcr = n4_pcr_read, + .write_pcr = n4_pcr_write, + .read_pic = n4_pic_read, + .write_pic = n4_pic_write, + .nmi_picl_value = n4_picl_value, + .pcr_nmi_enable = (PCR_N4_PICNPT | PCR_N4_STRACE | + PCR_N4_UTRACE | PCR_N4_TOE | + (26 << PCR_N4_SL_SHIFT)), + .pcr_nmi_disable = PCR_N4_PICNPT, +}; + static unsigned long perf_hsvc_group; static unsigned long perf_hsvc_major; static unsigned long perf_hsvc_minor; @@ -159,6 +211,10 @@ static int __init register_perf_hsvc(void) perf_hsvc_group = HV_GRP_KT_CPU; break; + case SUN4V_CHIP_NIAGARA4: + perf_hsvc_group = HV_GRP_VT_CPU; + break; + default: return -ENODEV; } @@ -183,6 +239,29 @@ static void __init unregister_perf_hsvc(void) sun4v_hvapi_unregister(perf_hsvc_group); } +static int __init setup_sun4v_pcr_ops(void) +{ + int ret = 0; + + switch (sun4v_chip_type) { + case SUN4V_CHIP_NIAGARA1: + case SUN4V_CHIP_NIAGARA2: + case SUN4V_CHIP_NIAGARA3: + pcr_ops = &n2_pcr_ops; + break; + + case SUN4V_CHIP_NIAGARA4: + pcr_ops = &n4_pcr_ops; + break; + + default: + ret = -ENODEV; + break; + } + + return ret; +} + int __init pcr_arch_init(void) { int err = register_perf_hsvc(); @@ -192,7 +271,9 @@ int __init pcr_arch_init(void) switch (tlb_type) { case hypervisor: - pcr_ops = &n2_pcr_ops; + err = setup_sun4v_pcr_ops(); + if (err) + goto out_unregister; break; case cheetah: -- cgit v1.2.3 From 3705665069944e003b7316ba31b44558864a00de Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 26 Aug 2012 20:12:58 -0700 Subject: sparc64: Fix spelling of CAMELLIA in CFR macro name and comment. Signed-off-by: David S. Miller --- arch/sparc/include/asm/pstate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/pstate.h b/arch/sparc/include/asm/pstate.h index 6dfa8f8c9749..4b6b998afd99 100644 --- a/arch/sparc/include/asm/pstate.h +++ b/arch/sparc/include/asm/pstate.h @@ -92,7 +92,7 @@ #define CFR_AES _AC(0x0000000000000001,UL) /* Supports AES opcodes */ #define CFR_DES _AC(0x0000000000000002,UL) /* Supports DES opcodes */ #define CFR_KASUMI _AC(0x0000000000000004,UL) /* Supports KASUMI opcodes */ -#define CFR_CAMELIA _AC(0x0000000000000008,UL) /* Supports CAMELIA opcodes */ +#define CFR_CAMELLIA _AC(0x0000000000000008,UL) /* Supports CAMELLIA opcodes*/ #define CFR_MD5 _AC(0x0000000000000010,UL) /* Supports MD5 opcodes */ #define CFR_SHA1 _AC(0x0000000000000020,UL) /* Supports SHA1 opcodes */ #define CFR_SHA256 _AC(0x0000000000000040,UL) /* Supports SHA256 opcodes */ -- cgit v1.2.3 From ce33fdc52ad50043eef07d11473bc51e225565bd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 6 Sep 2012 19:01:25 -0700 Subject: sparc64: Probe cpu page size support more portably. On sun4v, interrogate the machine description. This code is extremely defensive in nature, and a lot of the checks can probably be removed. On sun4u things are a lot simpler. There are the page sizes all chips support, and then Panther adds 32MB and 256MB pages. Report the probed value in /proc/cpuinfo Signed-off-by: David S. Miller --- arch/sparc/include/asm/mdesc.h | 1 + arch/sparc/kernel/mdesc.c | 24 ++++++++++++++++++++++++ arch/sparc/mm/init_64.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) (limited to 'arch/sparc/include/asm') diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index 9faa046713fb..139097f3a67b 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -73,6 +73,7 @@ extern void mdesc_register_notifier(struct mdesc_notifier_client *client); extern void mdesc_fill_in_cpu_data(cpumask_t *mask); extern void mdesc_populate_present_mask(cpumask_t *mask); +extern void mdesc_get_page_sizes(cpumask_t *mask, unsigned long *pgsz_mask); extern void sun4v_mdesc_init(void); diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 6dc796280589..831c001604e8 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -817,6 +817,30 @@ void __cpuinit mdesc_populate_present_mask(cpumask_t *mask) mdesc_iterate_over_cpus(record_one_cpu, NULL, mask); } +static void * __init check_one_pgsz(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg) +{ + const u64 *pgsz_prop = mdesc_get_property(hp, mp, "mmu-page-size-list", NULL); + unsigned long *pgsz_mask = arg; + u64 val; + + val = (HV_PGSZ_MASK_8K | HV_PGSZ_MASK_64K | + HV_PGSZ_MASK_512K | HV_PGSZ_MASK_4MB); + if (pgsz_prop) + val = *pgsz_prop; + + if (!*pgsz_mask) + *pgsz_mask = val; + else + *pgsz_mask &= val; + return NULL; +} + +void __init mdesc_get_page_sizes(cpumask_t *mask, unsigned long *pgsz_mask) +{ + *pgsz_mask = 0; + mdesc_iterate_over_cpus(check_one_pgsz, pgsz_mask, mask); +} + static void * __cpuinit fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg) { const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL); diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index c0fc25be0c51..445369132e03 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -83,6 +83,8 @@ unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)]; extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; #endif +static unsigned long cpu_pgsz_mask; + #define MAX_BANKS 32 static struct linux_prom64_registers pavail[MAX_BANKS] __devinitdata; @@ -419,6 +421,12 @@ EXPORT_SYMBOL(flush_icache_range); void mmu_info(struct seq_file *m) { + static const char *pgsz_strings[] = { + "8K", "64K", "512K", "4MB", "32MB", + "256MB", "2GB", "16GB", + }; + int i, printed; + if (tlb_type == cheetah) seq_printf(m, "MMU Type\t: Cheetah\n"); else if (tlb_type == cheetah_plus) @@ -430,6 +438,17 @@ void mmu_info(struct seq_file *m) else seq_printf(m, "MMU Type\t: ???\n"); + seq_printf(m, "MMU PGSZs\t: "); + printed = 0; + for (i = 0; i < ARRAY_SIZE(pgsz_strings); i++) { + if (cpu_pgsz_mask & (1UL << i)) { + seq_printf(m, "%s%s", + printed ? "," : "", pgsz_strings[i]); + printed++; + } + } + seq_putc(m, '\n'); + #ifdef CONFIG_DEBUG_DCFLUSH seq_printf(m, "DCPageFlushes\t: %d\n", atomic_read(&dcpage_flushes)); @@ -1803,6 +1822,18 @@ void __init paging_init(void) #ifndef CONFIG_SMP mdesc_fill_in_cpu_data(cpu_all_mask); #endif + mdesc_get_page_sizes(cpu_all_mask, &cpu_pgsz_mask); + } else { + unsigned long impl, ver; + + cpu_pgsz_mask = (HV_PGSZ_MASK_8K | HV_PGSZ_MASK_64K | + HV_PGSZ_MASK_512K | HV_PGSZ_MASK_4MB); + + __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver)); + impl = ((ver >> 32) & 0xffff); + if (impl == PANTHER_IMPL) + cpu_pgsz_mask |= (HV_PGSZ_MASK_32MB | + HV_PGSZ_MASK_256MB); } /* Setup bootmem... */ -- cgit v1.2.3