]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: add hot-patched and inlined get_tick()
authorPavel Tatashin <pasha.tatashin@oracle.com>
Mon, 12 Jun 2017 20:41:47 +0000 (16:41 -0400)
committerAllen Pais <allen.pais@oracle.com>
Thu, 29 Jun 2017 08:09:43 +0000 (13:39 +0530)
Add the new get_tick() function that is hot-patched during boot based on
processor we are booting on.

Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Orabug: 24401250
Orabug: 25637776

(cherry picked from commit 4929c83a6ce6584cb64381bf1407c487f67d588a)
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Signed-off-by: Allen Pais <allen.pais@oracle.com>
arch/sparc/include/asm/timer_64.h
arch/sparc/kernel/time_64.c
arch/sparc/kernel/vmlinux.lds.S

index 61d07251792c9f09eb3c9ac2fc1d7f5c83dde954..51bc3bc54bfe60014f5a59f7ed439b8a7da26f0b 100644 (file)
@@ -34,4 +34,64 @@ unsigned long sparc64_get_clock_tick(unsigned int cpu);
 void setup_sparc64_timer(void);
 void __init time_init(void);
 
+#define TICK_PRIV_BIT          BIT(63)
+#define TICKCMP_IRQ_BIT                BIT(63)
+
+#define HBIRD_STICKCMP_ADDR    0x1fe0000f060UL
+#define HBIRD_STICK_ADDR       0x1fe0000f070UL
+
+#define GET_TICK_NINSTR                13
+struct get_tick_patch {
+       unsigned int    addr;
+       unsigned int    tick[GET_TICK_NINSTR];
+       unsigned int    stick[GET_TICK_NINSTR];
+};
+
+extern struct get_tick_patch __get_tick_patch;
+extern struct get_tick_patch __get_tick_patch_end;
+
+static inline unsigned long get_tick(void)
+{
+       unsigned long tick, tmp1, tmp2;
+
+       __asm__ __volatile__(
+       /* read hbtick 13 instructions */
+       "661:\n"
+       "       mov     0x1fe, %1\n"
+       "       sllx    %1, 0x20, %1\n"
+       "       sethi   %%hi(0xf000), %2\n"
+       "       or      %2, 0x70, %2\n"
+       "       or      %1, %2, %1\n"   /* %1 = HBIRD_STICK_ADDR */
+       "       add     %1, 8, %2\n"
+       "       ldxa    [%2]%3, %0\n"
+       "       ldxa    [%1]%3, %1\n"
+       "       ldxa    [%2]%3, %2\n"
+       "       sub     %2, %0, %0\n"   /* don't modify %xcc */
+       "       brnz,pn %0, 661b\n"     /* restart to save one register */
+       "        sllx   %2, 32, %2\n"
+       "       or      %2, %1, %0\n"
+       /* Common/not patched code */
+       "       sllx    %0, 1, %0\n"
+       "       srlx    %0, 1, %0\n"    /* Clear TICK_PRIV_BIT */
+       /* Beginning of patch section */
+       "       .section .get_tick_patch, \"ax\"\n"
+       "       .word   661b\n"
+       /* read tick 2 instructions and 11 skipped */
+       "       ba      1f\n"
+       "        rd     %%tick, %0\n"
+       "       .skip   4 * (%4 - 2)\n"
+       "1:\n"
+       /* read stick 2 instructions and 11 skipped */
+       "       ba      1f\n"
+       "        rd     %%asr24, %0\n"
+       "       .skip   4 * (%4 - 2)\n"
+       "1:\n"
+       /* End of patch section */
+       "       .previous\n"
+       : "=&r" (tick), "=&r" (tmp1), "=&r" (tmp2)
+       : "i" (ASI_PHYS_BYPASS_EC_E), "i" (GET_TICK_NINSTR));
+
+       return tick;
+}
+
 #endif /* _SPARC64_TIMER_H */
index 3d6a52e1a14a666d31f4921d67ecc85b89952699..2484a4a1e62a8cdd808ecfba46838cea3375715d 100644 (file)
 #include <asm/cpudata.h>
 #include <asm/uaccess.h>
 #include <asm/irq_regs.h>
+#include <asm/cacheflush.h>
 
 #include "entry.h"
 #include "kernel.h"
 
 DEFINE_SPINLOCK(rtc_lock);
 
-#define TICK_PRIV_BIT  (1UL << 63)
-#define TICKCMP_IRQ_BIT        (1UL << 63)
-
 #ifdef CONFIG_SMP
 unsigned long profile_pc(struct pt_regs *regs)
 {
@@ -290,9 +288,6 @@ static struct sparc64_tick_ops stick_operations __read_mostly = {
  * 2) write high
  * 3) write low
  */
-#define HBIRD_STICKCMP_ADDR    0x1fe0000f060UL
-#define HBIRD_STICK_ADDR       0x1fe0000f070UL
-
 static unsigned long __hbird_read_stick(void)
 {
        unsigned long ret, tmp1, tmp2, tmp3;
@@ -790,6 +785,26 @@ static cycle_t clocksource_tick_read(struct clocksource *cs)
        return tick_operations.get_tick();
 }
 
+static void __init get_tick_patch(void)
+{
+       unsigned int *addr, *instr, i;
+       struct get_tick_patch *p;
+
+       if (tlb_type == spitfire && is_hummingbird())
+               return;
+
+       for (p = &__get_tick_patch; p < &__get_tick_patch_end; p++) {
+               instr = (tlb_type == spitfire) ? p->tick : p->stick;
+               addr = (unsigned int *)(unsigned long)p->addr;
+               for (i = 0; i < GET_TICK_NINSTR; i++) {
+                       addr[i] = instr[i];
+                       /* ensure that address is modified before flush */
+                       wmb();
+                       flushi(&addr[i]);
+               }
+       }
+}
+
 static void init_tick_ops(struct sparc64_tick_ops *ops)
 {
        unsigned long freq, quotient, tick;
@@ -802,6 +817,7 @@ static void init_tick_ops(struct sparc64_tick_ops *ops)
        ops->ticks_per_nsec_quotient = quotient;
        ops->frequency = freq;
        tick_operations = *ops;
+       get_tick_patch();
 }
 
 void __init time_init_early(void)
index 74438d8d08d01aecf645092ba3de5e1511f2023b..ec931a3b362d93cbed8bd67039ed99ae864e1924 100644 (file)
@@ -148,6 +148,11 @@ SECTIONS
                *(.sun4v_adi_2insn_patch)
                __sun4v_adi_2insn_patch_end = .;
        }
+       .get_tick_patch : {
+               __get_tick_patch = .;
+               *(.get_tick_patch)
+               __get_tick_patch_end = .;
+       }
        PERCPU_SECTION(SMP_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);