From patchwork Tue Apr 12 04:38:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver O'Halloran X-Patchwork-Id: 609233 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qkZ4F1pLpz9sCj for ; Tue, 12 Apr 2016 14:40:29 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=eUzYCqNG; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3qkZ4D74XrzDqCc for ; Tue, 12 Apr 2016 14:40:28 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=eUzYCqNG; dkim-atps=neutral X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Received: from mail-pf0-x242.google.com (mail-pf0-x242.google.com [IPv6:2607:f8b0:400e:c00::242]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3qkZ2g4yKfzDqBC for ; Tue, 12 Apr 2016 14:39:06 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=eUzYCqNG; dkim-atps=neutral Received: by mail-pf0-x242.google.com with SMTP id d184so570470pfc.1 for ; Mon, 11 Apr 2016 21:39:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=L5XXfEiDvnhTRyeNNzaqto2LOvXQI0yxhbk4fKtRiHQ=; b=eUzYCqNGpGUBewMZI6AA7B7fIXCGFzVJDfURTYbx1ABjF1R4O0k/fBVFDImLWkm9Xh H3YVkGrOAJFxbgUfnM/1f1rtnEjH214MdH8Y1jQaFDs3cbdAhF5me5IJoaO4EVvf5oOW TwQJEviphUTSaLemQxrWqkcuKYFf+aG3lU9sXf0Jv3qwX03N49zN6yD1hMU72t67q0sF p03F1wGjSflfayxnLlgWy+tMrGTPJKb8luqTuRrck8yEuVlSVrEOa/bL/866B4urrNVj oyAjybQtj2v1lWsAtcRrq6i3Pvc9xfILap1E7mBS8X79bNjKy14o60oqr9IObvBNRDN9 Y7gg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=L5XXfEiDvnhTRyeNNzaqto2LOvXQI0yxhbk4fKtRiHQ=; b=GBTY06P+fmjoSKPglCCCNMK5XjC4hXGwGxuIw8Q1Dl5j4HpK1+LSFHMBwUtZ4NC652 71HlWRcTM339+lQFkEhR+ZFBoHDReXNrawV7gv1m5Ya5OL+tO33EIF4cGdskKky3EeNV 4nZxBk2+TasvaPwFQOIsCEpjt8S2lprEqvSK7SylNvN5FOhXt7J1htpl8yqViC7ifiRW P1FhZ8X8nxEX/6nIWVGzhEkil8wJ0GRKnZgjoGlnq5o+3wWERufsgNpjVJYjKNlmontE sxyr8X2wbYYUmW1LYTxYryxE/euabtOWTlwH/qUVnsk4yqt8YxGGo6kBwhthAt16kBqH 88AA== X-Gm-Message-State: AOPr4FXxBFZcDPrxkFSjYSNPLHX9+swoPMRTj2zGyRl3YfOSMG3MxPJ25lHJfl3fzMhFTA== X-Received: by 10.98.19.195 with SMTP id 64mr1734705pft.62.1460435944629; Mon, 11 Apr 2016 21:39:04 -0700 (PDT) Received: from canetoad.ozlabs.ibm.com ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id h2sm39588498pfd.91.2016.04.11.21.39.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 11 Apr 2016 21:39:04 -0700 (PDT) From: Oliver O'Halloran To: linuxppc-dev@lists.ozlabs.org Subject: [PATCH 1/2] powerpc/timer - large decrementer support Date: Tue, 12 Apr 2016 14:38:47 +1000 Message-Id: <1460435928-5450-1-git-send-email-oohall@gmail.com> X-Mailer: git-send-email 2.5.5 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Oliver O'Halloran , Jack Miller MIME-Version: 1.0 Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" POWER ISA v3 adds large decrementer (LD) mode of operation which increases the size of the decrementer register from 32 bits to an implementation defined with of up to 64 bits. This patch adds support for the LD on processors with the CPU_FTR_ARCH_300 cpu feature flag set. Even for CPUs with this feature LD mode is only enabled when the property ibm,dec-bits devicetree property is supplied for the boot CPU. The decrementer value is a signed quantity (with negative values indicating a pending exception) and this property is required to find the maximum positive decrementer value. If this property is not supplied then the traditional decrementer width of 32 bits is assumed and LD mode is disabled. This patch was based on inital work by Jack Miller. Signed-off-by: Oliver O'Halloran Cc: Jack Miller --- arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/include/asm/time.h | 6 +-- arch/powerpc/kernel/time.c | 89 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 86 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index f5f4c66bbbc9..ff581ed1ab9d 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -332,6 +332,7 @@ #define LPCR_AIL_0 0x00000000 /* MMU off exception offset 0x0 */ #define LPCR_AIL_3 0x01800000 /* MMU on exception offset 0xc00...4xxx */ #define LPCR_ONL 0x00040000 /* online - PURR/SPURR count */ +#define LPCR_LD 0x00020000 /* large decremeter */ #define LPCR_PECE 0x0001f000 /* powersave exit cause enable */ #define LPCR_PECEDP 0x00010000 /* directed priv dbells cause exit */ #define LPCR_PECEDH 0x00008000 /* directed hyp dbells cause exit */ diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 1092fdd7e737..09211640a0e0 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -146,7 +146,7 @@ static inline void set_tb(unsigned int upper, unsigned int lower) * in auto-reload mode. The problem is PIT stops counting when it * hits zero. If it would wrap, we could use it just like a decrementer. */ -static inline unsigned int get_dec(void) +static inline u64 get_dec(void) { #if defined(CONFIG_40x) return (mfspr(SPRN_PIT)); @@ -160,10 +160,10 @@ static inline unsigned int get_dec(void) * in when the decrementer generates its interrupt: on the 1 to 0 * transition for Book E/4xx, but on the 0 to -1 transition for others. */ -static inline void set_dec(int val) +static inline void set_dec(u64 val) { #if defined(CONFIG_40x) - mtspr(SPRN_PIT, val); + mtspr(SPRN_PIT, (u32) val); #else #ifndef CONFIG_BOOKE --val; diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 81b0900a39ee..0afaef6b5b6a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -95,7 +95,8 @@ static struct clocksource clocksource_timebase = { .read = timebase_read, }; -#define DECREMENTER_MAX 0x7fffffff +#define DECREMENTER_DEFAULT_MAX 0x7FFFFFFF +u64 decrementer_max = DECREMENTER_DEFAULT_MAX; static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev); @@ -503,7 +504,7 @@ static void __timer_interrupt(void) __this_cpu_inc(irq_stat.timer_irqs_event); } else { now = *next_tb - now; - if (now <= DECREMENTER_MAX) + if (now <= decrementer_max) set_dec((int)now); /* We may have raced with new irq work */ if (test_irq_work_pending()) @@ -534,7 +535,7 @@ void timer_interrupt(struct pt_regs * regs) /* Ensure a positive value is written to the decrementer, or else * some CPUs will continue to take decrementer exceptions. */ - set_dec(DECREMENTER_MAX); + set_dec(decrementer_max); /* Some implementations of hotplug will get timer interrupts while * offline, just ignore these and we also need to set @@ -562,6 +563,7 @@ void timer_interrupt(struct pt_regs * regs) irq_enter(); __timer_interrupt(); + irq_exit(); set_irq_regs(old_regs); } @@ -582,9 +584,9 @@ static void generic_suspend_disable_irqs(void) * with suspending. */ - set_dec(DECREMENTER_MAX); + set_dec(decrementer_max); local_irq_disable(); - set_dec(DECREMENTER_MAX); + set_dec(decrementer_max); } static void generic_suspend_enable_irqs(void) @@ -865,7 +867,7 @@ static int decrementer_set_next_event(unsigned long evt, static int decrementer_shutdown(struct clock_event_device *dev) { - decrementer_set_next_event(DECREMENTER_MAX, dev); + decrementer_set_next_event(decrementer_max, dev); return 0; } @@ -891,6 +893,72 @@ static void register_decrementer_clockevent(int cpu) clockevents_register_device(dec); } +static inline bool large_dec_on(void) +{ + return (mfspr(SPRN_LPCR) & LPCR_LD) == LPCR_LD; +} + +static bool large_decrementer_supported(void) +{ + return cpu_has_feature(CPU_FTR_ARCH_300); +} + +/* enables the large decrementer for the current CPU */ +static void enable_large_decrementer(void) +{ + /* do we have a large decrementer? */ + if (!large_decrementer_supported()) + return; + + /* do we need a large decrementer? */ + if (decrementer_max <= DECREMENTER_DEFAULT_MAX) + return; + + mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_LD); + + if (!large_dec_on()) { + decrementer_max = DECREMENTER_DEFAULT_MAX; + + pr_debug("Failed to enable large dec on CPU %d, " + "limiting to 32 bits", smp_processor_id()); + } +} + +static void __init set_decrementer_max(void) +{ + struct device_node *cpu; + const __be32 *fp; + u64 bits = 32; + + /* dt node exists? */ + cpu = of_find_node_by_type(NULL, "cpu"); + if(cpu) + fp = of_get_property(cpu, "ibm,dec-bits", NULL); + + if(cpu && fp) { + bits = of_read_number(fp, 1); + + /* clamp to sane values */ + if (bits > 64) + bits = 64; + if (bits < 32) + bits = 32; + + /* Firmware says we support large dec but this cpu doesn't we + * should warn about it. We can still limp along with default + * 32 bit dec, but something is broken. */ + if (!large_decrementer_supported()) { + WARN_ON(bits > 32); + bits = 32; + } + + decrementer_max = (1ul << (bits - 1)) - 1; + } + + pr_info("time_init: %llu bit decrementer (max: %llx)\n", + bits, decrementer_max); +} + static void __init init_decrementer_clockevent(void) { int cpu = smp_processor_id(); @@ -898,7 +966,7 @@ static void __init init_decrementer_clockevent(void) clockevents_calc_mult_shift(&decrementer_clockevent, ppc_tb_freq, 4); decrementer_clockevent.max_delta_ns = - clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent); + clockevent_delta2ns(decrementer_max, &decrementer_clockevent); decrementer_clockevent.min_delta_ns = clockevent_delta2ns(2, &decrementer_clockevent); @@ -907,6 +975,9 @@ static void __init init_decrementer_clockevent(void) void secondary_cpu_time_init(void) { + /* Enable the large decrementer (if we need to) */ + enable_large_decrementer(); + /* Start the decrementer on CPUs that have manual control * such as BookE */ @@ -972,6 +1043,10 @@ void __init time_init(void) vdso_data->tb_update_count = 0; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; + /* initialise and enable the large decrementer (if we have one) */ + set_decrementer_max(); + enable_large_decrementer(); + /* Start the decrementer on CPUs that have manual control * such as BookE */