Merge tag 'for-5.18/parisc-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 30 Mar 2022 22:11:26 +0000 (15:11 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 30 Mar 2022 22:11:26 +0000 (15:11 -0700)
Pull more parisc architecture updates from Helge Deller:

 - Revert a patch to the invalidate/flush vmap routines which broke
   kernel patching functions on older PA-RISC machines.

 - Fix the kernel patching code wrt locking and flushing. Works now on
   B160L machine as well.

 - Fix CPU IRQ affinity for LASI, WAX and Dino chips

 - Add CPU hotplug support

 - Detect the hppa-suse-linux-gcc compiler when cross-compiling

* tag 'for-5.18/parisc-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Fix patch code locking and flushing
  parisc: Find a new timesync master if current CPU is removed
  parisc: Move common_stext into .text section when CONFIG_HOTPLUG_CPU=y
  parisc: Rewrite arch_cpu_idle_dead() for CPU hotplugging
  parisc: Implement __cpu_die() and __cpu_disable() for CPU hotplugging
  parisc: Add PDC locking functions for rendezvous code
  parisc: Move disable_sr_hashing_asm() into .text section
  parisc: Move CPU startup-related functions into .text section
  parisc: Move store_cpu_topology() into text section
  parisc: Switch from GENERIC_CPU_DEVICES to GENERIC_ARCH_TOPOLOGY
  parisc: Ensure set_firmware_width() is called only once
  parisc: Add constants for control registers and clean up mfctl()
  parisc: Detect hppa-suse-linux-gcc compiler for cross-building
  parisc: Clean up cpu_check_affinity() and drop cpu_set_affinity_irq()
  parisc: Fix CPU affinity for Lasi, WAX and Dino chips
  Revert "parisc: Fix invalidate/flush vmap routines"

25 files changed:
arch/parisc/Kconfig
arch/parisc/Makefile
arch/parisc/include/asm/pdc.h
arch/parisc/include/asm/pdcpat.h
arch/parisc/include/asm/processor.h
arch/parisc/include/asm/smp.h
arch/parisc/include/asm/special_insns.h
arch/parisc/include/asm/topology.h
arch/parisc/kernel/Makefile
arch/parisc/kernel/cache.c
arch/parisc/kernel/firmware.c
arch/parisc/kernel/head.S
arch/parisc/kernel/irq.c
arch/parisc/kernel/pacache.S
arch/parisc/kernel/patch.c
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/smp.c
arch/parisc/kernel/time.c
arch/parisc/kernel/topology.c
drivers/parisc/dino.c
drivers/parisc/gsc.c
drivers/parisc/gsc.h
drivers/parisc/lasi.c
drivers/parisc/wax.c

index 90fc95bd55cac7baae329f08dce0bf8a8bfe78c7..52e550b45692402c4aca3ec88bc571e1002da99b 100644 (file)
@@ -37,7 +37,7 @@ config PARISC
        select GENERIC_PCI_IOMAP
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_SMP_IDLE_THREAD
-       select GENERIC_CPU_DEVICES
+       select GENERIC_ARCH_TOPOLOGY if SMP
        select GENERIC_LIB_DEVMEM_IS_ALLOWED
        select SYSCTL_ARCH_UNALIGN_ALLOW
        select SYSCTL_EXCEPTION_TRACE
@@ -56,6 +56,7 @@ config PARISC
        select HAVE_ARCH_TRACEHOOK
        select HAVE_REGS_AND_STACK_ACCESS_API
        select GENERIC_SCHED_CLOCK
+       select GENERIC_IRQ_MIGRATION if SMP
        select HAVE_UNSTABLE_SCHED_CLOCK if SMP
        select LEGACY_TIMER_TICK
        select CPU_NO_EFFICIENT_FFS
@@ -279,16 +280,9 @@ config SMP
 
          If you don't know what to do here, say N.
 
-config PARISC_CPU_TOPOLOGY
-       bool "Support cpu topology definition"
-       depends on SMP
-       default y
-       help
-         Support PARISC cpu topology definition.
-
 config SCHED_MC
        bool "Multi-core scheduler support"
-       depends on PARISC_CPU_TOPOLOGY && PA8X00
+       depends on GENERIC_ARCH_TOPOLOGY && PA8X00
        help
          Multi-core scheduler support improves the CPU scheduler's decision
          making when dealing with multi-core CPU chips at a cost of slightly
index 2a9387a93592e1a3a53baa4e1b5b9d6e20416025..7583fc39ab2dae8b76cdd60d3e60128a19ddc624 100644 (file)
@@ -42,7 +42,7 @@ export LD_BFD
 
 # Set default 32 bits cross compilers for vdso
 CC_ARCHES_32 = hppa hppa2.0 hppa1.1
-CC_SUFFIXES  = linux linux-gnu unknown-linux-gnu
+CC_SUFFIXES  = linux linux-gnu unknown-linux-gnu suse-linux
 CROSS32_COMPILE := $(call cc-cross-prefix, \
        $(foreach a,$(CC_ARCHES_32), \
        $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
@@ -52,7 +52,7 @@ export CROSS32CC
 # Set default cross compiler for kernel build
 ifdef cross_compiling
        ifeq ($(CROSS_COMPILE),)
-               CC_SUFFIXES = linux linux-gnu unknown-linux-gnu
+               CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux
                CROSS_COMPILE := $(call cc-cross-prefix, \
                        $(foreach a,$(CC_ARCHES), \
                        $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
index 18b957a8630da3f0c0f97f2357e1945c5112f5e3..b643092d4b985370702d13cbef4e6d9d143bfc85 100644 (file)
@@ -94,6 +94,9 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
                  unsigned long glob_cfg);
 
 int __pdc_cpu_rendezvous(void);
+void pdc_cpu_rendezvous_lock(void);
+void pdc_cpu_rendezvous_unlock(void);
+
 static inline char * os_id_to_string(u16 os_id) {
        switch(os_id) {
        case OS_ID_NONE:        return "No OS";
index 24355ed1453a0af598cecefea4f148c3def64688..8f160375b865bf8468b06cb7e7bac5369d237b5f 100644 (file)
@@ -83,6 +83,7 @@
 #define PDC_PAT_CPU_RENDEZVOUS         6L /* Rendezvous CPU */
 #define PDC_PAT_CPU_GET_CLOCK_INFO     7L /* Return CPU Clock info */
 #define PDC_PAT_CPU_GET_RENDEZVOUS_STATE 8L /* Return Rendezvous State */
+#define PDC_PAT_CPU_GET_PDC_ENTRYPOINT 11L /* Return PDC Entry point */
 #define PDC_PAT_CPU_PLUNGE_FABRIC      128L /* Plunge Fabric */
 #define PDC_PAT_CPU_UPDATE_CACHE_CLEANSING 129L /* Manipulate Cache 
                                                  * Cleansing Mode */
@@ -356,7 +357,7 @@ struct pdc_pat_cell_mod_maddr_block {       /* PDC_PAT_CELL_MODULE */
 
 typedef struct pdc_pat_cell_mod_maddr_block pdc_pat_cell_mod_maddr_block_t;
 
-
+extern int pdc_pat_get_PDC_entrypoint(unsigned long *pdc_entry);
 extern int pdc_pat_chassis_send_log(unsigned long status, unsigned long data);
 extern int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
 extern int pdc_pat_cell_info(struct pdc_pat_cell_info_rtn_block *info,
index 00636421279549b1a2ba3a1896a536b452ba8470..4621ceb51314702a066b241bc6c8a36ec6e5b261 100644 (file)
@@ -95,6 +95,7 @@ struct cpuinfo_parisc {
 
 extern struct system_cpuinfo_parisc boot_cpu_data;
 DECLARE_PER_CPU(struct cpuinfo_parisc, cpu_data);
+extern int time_keeper_id;             /* CPU used for timekeeping */
 
 #define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
 
index 2279ebe5e2dad1028147dee2e858607be621f311..94d1f21ce99a1c43206f6a8ff2a7a0aed160b498 100644 (file)
@@ -44,12 +44,7 @@ static inline void smp_send_all_nop(void) { return; }
 
 #define NO_PROC_ID             0xFF            /* No processor magic marker */
 #define ANY_PROC_ID            0xFF            /* Any processor magic marker */
-static inline int __cpu_disable (void) {
-  return 0;
-}
-static inline void __cpu_die (unsigned int cpu) {
-  while(1)
-    ;
-}
+int __cpu_disable(void);
+void __cpu_die(unsigned int cpu);
 
 #endif /*  __ASM_SMP_H */
index 41b3ddbd344cefc5ed22e632fbac04d815fd769c..c822bd0c0e3c6ccb86b4190d15500589c70f353a 100644 (file)
        pa;                                             \
 })
 
+#define CR_EIEM 15     /* External Interrupt Enable Mask */
+#define CR_CR16 16     /* CR16 Interval Timer */
+#define CR_EIRR 23     /* External Interrupt Request Register */
+
 #define mfctl(reg)     ({              \
        unsigned long cr;               \
        __asm__ __volatile__(           \
-               "mfctl " #reg ",%0" :   \
-                "=r" (cr)              \
+               "mfctl %1,%0" :         \
+                "=r" (cr) : "i" (reg)  \
        );                              \
        cr;                             \
 })
                : /* no outputs */ \
                : "r" (gr), "i" (cr) : "memory")
 
-/* these are here to de-mystefy the calling code, and to provide hooks */
-/* which I needed for debugging EIEM problems -PB */
-#define get_eiem() mfctl(15)
-static inline void set_eiem(unsigned long val)
-{
-       mtctl(val, 15);
-}
+#define get_eiem()     mfctl(CR_EIEM)
+#define set_eiem(val)  mtctl(val, CR_EIEM)
 
 #define mfsp(reg)      ({              \
        unsigned long cr;               \
index 6f0750c74e47e1b8703df3b748cea6b7946620f5..406afb356f1a3b6f312e20310d886259574bd8eb 100644 (file)
@@ -1,33 +1,16 @@
 #ifndef _ASM_PARISC_TOPOLOGY_H
 #define _ASM_PARISC_TOPOLOGY_H
 
-#ifdef CONFIG_PARISC_CPU_TOPOLOGY
+#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
 
 #include <linux/cpumask.h>
-
-struct cputopo_parisc {
-       int thread_id;
-       int core_id;
-       int socket_id;
-       cpumask_t thread_sibling;
-       cpumask_t core_sibling;
-};
-
-extern struct cputopo_parisc cpu_topology[NR_CPUS];
-
-#define topology_physical_package_id(cpu)      (cpu_topology[cpu].socket_id)
-#define topology_core_id(cpu)          (cpu_topology[cpu].core_id)
-#define topology_core_cpumask(cpu)     (&cpu_topology[cpu].core_sibling)
-#define topology_sibling_cpumask(cpu)  (&cpu_topology[cpu].thread_sibling)
-
-void init_cpu_topology(void);
-void store_cpu_topology(unsigned int cpuid);
-const struct cpumask *cpu_coregroup_mask(int cpu);
+#include <linux/arch_topology.h>
 
 #else
 
 static inline void init_cpu_topology(void) { }
 static inline void store_cpu_topology(unsigned int cpuid) { }
+static inline void reset_cpu_topology(void) { }
 
 #endif
 
index d579243edc2fb122f44ea2bbb72cad64963fc446..d0bfac89a84272e1e8ae621ee4dc70b41ed6dbf3 100644 (file)
@@ -31,7 +31,7 @@ obj-$(CONFIG_AUDIT)   += audit.o
 obj64-$(CONFIG_AUDIT)  += compat_audit.o
 # only supported for PCX-W/U in 64-bit mode at the moment
 obj-$(CONFIG_64BIT)    += perf.o perf_asm.o $(obj64-y)
-obj-$(CONFIG_PARISC_CPU_TOPOLOGY)      += topology.o
+obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY)    += topology.o
 obj-$(CONFIG_FUNCTION_TRACER)          += ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
 obj-$(CONFIG_JUMP_LABEL)               += jump_label.o
index 456e879d34a8dccd5848a1274d8fd8cb4e87e724..23348199f3f8060e130b17819b2703b635928a52 100644 (file)
@@ -273,7 +273,7 @@ parisc_cache_init(void)
        }
 }
 
-void __init disable_sr_hashing(void)
+void disable_sr_hashing(void)
 {
        int srhash_type, retval;
        unsigned long space_bits;
@@ -611,8 +611,8 @@ void
 flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
 {
        if (pfn_valid(pfn)) {
-               flush_tlb_page(vma, vmaddr);
                if (likely(vma->vm_mm->context.space_id)) {
+                       flush_tlb_page(vma, vmaddr);
                        __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
                } else {
                        __purge_cache_page(vma, vmaddr, PFN_PHYS(pfn));
@@ -624,7 +624,6 @@ void flush_kernel_vmap_range(void *vaddr, int size)
 {
        unsigned long start = (unsigned long)vaddr;
        unsigned long end = start + size;
-       unsigned long flags, physaddr;
 
        if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
            (unsigned long)size >= parisc_cache_flush_threshold) {
@@ -633,14 +632,8 @@ void flush_kernel_vmap_range(void *vaddr, int size)
                return;
        }
 
-       while (start < end) {
-               physaddr = lpa(start);
-               purge_tlb_start(flags);
-               pdtlb(SR_KERNEL, start);
-               purge_tlb_end(flags);
-               flush_dcache_page_asm(physaddr, start);
-               start += PAGE_SIZE;
-       }
+       flush_kernel_dcache_range_asm(start, end);
+       flush_tlb_kernel_range(start, end);
 }
 EXPORT_SYMBOL(flush_kernel_vmap_range);
 
@@ -648,7 +641,6 @@ void invalidate_kernel_vmap_range(void *vaddr, int size)
 {
        unsigned long start = (unsigned long)vaddr;
        unsigned long end = start + size;
-       unsigned long flags, physaddr;
 
        if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
            (unsigned long)size >= parisc_cache_flush_threshold) {
@@ -657,13 +649,7 @@ void invalidate_kernel_vmap_range(void *vaddr, int size)
                return;
        }
 
-       while (start < end) {
-               physaddr = lpa(start);
-               purge_tlb_start(flags);
-               pdtlb(SR_KERNEL, start);
-               purge_tlb_end(flags);
-               purge_dcache_page_asm(physaddr, start);
-               start += PAGE_SIZE;
-       }
+       purge_kernel_dcache_range_asm(start, end);
+       flush_tlb_kernel_range(start, end);
 }
 EXPORT_SYMBOL(invalidate_kernel_vmap_range);
index 3370e347dde3264652d7f3782fa48c7a578a0f54..6a7e315bcc2e5b8215dd3d8769a5aa736d03c099 100644 (file)
@@ -83,7 +83,7 @@ extern unsigned long pdc_result2[NUM_PDC_RESULT];
 
 /* Firmware needs to be initially set to narrow to determine the 
  * actual firmware width. */
-int parisc_narrow_firmware __ro_after_init = 1;
+int parisc_narrow_firmware __ro_after_init = 2;
 #endif
 
 /* On most currently-supported platforms, IODC I/O calls are 32-bit calls
@@ -174,6 +174,11 @@ void set_firmware_width_unlocked(void)
 void set_firmware_width(void)
 {
        unsigned long flags;
+
+       /* already initialized? */
+       if (parisc_narrow_firmware != 2)
+               return;
+
        spin_lock_irqsave(&pdc_lock, flags);
        set_firmware_width_unlocked();
        spin_unlock_irqrestore(&pdc_lock, flags);
@@ -324,7 +329,44 @@ int __pdc_cpu_rendezvous(void)
                return mem_pdc_call(PDC_PROC, 1, 0);
 }
 
+/**
+ * pdc_cpu_rendezvous_lock - Lock PDC while transitioning to rendezvous state
+ */
+void pdc_cpu_rendezvous_lock(void)
+{
+       spin_lock(&pdc_lock);
+}
+
+/**
+ * pdc_cpu_rendezvous_unlock - Unlock PDC after reaching rendezvous state
+ */
+void pdc_cpu_rendezvous_unlock(void)
+{
+       spin_unlock(&pdc_lock);
+}
+
+/**
+ * pdc_pat_get_PDC_entrypoint - Get PDC entry point for current CPU
+ * @retval: -1 on error, 0 on success
+ */
+int pdc_pat_get_PDC_entrypoint(unsigned long *pdc_entry)
+{
+       int retval = 0;
+       unsigned long flags;
+
+       if (!IS_ENABLED(CONFIG_SMP) || !is_pdc_pat()) {
+               *pdc_entry = MEM_PDC;
+               return 0;
+       }
+
+       spin_lock_irqsave(&pdc_lock, flags);
+       retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_PDC_ENTRYPOINT,
+                       __pa(pdc_result));
+       *pdc_entry = pdc_result[0];
+       spin_unlock_irqrestore(&pdc_lock, flags);
 
+       return retval;
+}
 /**
  * pdc_chassis_warn - Fetches chassis warnings
  * @retval: -1 on error, 0 on success
index b24f77748c22b22c3fdb3143e0204391e3210eb3..e0a9e96576221a614522acc63e45f13e5248462e 100644 (file)
@@ -162,6 +162,15 @@ $pgt_fill_loop:
        /* FALLTHROUGH */
        .procend
 
+#ifdef CONFIG_HOTPLUG_CPU
+       /* common_stext is far away in another section... jump there */
+       load32          PA(common_stext), %rp
+       bv,n            (%rp)
+
+       /* common_stext and smp_slave_stext needs to be in text section */
+       .text
+#endif
+
        /*
        ** Code Common to both Monarch and Slave processors.
        ** Entry:
@@ -371,8 +380,6 @@ smp_slave_stext:
        .procend
 #endif /* CONFIG_SMP */
 
-ENDPROC(parisc_kernel_start)
-
 #ifndef CONFIG_64BIT
        .section .data..ro_after_init
 
index eb18e16362f6cb951955ec3eb8ab91f85e271160..0fe2d79fb123fa76f4ef0ad916f7707e462c8561 100644 (file)
@@ -105,28 +105,12 @@ int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest)
        if (irqd_is_per_cpu(d))
                return -EINVAL;
 
-       /* whatever mask they set, we just allow one CPU */
-       cpu_dest = cpumask_next_and(d->irq & (num_online_cpus()-1),
-                                       dest, cpu_online_mask);
+       cpu_dest = cpumask_first_and(dest, cpu_online_mask);
        if (cpu_dest >= nr_cpu_ids)
-               cpu_dest = cpumask_first_and(dest, cpu_online_mask);
+               cpu_dest = cpumask_first(cpu_online_mask);
 
        return cpu_dest;
 }
-
-static int cpu_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
-                               bool force)
-{
-       int cpu_dest;
-
-       cpu_dest = cpu_check_affinity(d, dest);
-       if (cpu_dest < 0)
-               return -1;
-
-       cpumask_copy(irq_data_get_affinity_mask(d), dest);
-
-       return 0;
-}
 #endif
 
 static struct irq_chip cpu_interrupt_type = {
@@ -135,9 +119,6 @@ static struct irq_chip cpu_interrupt_type = {
        .irq_unmask             = cpu_unmask_irq,
        .irq_ack                = cpu_ack_irq,
        .irq_eoi                = cpu_eoi_irq,
-#ifdef CONFIG_SMP
-       .irq_set_affinity       = cpu_set_affinity_irq,
-#endif
        /* XXX: Needs to be written.  We managed without it so far, but
         * we really ought to write it.
         */
@@ -582,7 +563,7 @@ static void claim_cpu_irqs(void)
 #endif
 }
 
-void __init init_IRQ(void)
+void init_IRQ(void)
 {
        local_irq_disable();    /* PARANOID - should already be disabled */
        mtctl(~0UL, 23);        /* EIRR : clear all pending external intr */
index b2ba6d63306567fe204d5ae5192f6c047ed56729..b4c3f01e2399b31b57a291beae1053cf2ee682be 100644 (file)
@@ -1264,7 +1264,7 @@ ENTRY_CFI(flush_kernel_icache_range_asm)
        nop
 ENDPROC_CFI(flush_kernel_icache_range_asm)
 
-       __INIT
+       .text
 
        /* align should cover use of rfi in disable_sr_hashing_asm and
         * srdis_done.
index 80a0ab372802db148a1ccb0867bc0eb8ae3b7b69..e59574f65e641a09cbedb2e0ca7fa5e6045f3650 100644 (file)
@@ -40,10 +40,7 @@ static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags,
 
        *need_unmap = 1;
        set_fixmap(fixmap, page_to_phys(page));
-       if (flags)
-               raw_spin_lock_irqsave(&patch_lock, *flags);
-       else
-               __acquire(&patch_lock);
+       raw_spin_lock_irqsave(&patch_lock, *flags);
 
        return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK));
 }
@@ -52,10 +49,7 @@ static void __kprobes patch_unmap(int fixmap, unsigned long *flags)
 {
        clear_fixmap(fixmap);
 
-       if (flags)
-               raw_spin_unlock_irqrestore(&patch_lock, *flags);
-       else
-               __release(&patch_lock);
+       raw_spin_unlock_irqrestore(&patch_lock, *flags);
 }
 
 void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
@@ -67,8 +61,9 @@ void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
        int mapped;
 
        /* Make sure we don't have any aliases in cache */
-       flush_kernel_vmap_range(addr, len);
-       flush_icache_range(start, end);
+       flush_kernel_dcache_range_asm(start, end);
+       flush_kernel_icache_range_asm(start, end);
+       flush_tlb_kernel_range(start, end);
 
        p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags, &mapped);
 
@@ -81,8 +76,10 @@ void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
                         * We're crossing a page boundary, so
                         * need to remap
                         */
-                       flush_kernel_vmap_range((void *)fixmap,
-                                               (p-fixmap) * sizeof(*p));
+                       flush_kernel_dcache_range_asm((unsigned long)fixmap,
+                                                     (unsigned long)p);
+                       flush_tlb_kernel_range((unsigned long)fixmap,
+                                              (unsigned long)p);
                        if (mapped)
                                patch_unmap(FIX_TEXT_POKE0, &flags);
                        p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags,
@@ -90,10 +87,10 @@ void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
                }
        }
 
-       flush_kernel_vmap_range((void *)fixmap, (p-fixmap) * sizeof(*p));
+       flush_kernel_dcache_range_asm((unsigned long)fixmap, (unsigned long)p);
+       flush_tlb_kernel_range((unsigned long)fixmap, (unsigned long)p);
        if (mapped)
                patch_unmap(FIX_TEXT_POKE0, &flags);
-       flush_icache_range(start, end);
 }
 
 void __kprobes __patch_text(void *addr, u32 insn)
index 2030c77592d3a4fcd3e7677a4b676a801b0857d3..28b6a2a5574c614d20af12cae29eedb05c6664c6 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/rcupdate.h>
 #include <linux/random.h>
 #include <linux/nmi.h>
+#include <linux/sched/hotplug.h>
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
@@ -46,6 +47,7 @@
 #include <asm/pdc_chassis.h>
 #include <asm/unwind.h>
 #include <asm/sections.h>
+#include <asm/cacheflush.h>
 
 #define COMMAND_GLOBAL  F_EXTEND(0xfffe0030)
 #define CMD_RESET       5       /* reset any module */
@@ -158,10 +160,29 @@ void release_thread(struct task_struct *dead_task)
 int running_on_qemu __ro_after_init;
 EXPORT_SYMBOL(running_on_qemu);
 
-void __cpuidle arch_cpu_idle_dead(void)
+/*
+ * Called from the idle thread for the CPU which has been shutdown.
+ */
+void arch_cpu_idle_dead(void)
 {
-       /* nop on real hardware, qemu will offline CPU. */
-       asm volatile("or %%r31,%%r31,%%r31\n":::);
+#ifdef CONFIG_HOTPLUG_CPU
+       idle_task_exit();
+
+       local_irq_disable();
+
+       /* Tell __cpu_die() that this CPU is now safe to dispose of. */
+       (void)cpu_report_death();
+
+       /* Ensure that the cache lines are written out. */
+       flush_cache_all_local();
+       flush_tlb_all_local(NULL);
+
+       /* Let PDC firmware put CPU into firmware idle loop. */
+       __pdc_cpu_rendezvous();
+
+       pr_warn("PDC does not provide rendezvous function.\n");
+#endif
+       while (1);
 }
 
 void __cpuidle arch_cpu_idle(void)
index 1b6129e7d776b5da798280f8c6616818cfc06bb4..d98692115221a119579a9eec8782db87a194f85c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
+#include <asm/topology.h>
 #include <asm/param.h>
 #include <asm/cache.h>
 #include <asm/hardware.h>      /* for register_parisc_driver() stuff */
@@ -317,7 +318,7 @@ void __init collect_boot_cpu_data(void)
  *
  * o Enable CPU profiling hooks.
  */
-int __init init_per_cpu(int cpunum)
+int init_per_cpu(int cpunum)
 {
        int ret;
        struct pdc_coproc_cfg coproc_cfg;
@@ -390,7 +391,7 @@ show_cpuinfo (struct seq_file *m, void *v)
                                 boot_cpu_data.cpu_hz / 1000000,
                                 boot_cpu_data.cpu_hz % 1000000  );
 
-#ifdef CONFIG_PARISC_CPU_TOPOLOGY
+#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
                seq_printf(m, "physical id\t: %d\n",
                                topology_physical_package_id(cpu));
                seq_printf(m, "siblings\t: %d\n",
@@ -460,5 +461,6 @@ static struct parisc_driver cpu_driver __refdata = {
  */
 void __init processor_init(void)
 {
+       reset_cpu_topology();
        register_parisc_driver(&cpu_driver);
 }
index a32a882a2d58beb9a378cb19d87e9409bbe3d432..24d0744c3b3abcaf72b7fdab3defc201c4be1c7e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ftrace.h>
 #include <linux/cpu.h>
 #include <linux/kgdb.h>
+#include <linux/sched/hotplug.h>
 
 #include <linux/atomic.h>
 #include <asm/current.h>
@@ -60,8 +61,6 @@ volatile struct task_struct *smp_init_current_idle_task;
 /* track which CPU is booting */
 static volatile int cpu_now_booting;
 
-static int parisc_max_cpus = 1;
-
 static DEFINE_PER_CPU(spinlock_t, ipi_lock);
 
 enum ipi_message_type {
@@ -269,7 +268,7 @@ void arch_send_call_function_single_ipi(int cpu)
 /*
  * Called by secondaries to update state and initialize CPU registers.
  */
-static void __init
+static void
 smp_cpu_init(int cpunum)
 {
        extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
@@ -309,7 +308,7 @@ smp_cpu_init(int cpunum)
  * Slaves start using C here. Indirectly called from smp_slave_stext.
  * Do what start_kernel() and main() do for boot strap processor (aka monarch)
  */
-void __init smp_callin(unsigned long pdce_proc)
+void smp_callin(unsigned long pdce_proc)
 {
        int slave_id = cpu_now_booting;
 
@@ -334,11 +333,28 @@ void __init smp_callin(unsigned long pdce_proc)
 /*
  * Bring one cpu online.
  */
-int smp_boot_one_cpu(int cpuid, struct task_struct *idle)
+static int smp_boot_one_cpu(int cpuid, struct task_struct *idle)
 {
        const struct cpuinfo_parisc *p = &per_cpu(cpu_data, cpuid);
        long timeout;
 
+#ifdef CONFIG_HOTPLUG_CPU
+       int i;
+
+       /* reset irq statistics for this CPU */
+       memset(&per_cpu(irq_stat, cpuid), 0, sizeof(irq_cpustat_t));
+       for (i = 0; i < NR_IRQS; i++) {
+               struct irq_desc *desc = irq_to_desc(i);
+
+               if (desc && desc->kstat_irqs)
+                       *per_cpu_ptr(desc->kstat_irqs, cpuid) = 0;
+       }
+#endif
+
+       /* wait until last booting CPU has started. */
+       while (cpu_now_booting)
+               ;
+
        /* Let _start know what logical CPU we're booting
        ** (offset into init_tasks[],cpu_data[])
        */
@@ -374,7 +390,6 @@ int smp_boot_one_cpu(int cpuid, struct task_struct *idle)
                if(cpu_online(cpuid)) {
                        /* Which implies Slave has started up */
                        cpu_now_booting = 0;
-                       smp_init_current_idle_task = NULL;
                        goto alive ;
                }
                udelay(100);
@@ -415,25 +430,88 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                spin_lock_init(&per_cpu(ipi_lock, cpu));
 
        init_cpu_present(cpumask_of(0));
-
-       parisc_max_cpus = max_cpus;
-       if (!max_cpus)
-               printk(KERN_INFO "SMP mode deactivated.\n");
 }
 
 
-void smp_cpus_done(unsigned int cpu_max)
+void __init smp_cpus_done(unsigned int cpu_max)
 {
-       return;
 }
 
 
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
-       if (cpu != 0 && cpu < parisc_max_cpus && smp_boot_one_cpu(cpu, tidle))
-               return -ENOSYS;
+       if (cpu_online(cpu))
+               return 0;
+
+       if (num_online_cpus() < setup_max_cpus && smp_boot_one_cpu(cpu, tidle))
+               return -EIO;
+
+       return cpu_online(cpu) ? 0 : -EIO;
+}
+
+/*
+ * __cpu_disable runs on the processor to be shutdown.
+ */
+int __cpu_disable(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       unsigned int cpu = smp_processor_id();
+
+       remove_cpu_topology(cpu);
+
+       /*
+        * Take this CPU offline.  Once we clear this, we can't return,
+        * and we must not schedule until we're ready to give up the cpu.
+        */
+       set_cpu_online(cpu, false);
+
+       /* Find a new timesync master */
+       if (cpu == time_keeper_id) {
+               time_keeper_id = cpumask_first(cpu_online_mask);
+               pr_info("CPU %d is now promoted to time-keeper master\n", time_keeper_id);
+       }
+
+       disable_percpu_irq(IPI_IRQ);
+
+       irq_migrate_all_off_this_cpu();
+
+       flush_cache_all_local();
+       flush_tlb_all_local(NULL);
+
+       /* disable all irqs, including timer irq */
+       local_irq_disable();
+
+       /* wait for next timer irq ... */
+       mdelay(1000/HZ+100);
+
+       /* ... and then clear all pending external irqs */
+       set_eiem(0);
+       mtctl(~0UL, CR_EIRR);
+       mfctl(CR_EIRR);
+       mtctl(0, CR_EIRR);
+#endif
+       return 0;
+}
+
+/*
+ * called on the thread which is asking for a CPU to be shutdown -
+ * waits until shutdown has completed, or it is timed out.
+ */
+void __cpu_die(unsigned int cpu)
+{
+       pdc_cpu_rendezvous_lock();
+
+       if (!cpu_wait_death(cpu, 5)) {
+               pr_crit("CPU%u: cpu didn't die\n", cpu);
+               return;
+       }
+       pr_info("CPU%u: is shutting down\n", cpu);
+
+       /* set task's state to interruptible sleep */
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout((IS_ENABLED(CONFIG_64BIT) ? 8:2) * HZ);
 
-       return cpu_online(cpu) ? 0 : -ENOSYS;
+       pdc_cpu_rendezvous_unlock();
 }
 
 #ifdef CONFIG_PROC_FS
index 061119a56fbe81b0a64540de3ff6d2596f5ec112..bb27dfeeddfcc2f776c70ccf0a84df3c8971da09 100644 (file)
@@ -40,6 +40,8 @@
 
 #include <linux/timex.h>
 
+int time_keeper_id __read_mostly;      /* CPU used for timekeeping. */
+
 static unsigned long clocktick __ro_after_init;        /* timer cycles per tick */
 
 /*
@@ -84,7 +86,7 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
        cpuinfo->it_value = next_tick;
 
        /* Go do system house keeping. */
-       if (cpu != 0)
+       if (IS_ENABLED(CONFIG_SMP) && (cpu != time_keeper_id))
                ticks_elapsed = 0;
        legacy_timer_tick(ticks_elapsed);
 
@@ -150,7 +152,7 @@ static struct clocksource clocksource_cr16 = {
        .flags                  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-void __init start_cpu_itimer(void)
+void start_cpu_itimer(void)
 {
        unsigned int cpu = smp_processor_id();
        unsigned long next_tick = mfctl(16) + clocktick;
index e88a6ce7c96d5bdaf2918d852389b7f8f9519a7c..9696e3cb6a2a65668982a9be8c1e564ffb2b43d7 100644 (file)
 #include <linux/percpu.h>
 #include <linux/sched.h>
 #include <linux/sched/topology.h>
+#include <linux/cpu.h>
 
 #include <asm/topology.h>
+#include <asm/sections.h>
 
- /*
-  * cpu topology table
-  */
-struct cputopo_parisc cpu_topology[NR_CPUS] __read_mostly;
-EXPORT_SYMBOL_GPL(cpu_topology);
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
-const struct cpumask *cpu_coregroup_mask(int cpu)
-{
-       return &cpu_topology[cpu].core_sibling;
-}
-
-static void update_siblings_masks(unsigned int cpuid)
-{
-       struct cputopo_parisc *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
-       int cpu;
-
-       /* update core and thread sibling masks */
-       for_each_possible_cpu(cpu) {
-               cpu_topo = &cpu_topology[cpu];
-
-               if (cpuid_topo->socket_id != cpu_topo->socket_id)
-                       continue;
-
-               cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
-               if (cpu != cpuid)
-                       cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
-
-               if (cpuid_topo->core_id != cpu_topo->core_id)
-                       continue;
-
-               cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
-               if (cpu != cpuid)
-                       cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
-       }
-       smp_wmb();
-}
-
-static int dualcores_found __initdata;
+static int dualcores_found;
 
 /*
  * store_cpu_topology is called at boot when only one cpu is running
  * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
  * which prevents simultaneous write access to cpu_topology array
  */
-void __init store_cpu_topology(unsigned int cpuid)
+void store_cpu_topology(unsigned int cpuid)
 {
-       struct cputopo_parisc *cpuid_topo = &cpu_topology[cpuid];
+       struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
        struct cpuinfo_parisc *p;
        int max_socket = -1;
        unsigned long cpu;
@@ -71,6 +38,12 @@ void __init store_cpu_topology(unsigned int cpuid)
        if (cpuid_topo->core_id != -1)
                return;
 
+#ifdef CONFIG_HOTPLUG_CPU
+       per_cpu(cpu_devices, cpuid).hotpluggable = 1;
+#endif
+       if (register_cpu(&per_cpu(cpu_devices, cpuid), cpuid))
+               pr_warn("Failed to register CPU%d device", cpuid);
+
        /* create cpu topology mapping */
        cpuid_topo->thread_id = -1;
        cpuid_topo->core_id = 0;
@@ -86,25 +59,25 @@ void __init store_cpu_topology(unsigned int cpuid)
                        cpuid_topo->core_id = cpu_topology[cpu].core_id;
                        if (p->cpu_loc) {
                                cpuid_topo->core_id++;
-                               cpuid_topo->socket_id = cpu_topology[cpu].socket_id;
+                               cpuid_topo->package_id = cpu_topology[cpu].package_id;
                                dualcores_found = 1;
                                continue;
                        }
                }
 
-               if (cpuid_topo->socket_id == -1)
-                       max_socket = max(max_socket, cpu_topology[cpu].socket_id);
+               if (cpuid_topo->package_id == -1)
+                       max_socket = max(max_socket, cpu_topology[cpu].package_id);
        }
 
-       if (cpuid_topo->socket_id == -1)
-               cpuid_topo->socket_id = max_socket + 1;
+       if (cpuid_topo->package_id == -1)
+               cpuid_topo->package_id = max_socket + 1;
 
        update_siblings_masks(cpuid);
 
        pr_info("CPU%u: cpu core %d of socket %d\n",
                cpuid,
                cpu_topology[cpuid].core_id,
-               cpu_topology[cpuid].socket_id);
+               cpu_topology[cpuid].package_id);
 }
 
 static struct sched_domain_topology_level parisc_mc_topology[] = {
@@ -122,20 +95,6 @@ static struct sched_domain_topology_level parisc_mc_topology[] = {
  */
 void __init init_cpu_topology(void)
 {
-       unsigned int cpu;
-
-       /* init core mask and capacity */
-       for_each_possible_cpu(cpu) {
-               struct cputopo_parisc *cpu_topo = &(cpu_topology[cpu]);
-
-               cpu_topo->thread_id = -1;
-               cpu_topo->core_id =  -1;
-               cpu_topo->socket_id = -1;
-               cpumask_clear(&cpu_topo->core_sibling);
-               cpumask_clear(&cpu_topo->thread_sibling);
-       }
-       smp_wmb();
-
        /* Set scheduler topology descriptor */
        if (dualcores_found)
                set_sched_topology(parisc_mc_topology);
index 952a92504df69aa5c627ec8b38854c48c5c5a999..e33036281327d484c9470772839ede70e7b5e85d 100644 (file)
@@ -142,9 +142,8 @@ struct dino_device
 {
        struct pci_hba_data     hba;    /* 'C' inheritance - must be first */
        spinlock_t              dinosaur_pen;
-       unsigned long           txn_addr; /* EIR addr to generate interrupt */ 
-       u32                     txn_data; /* EIR data assign to each dino */ 
        u32                     imr;      /* IRQ's which are enabled */ 
+       struct gsc_irq          gsc_irq;
        int                     global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
 #ifdef DINO_DEBUG
        unsigned int            dino_irr0; /* save most recent IRQ line stat */
@@ -339,14 +338,43 @@ static void dino_unmask_irq(struct irq_data *d)
        if (tmp & DINO_MASK_IRQ(local_irq)) {
                DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
                                __func__, tmp);
-               gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
+               gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr);
        }
 }
 
+#ifdef CONFIG_SMP
+static int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+                               bool force)
+{
+       struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
+       struct cpumask tmask;
+       int cpu_irq;
+       u32 eim;
+
+       if (!cpumask_and(&tmask, dest, cpu_online_mask))
+               return -EINVAL;
+
+       cpu_irq = cpu_check_affinity(d, &tmask);
+       if (cpu_irq < 0)
+               return cpu_irq;
+
+       dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
+       eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
+       __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
+
+       irq_data_update_effective_affinity(d, &tmask);
+
+       return IRQ_SET_MASK_OK;
+}
+#endif
+
 static struct irq_chip dino_interrupt_type = {
        .name           = "GSC-PCI",
        .irq_unmask     = dino_unmask_irq,
        .irq_mask       = dino_mask_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = dino_set_affinity_irq,
+#endif
 };
 
 
@@ -806,7 +834,6 @@ static int __init dino_common_init(struct parisc_device *dev,
 {
        int status;
        u32 eim;
-       struct gsc_irq gsc_irq;
        struct resource *res;
 
        pcibios_register_hba(&dino_dev->hba);
@@ -821,10 +848,8 @@ static int __init dino_common_init(struct parisc_device *dev,
        **   still only has 11 IRQ input lines - just map some of them
        **   to a different processor.
        */
-       dev->irq = gsc_alloc_irq(&gsc_irq);
-       dino_dev->txn_addr = gsc_irq.txn_addr;
-       dino_dev->txn_data = gsc_irq.txn_data;
-       eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+       dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq);
+       eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
 
        /* 
        ** Dino needs a PA "IRQ" to get a processor's attention.
index ed9371acf37eb6b40b649b4eec1607531cd2e17f..ec175ae998733bb69f90217eb2794e25d66e9ab5 100644 (file)
@@ -135,10 +135,41 @@ static void gsc_asic_unmask_irq(struct irq_data *d)
         */
 }
 
+#ifdef CONFIG_SMP
+static int gsc_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+                               bool force)
+{
+       struct gsc_asic *gsc_dev = irq_data_get_irq_chip_data(d);
+       struct cpumask tmask;
+       int cpu_irq;
+
+       if (!cpumask_and(&tmask, dest, cpu_online_mask))
+               return -EINVAL;
+
+       cpu_irq = cpu_check_affinity(d, &tmask);
+       if (cpu_irq < 0)
+               return cpu_irq;
+
+       gsc_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
+       gsc_dev->eim = ((u32) gsc_dev->gsc_irq.txn_addr) | gsc_dev->gsc_irq.txn_data;
+
+       /* switch IRQ's for devices below LASI/WAX to other CPU */
+       gsc_writel(gsc_dev->eim, gsc_dev->hpa + OFFSET_IAR);
+
+       irq_data_update_effective_affinity(d, &tmask);
+
+       return IRQ_SET_MASK_OK;
+}
+#endif
+
+
 static struct irq_chip gsc_asic_interrupt_type = {
        .name           =       "GSC-ASIC",
        .irq_unmask     =       gsc_asic_unmask_irq,
        .irq_mask       =       gsc_asic_mask_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity =     gsc_set_affinity_irq,
+#endif
 };
 
 int gsc_assign_irq(struct irq_chip *type, void *data)
index 86abad3fa2150b8bc61c1e66fc79354855026482..73cbd0bb1975a071063ff3cc70165d721e1fb96b 100644 (file)
@@ -31,6 +31,7 @@ struct gsc_asic {
        int version;
        int type;
        int eim;
+       struct gsc_irq gsc_irq;
        int global_irq[32];
 };
 
index 4e4fd12c2112ea805783313567a4dacddc1c52e1..6ef621adb63a850a47a4d37d05461a4ec2330150 100644 (file)
@@ -163,7 +163,6 @@ static int __init lasi_init_chip(struct parisc_device *dev)
 {
        extern void (*chassis_power_off)(void);
        struct gsc_asic *lasi;
-       struct gsc_irq gsc_irq;
        int ret;
 
        lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
@@ -185,7 +184,7 @@ static int __init lasi_init_chip(struct parisc_device *dev)
        lasi_init_irq(lasi);
 
        /* the IRQ lasi should use */
-       dev->irq = gsc_alloc_irq(&gsc_irq);
+       dev->irq = gsc_alloc_irq(&lasi->gsc_irq);
        if (dev->irq < 0) {
                printk(KERN_ERR "%s(): cannot get GSC irq\n",
                                __func__);
@@ -193,9 +192,9 @@ static int __init lasi_init_chip(struct parisc_device *dev)
                return -EBUSY;
        }
 
-       lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+       lasi->eim = ((u32) lasi->gsc_irq.txn_addr) | lasi->gsc_irq.txn_data;
 
-       ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
+       ret = request_irq(lasi->gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
        if (ret < 0) {
                kfree(lasi);
                return ret;
index 5b6df1516235470167198138e0cdbcfdd5feef95..73a2b01f8d9ca7b33077e19637f92e04a7ac22c1 100644 (file)
@@ -68,7 +68,6 @@ static int __init wax_init_chip(struct parisc_device *dev)
 {
        struct gsc_asic *wax;
        struct parisc_device *parent;
-       struct gsc_irq gsc_irq;
        int ret;
 
        wax = kzalloc(sizeof(*wax), GFP_KERNEL);
@@ -85,7 +84,7 @@ static int __init wax_init_chip(struct parisc_device *dev)
        wax_init_irq(wax);
 
        /* the IRQ wax should use */
-       dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
+       dev->irq = gsc_claim_irq(&wax->gsc_irq, WAX_GSC_IRQ);
        if (dev->irq < 0) {
                printk(KERN_ERR "%s(): cannot get GSC irq\n",
                                __func__);
@@ -93,9 +92,9 @@ static int __init wax_init_chip(struct parisc_device *dev)
                return -EBUSY;
        }
 
-       wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+       wax->eim = ((u32) wax->gsc_irq.txn_addr) | wax->gsc_irq.txn_data;
 
-       ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
+       ret = request_irq(wax->gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
        if (ret < 0) {
                kfree(wax);
                return ret;