From 08a491b2e4b1c4c618ee82d3f4b0ff3b20c5acf5 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 27 Mar 2022 18:53:42 +0200 Subject: Revert "parisc: Fix invalidate/flush vmap routines" This reverts commit 53d862fac4a09b9c56cca0433fa9de5732fd05a1. It turned out that flush_kernel_vmap_range() is being called with interrupts disabled. There's no way to flush entire cache with interrupts disabled. Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 456e879d34a8..d41fee3a9874 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -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); -- cgit From ac2dd327944548fe732b3f7173b983791bde42a4 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 27 Mar 2022 15:41:06 +0200 Subject: parisc: Clean up cpu_check_affinity() and drop cpu_set_affinity_irq() The cpu_set_affinity_irq() isn't needed. Not the CPU irqs need to change, but the slave irq chips simply need to be reprogrammed to a new CPU irq with the txn_* functions. Signed-off-by: Helge Deller --- arch/parisc/kernel/irq.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index eb18e16362f6..928ce9dbc738 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -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. */ -- cgit From ed9794812b0a61f62317991c5c3e6c78749a0bdc Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 21 Mar 2022 22:02:01 +0100 Subject: parisc: Detect hppa-suse-linux-gcc compiler for cross-building Allow the system to find the SUSE hppa compiler and linker to set CROSS32_COMPILE and CROSS_COMPILE. Suggested-by: Jiri Slaby Signed-off-by: Helge Deller --- arch/parisc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 2a9387a93592..7583fc39ab2d 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -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)-))) -- cgit From 7e0b2be94c3142c4ce1e9f7f28747dea4a1ef5bd Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 17:37:51 +0100 Subject: parisc: Add constants for control registers and clean up mfctl() Clean up the code for the mfctl() and mtctl() functions and add often used constants. Signed-off-by: Helge Deller --- arch/parisc/include/asm/special_insns.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h index 41b3ddbd344c..c822bd0c0e3c 100644 --- a/arch/parisc/include/asm/special_insns.h +++ b/arch/parisc/include/asm/special_insns.h @@ -30,11 +30,15 @@ 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; \ }) @@ -44,13 +48,8 @@ : /* 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; \ -- cgit From 1e93848a385ed2c2df9cb246b073dc8c66d10793 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 13:10:45 +0100 Subject: parisc: Ensure set_firmware_width() is called only once Call set_firmware_width() only once at runtime. This prevents that hotplugged CPUs will get stuck in spinlocks later on. Signed-off-by: Helge Deller --- arch/parisc/kernel/firmware.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 3370e347dde3..c6b11bdb8602 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -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); -- cgit From 62773112acc55d29727465d075fc61ed08a0a532 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 24 Mar 2022 19:46:50 +0100 Subject: parisc: Switch from GENERIC_CPU_DEVICES to GENERIC_ARCH_TOPOLOGY Switch away from the own cpu topology code to common code which is used by ARM64 and RISCV. That will allow us to enable CPU hotplug later on. Signed-off-by: Helge Deller --- arch/parisc/Kconfig | 11 ++---- arch/parisc/include/asm/topology.h | 23 ++---------- arch/parisc/kernel/Makefile | 2 +- arch/parisc/kernel/processor.c | 4 ++- arch/parisc/kernel/topology.c | 72 ++++++++------------------------------ 5 files changed, 24 insertions(+), 88 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 90fc95bd55ca..590843b8a62e 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -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 @@ -279,16 +279,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 diff --git a/arch/parisc/include/asm/topology.h b/arch/parisc/include/asm/topology.h index 6f0750c74e47..406afb356f1a 100644 --- a/arch/parisc/include/asm/topology.h +++ b/arch/parisc/include/asm/topology.h @@ -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 - -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 #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 diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index d579243edc2f..d0bfac89a842 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -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 diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 1b6129e7d776..f48823eba75f 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include /* for register_parisc_driver() stuff */ @@ -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); } diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c index e88a6ce7c96d..8fce9a5350ef 100644 --- a/arch/parisc/kernel/topology.c +++ b/arch/parisc/kernel/topology.c @@ -13,45 +13,11 @@ #include #include #include +#include #include - /* - * cpu topology table - */ -struct cputopo_parisc cpu_topology[NR_CPUS] __read_mostly; -EXPORT_SYMBOL_GPL(cpu_topology); - -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 DEFINE_PER_CPU(struct cpu, cpu_devices); static int dualcores_found __initdata; @@ -62,7 +28,7 @@ static int dualcores_found __initdata; */ void __init 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 +37,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 +58,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 +94,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); -- cgit From 95370b4031ec67f9749e5873ae7139a53cc6bf53 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 12:50:13 +0100 Subject: parisc: Move store_cpu_topology() into text section Signed-off-by: Helge Deller --- arch/parisc/kernel/topology.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c index 8fce9a5350ef..9696e3cb6a2a 100644 --- a/arch/parisc/kernel/topology.c +++ b/arch/parisc/kernel/topology.c @@ -16,17 +16,18 @@ #include #include +#include static DEFINE_PER_CPU(struct cpu, cpu_devices); -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 cpu_topology *cpuid_topo = &cpu_topology[cpuid]; struct cpuinfo_parisc *p; -- cgit From beb48dfd9672f82413e3b2bac220331073afbb02 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 26 Mar 2022 15:10:54 +0100 Subject: parisc: Move CPU startup-related functions into .text section If CONFIG_HOTPLUG_CPU is enabled, those functions will be run again after bootup. So they need to reside in the .text section. Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 2 +- arch/parisc/kernel/irq.c | 2 +- arch/parisc/kernel/processor.c | 2 +- arch/parisc/kernel/time.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index d41fee3a9874..23348199f3f8 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -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; diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 928ce9dbc738..0fe2d79fb123 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -563,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 */ diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index f48823eba75f..d98692115221 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -318,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; diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 061119a56fbe..874b128c5783 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -150,7 +150,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; -- cgit From 4d7d4c3fc1aed6bf95fa188c30bc9ba5901f6531 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 12:52:24 +0100 Subject: parisc: Move disable_sr_hashing_asm() into .text section Signed-off-by: Helge Deller --- arch/parisc/kernel/pacache.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index b2ba6d633065..b4c3f01e2399 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -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. -- cgit From db2b0d76cdc4e781d32bf26d0c649ca2fe608c4e Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 29 Mar 2022 14:15:29 +0200 Subject: parisc: Add PDC locking functions for rendezvous code Add pdc_cpu_rendezvous_lock() and pdc_cpu_rendezvous_unlock() to lock PDC while CPU is transitioning into rendezvous state. This is needed, because the transition phase may take up to 8 seconds. Add pdc_pat_get_PDC_entrypoint() to get PDC entry point for current CPU. Signed-off-by: Helge Deller --- arch/parisc/include/asm/pdc.h | 3 +++ arch/parisc/include/asm/pdcpat.h | 3 ++- arch/parisc/kernel/firmware.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) (limited to 'arch/parisc') diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h index 18b957a8630d..b643092d4b98 100644 --- a/arch/parisc/include/asm/pdc.h +++ b/arch/parisc/include/asm/pdc.h @@ -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"; diff --git a/arch/parisc/include/asm/pdcpat.h b/arch/parisc/include/asm/pdcpat.h index 24355ed1453a..8f160375b865 100644 --- a/arch/parisc/include/asm/pdcpat.h +++ b/arch/parisc/include/asm/pdcpat.h @@ -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, diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index c6b11bdb8602..6a7e315bcc2e 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -329,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 -- cgit From 88b3aac6228baaac6a3bcc0808845083b9d9f08f Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 14:31:08 +0100 Subject: parisc: Implement __cpu_die() and __cpu_disable() for CPU hotplugging Add relevant code to __cpu_die() and __cpu_disable() to finally enable the CPU hotplugging features. Reset the irq count values in smp_callin() to zero before bringing up the CPU. It seems that the firmware may need up to 8 seconds to fully stop a CPU in which no other PDC calls are allowed to be made. Use a timeout __cpu_die() to accommodate for this. Use "chcpu -d 1" to bring CPU1 down, and "chcpu -e 1" to bring it up. Signed-off-by: Helge Deller --- arch/parisc/Kconfig | 1 + arch/parisc/include/asm/smp.h | 9 +--- arch/parisc/kernel/smp.c | 102 +++++++++++++++++++++++++++++++++++------- 3 files changed, 90 insertions(+), 22 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 590843b8a62e..52e550b45692 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -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 diff --git a/arch/parisc/include/asm/smp.h b/arch/parisc/include/asm/smp.h index 2279ebe5e2da..94d1f21ce99a 100644 --- a/arch/parisc/include/asm/smp.h +++ b/arch/parisc/include/asm/smp.h @@ -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 */ diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index a32a882a2d58..8c5ea457b6e1 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -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,82 @@ 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); + + 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 -- cgit From 98903688e6106d9ca68e44c7d218e61336d54631 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 14:27:21 +0100 Subject: parisc: Rewrite arch_cpu_idle_dead() for CPU hotplugging Let the PDC firmware put the CPU into firmware idle loop with the pdc_cpu_rendezvous() function. Signed-off-by: Helge Deller --- arch/parisc/kernel/process.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 2030c77592d3..28b6a2a5574c 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #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) -- cgit From ca45ec3cb44aabe0933f9e10dba1b6946afb2a13 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 25 Mar 2022 14:22:57 +0100 Subject: parisc: Move common_stext into .text section when CONFIG_HOTPLUG_CPU=y Move the common_stext function into the non-init text section if hotplug is enabled. This function is called from the firmware when hotplugged CPUs are brought up. Signed-off-by: Helge Deller --- arch/parisc/kernel/head.S | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index b24f77748c22..e0a9e9657622 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -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 -- cgit From 1afde47d082c92c4fd3d9b322d944f8d87469834 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 27 Mar 2022 15:03:53 +0200 Subject: parisc: Find a new timesync master if current CPU is removed When CPU hotplugging is enabled, the user may want to remove the current CPU which is providing the timer ticks. If this happens we need to find a new timesync master. Signed-off-by: Helge Deller --- arch/parisc/include/asm/processor.h | 1 + arch/parisc/kernel/smp.c | 6 ++++++ arch/parisc/kernel/time.c | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'arch/parisc') diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index 006364212795..4621ceb51314 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -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) diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 8c5ea457b6e1..24d0744c3b3a 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -465,6 +465,12 @@ int __cpu_disable(void) */ 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(); diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 874b128c5783..bb27dfeeddfc 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -40,6 +40,8 @@ #include +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); -- cgit From a9fe7fa7d874a536e0540469f314772c054a0323 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 29 Mar 2022 18:54:36 +0000 Subject: parisc: Fix patch code locking and flushing This change fixes the following: 1) The flags variable is not initialized. Always use raw_spin_lock_irqsave and raw_spin_unlock_irqrestore to serialize patching. 2) flush_kernel_vmap_range is primarily intended for DMA flushes. Since __patch_text_multiple is often called with interrupts disabled, it is better to directly call flush_kernel_dcache_range_asm and flush_kernel_icache_range_asm. This avoids an extra call. 3) The final call to flush_icache_range is unnecessary. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/patch.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'arch/parisc') diff --git a/arch/parisc/kernel/patch.c b/arch/parisc/kernel/patch.c index 80a0ab372802..e59574f65e64 100644 --- a/arch/parisc/kernel/patch.c +++ b/arch/parisc/kernel/patch.c @@ -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) -- cgit