Commit 837c07cf authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-6.2-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fixes from Michael Ellerman:
 "It's a bit of a big batch for rc6, but just because I didn't send any
  fixes the last week or two while I was on vacation, next week should
  be quieter:

   - Fix a few objtool warnings since we recently enabled objtool.

   - Fix a deadlock with the hash MMU vs perf record.

   - Fix perf profiling of asynchronous interrupt handlers.

   - Revert the IMC PMU nest_init_lock to being a mutex.

   - Two commits fixing problems with the kexec_file FDT size
     estimation.

   - Two commits fixing problems with strict RWX vs kernels running at
     non-zero.

   - Reconnect tlb_flush() to hash__tlb_flush()

  Thanks to Kajol Jain, Nicholas Piggin, Sachin Sant Sathvika Vasireddy,
  and Sourabh Jain"

* tag 'powerpc-6.2-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/64s: Reconnect tlb_flush() to hash__tlb_flush()
  powerpc/kexec_file: Count hot-pluggable memory in FDT estimate
  powerpc/64s/radix: Fix RWX mapping with relocated kernel
  powerpc/64s/radix: Fix crash with unaligned relocated kernel
  powerpc/kexec_file: Fix division by zero in extra size estimation
  powerpc/imc-pmu: Revert nest_init_lock to being a mutex
  powerpc/64: Fix perf profiling asynchronous interrupt handlers
  powerpc/64s: Fix local irq disable when PMIs are disabled
  powerpc/kvm: Fix unannotated intra-function call warning
  powerpc/85xx: Fix unannotated intra-function call warning
parents 95078069 1665c027
...@@ -97,6 +97,8 @@ static inline void tlb_flush(struct mmu_gather *tlb) ...@@ -97,6 +97,8 @@ static inline void tlb_flush(struct mmu_gather *tlb)
{ {
if (radix_enabled()) if (radix_enabled())
radix__tlb_flush(tlb); radix__tlb_flush(tlb);
return hash__tlb_flush(tlb);
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
......
...@@ -173,6 +173,15 @@ static inline notrace unsigned long irq_soft_mask_or_return(unsigned long mask) ...@@ -173,6 +173,15 @@ static inline notrace unsigned long irq_soft_mask_or_return(unsigned long mask)
return flags; return flags;
} }
static inline notrace unsigned long irq_soft_mask_andc_return(unsigned long mask)
{
unsigned long flags = irq_soft_mask_return();
irq_soft_mask_set(flags & ~mask);
return flags;
}
static inline unsigned long arch_local_save_flags(void) static inline unsigned long arch_local_save_flags(void)
{ {
return irq_soft_mask_return(); return irq_soft_mask_return();
...@@ -192,7 +201,7 @@ static inline void arch_local_irq_enable(void) ...@@ -192,7 +201,7 @@ static inline void arch_local_irq_enable(void)
static inline unsigned long arch_local_irq_save(void) static inline unsigned long arch_local_irq_save(void)
{ {
return irq_soft_mask_set_return(IRQS_DISABLED); return irq_soft_mask_or_return(IRQS_DISABLED);
} }
static inline bool arch_irqs_disabled_flags(unsigned long flags) static inline bool arch_irqs_disabled_flags(unsigned long flags)
...@@ -331,10 +340,11 @@ bool power_pmu_wants_prompt_pmi(void); ...@@ -331,10 +340,11 @@ bool power_pmu_wants_prompt_pmi(void);
* is a different soft-masked interrupt pending that requires hard * is a different soft-masked interrupt pending that requires hard
* masking. * masking.
*/ */
static inline bool should_hard_irq_enable(void) static inline bool should_hard_irq_enable(struct pt_regs *regs)
{ {
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) { if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
WARN_ON(irq_soft_mask_return() == IRQS_ENABLED); WARN_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED);
WARN_ON(!(get_paca()->irq_happened & PACA_IRQ_HARD_DIS));
WARN_ON(mfmsr() & MSR_EE); WARN_ON(mfmsr() & MSR_EE);
} }
...@@ -347,8 +357,17 @@ static inline bool should_hard_irq_enable(void) ...@@ -347,8 +357,17 @@ static inline bool should_hard_irq_enable(void)
* *
* TODO: Add test for 64e * TODO: Add test for 64e
*/ */
if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !power_pmu_wants_prompt_pmi()) if (IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
if (!power_pmu_wants_prompt_pmi())
return false; return false;
/*
* If PMIs are disabled then IRQs should be disabled as well,
* so we shouldn't see this condition, check for it just in
* case because we are about to enable PMIs.
*/
if (WARN_ON_ONCE(regs->softe & IRQS_PMI_DISABLED))
return false;
}
if (get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK) if (get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK)
return false; return false;
...@@ -358,18 +377,16 @@ static inline bool should_hard_irq_enable(void) ...@@ -358,18 +377,16 @@ static inline bool should_hard_irq_enable(void)
/* /*
* Do the hard enabling, only call this if should_hard_irq_enable is true. * Do the hard enabling, only call this if should_hard_irq_enable is true.
* This allows PMI interrupts to profile irq handlers.
*/ */
static inline void do_hard_irq_enable(void) static inline void do_hard_irq_enable(void)
{ {
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
WARN_ON(irq_soft_mask_return() == IRQS_ENABLED);
WARN_ON(get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK);
WARN_ON(mfmsr() & MSR_EE);
}
/* /*
* This allows PMI interrupts (and watchdog soft-NMIs) through. * Asynch interrupts come in with IRQS_ALL_DISABLED,
* There is no other reason to enable this way. * PACA_IRQ_HARD_DIS, and MSR[EE]=0.
*/ */
if (IS_ENABLED(CONFIG_PPC_BOOK3S_64))
irq_soft_mask_andc_return(IRQS_PMI_DISABLED);
get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS; get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
__hard_irq_enable(); __hard_irq_enable();
} }
...@@ -452,7 +469,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs) ...@@ -452,7 +469,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
return !(regs->msr & MSR_EE); return !(regs->msr & MSR_EE);
} }
static __always_inline bool should_hard_irq_enable(void) static __always_inline bool should_hard_irq_enable(struct pt_regs *regs)
{ {
return false; return false;
} }
......
...@@ -27,7 +27,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(doorbell_exception) ...@@ -27,7 +27,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(doorbell_exception)
ppc_msgsync(); ppc_msgsync();
if (should_hard_irq_enable()) if (should_hard_irq_enable(regs))
do_hard_irq_enable(); do_hard_irq_enable();
kvmppc_clear_host_ipi(smp_processor_id()); kvmppc_clear_host_ipi(smp_processor_id());
......
...@@ -864,7 +864,7 @@ _GLOBAL(load_up_spe) ...@@ -864,7 +864,7 @@ _GLOBAL(load_up_spe)
* SPE unavailable trap from kernel - print a message, but let * SPE unavailable trap from kernel - print a message, but let
* the task use SPE in the kernel until it returns to user mode. * the task use SPE in the kernel until it returns to user mode.
*/ */
KernelSPE: SYM_FUNC_START_LOCAL(KernelSPE)
lwz r3,_MSR(r1) lwz r3,_MSR(r1)
oris r3,r3,MSR_SPE@h oris r3,r3,MSR_SPE@h
stw r3,_MSR(r1) /* enable use of SPE after return */ stw r3,_MSR(r1) /* enable use of SPE after return */
...@@ -881,6 +881,7 @@ KernelSPE: ...@@ -881,6 +881,7 @@ KernelSPE:
#endif #endif
.align 4,0 .align 4,0
SYM_FUNC_END(KernelSPE)
#endif /* CONFIG_SPE */ #endif /* CONFIG_SPE */
/* /*
......
...@@ -238,7 +238,7 @@ static void __do_irq(struct pt_regs *regs, unsigned long oldsp) ...@@ -238,7 +238,7 @@ static void __do_irq(struct pt_regs *regs, unsigned long oldsp)
irq = static_call(ppc_get_irq)(); irq = static_call(ppc_get_irq)();
/* We can hard enable interrupts now to allow perf interrupts */ /* We can hard enable interrupts now to allow perf interrupts */
if (should_hard_irq_enable()) if (should_hard_irq_enable(regs))
do_hard_irq_enable(); do_hard_irq_enable();
/* And finally process it */ /* And finally process it */
......
...@@ -515,7 +515,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt) ...@@ -515,7 +515,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
} }
/* Conditionally hard-enable interrupts. */ /* Conditionally hard-enable interrupts. */
if (should_hard_irq_enable()) { if (should_hard_irq_enable(regs)) {
/* /*
* Ensure a positive value is written to the decrementer, or * Ensure a positive value is written to the decrementer, or
* else some CPUs will continue to take decrementer exceptions. * else some CPUs will continue to take decrementer exceptions.
......
...@@ -989,10 +989,13 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image) ...@@ -989,10 +989,13 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
* linux,drconf-usable-memory properties. Get an approximate on the * linux,drconf-usable-memory properties. Get an approximate on the
* number of usable memory entries and use for FDT size estimation. * number of usable memory entries and use for FDT size estimation.
*/ */
usm_entries = ((memblock_end_of_DRAM() / drmem_lmb_size()) + if (drmem_lmb_size()) {
usm_entries = ((memory_hotplug_max() / drmem_lmb_size()) +
(2 * (resource_size(&crashk_res) / drmem_lmb_size()))); (2 * (resource_size(&crashk_res) / drmem_lmb_size())));
extra_size = (unsigned int)(usm_entries * sizeof(u64)); extra_size = (unsigned int)(usm_entries * sizeof(u64));
} else {
extra_size = 0;
}
/* /*
* Get the number of CPU nodes in the current DT. This allows to * Get the number of CPU nodes in the current DT. This allows to
......
...@@ -912,16 +912,15 @@ static int kvmppc_handle_debug(struct kvm_vcpu *vcpu) ...@@ -912,16 +912,15 @@ static int kvmppc_handle_debug(struct kvm_vcpu *vcpu)
static void kvmppc_fill_pt_regs(struct pt_regs *regs) static void kvmppc_fill_pt_regs(struct pt_regs *regs)
{ {
ulong r1, ip, msr, lr; ulong r1, msr, lr;
asm("mr %0, 1" : "=r"(r1)); asm("mr %0, 1" : "=r"(r1));
asm("mflr %0" : "=r"(lr)); asm("mflr %0" : "=r"(lr));
asm("mfmsr %0" : "=r"(msr)); asm("mfmsr %0" : "=r"(msr));
asm("bl 1f; 1: mflr %0" : "=r"(ip));
memset(regs, 0, sizeof(*regs)); memset(regs, 0, sizeof(*regs));
regs->gpr[1] = r1; regs->gpr[1] = r1;
regs->nip = ip; regs->nip = _THIS_IP_;
regs->msr = msr; regs->msr = msr;
regs->link = lr; regs->link = lr;
} }
......
...@@ -234,6 +234,14 @@ void radix__mark_rodata_ro(void) ...@@ -234,6 +234,14 @@ void radix__mark_rodata_ro(void)
end = (unsigned long)__end_rodata; end = (unsigned long)__end_rodata;
radix__change_memory_range(start, end, _PAGE_WRITE); radix__change_memory_range(start, end, _PAGE_WRITE);
for (start = PAGE_OFFSET; start < (unsigned long)_stext; start += PAGE_SIZE) {
end = start + PAGE_SIZE;
if (overlaps_interrupt_vector_text(start, end))
radix__change_memory_range(start, end, _PAGE_WRITE);
else
break;
}
} }
void radix__mark_initmem_nx(void) void radix__mark_initmem_nx(void)
...@@ -262,6 +270,22 @@ print_mapping(unsigned long start, unsigned long end, unsigned long size, bool e ...@@ -262,6 +270,22 @@ print_mapping(unsigned long start, unsigned long end, unsigned long size, bool e
static unsigned long next_boundary(unsigned long addr, unsigned long end) static unsigned long next_boundary(unsigned long addr, unsigned long end)
{ {
#ifdef CONFIG_STRICT_KERNEL_RWX #ifdef CONFIG_STRICT_KERNEL_RWX
unsigned long stext_phys;
stext_phys = __pa_symbol(_stext);
// Relocatable kernel running at non-zero real address
if (stext_phys != 0) {
// The end of interrupts code at zero is a rodata boundary
unsigned long end_intr = __pa_symbol(__end_interrupts) - stext_phys;
if (addr < end_intr)
return end_intr;
// Start of relocated kernel text is a rodata boundary
if (addr < stext_phys)
return stext_phys;
}
if (addr < __pa_symbol(__srwx_boundary)) if (addr < __pa_symbol(__srwx_boundary))
return __pa_symbol(__srwx_boundary); return __pa_symbol(__srwx_boundary);
#endif #endif
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* Used to avoid races in counting the nest-pmu units during hotplug * Used to avoid races in counting the nest-pmu units during hotplug
* register and unregister * register and unregister
*/ */
static DEFINE_SPINLOCK(nest_init_lock); static DEFINE_MUTEX(nest_init_lock);
static DEFINE_PER_CPU(struct imc_pmu_ref *, local_nest_imc_refc); static DEFINE_PER_CPU(struct imc_pmu_ref *, local_nest_imc_refc);
static struct imc_pmu **per_nest_pmu_arr; static struct imc_pmu **per_nest_pmu_arr;
static cpumask_t nest_imc_cpumask; static cpumask_t nest_imc_cpumask;
...@@ -1629,7 +1629,7 @@ static void imc_common_mem_free(struct imc_pmu *pmu_ptr) ...@@ -1629,7 +1629,7 @@ static void imc_common_mem_free(struct imc_pmu *pmu_ptr)
static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr) static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
{ {
if (pmu_ptr->domain == IMC_DOMAIN_NEST) { if (pmu_ptr->domain == IMC_DOMAIN_NEST) {
spin_lock(&nest_init_lock); mutex_lock(&nest_init_lock);
if (nest_pmus == 1) { if (nest_pmus == 1) {
cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE); cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE);
kfree(nest_imc_refc); kfree(nest_imc_refc);
...@@ -1639,7 +1639,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr) ...@@ -1639,7 +1639,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
if (nest_pmus > 0) if (nest_pmus > 0)
nest_pmus--; nest_pmus--;
spin_unlock(&nest_init_lock); mutex_unlock(&nest_init_lock);
} }
/* Free core_imc memory */ /* Free core_imc memory */
...@@ -1796,11 +1796,11 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id ...@@ -1796,11 +1796,11 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
* rest. To handle the cpuhotplug callback unregister, we track * rest. To handle the cpuhotplug callback unregister, we track
* the number of nest pmus in "nest_pmus". * the number of nest pmus in "nest_pmus".
*/ */
spin_lock(&nest_init_lock); mutex_lock(&nest_init_lock);
if (nest_pmus == 0) { if (nest_pmus == 0) {
ret = init_nest_pmu_ref(); ret = init_nest_pmu_ref();
if (ret) { if (ret) {
spin_unlock(&nest_init_lock); mutex_unlock(&nest_init_lock);
kfree(per_nest_pmu_arr); kfree(per_nest_pmu_arr);
per_nest_pmu_arr = NULL; per_nest_pmu_arr = NULL;
goto err_free_mem; goto err_free_mem;
...@@ -1808,7 +1808,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id ...@@ -1808,7 +1808,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
/* Register for cpu hotplug notification. */ /* Register for cpu hotplug notification. */
ret = nest_pmu_cpumask_init(); ret = nest_pmu_cpumask_init();
if (ret) { if (ret) {
spin_unlock(&nest_init_lock); mutex_unlock(&nest_init_lock);
kfree(nest_imc_refc); kfree(nest_imc_refc);
kfree(per_nest_pmu_arr); kfree(per_nest_pmu_arr);
per_nest_pmu_arr = NULL; per_nest_pmu_arr = NULL;
...@@ -1816,7 +1816,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id ...@@ -1816,7 +1816,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
} }
} }
nest_pmus++; nest_pmus++;
spin_unlock(&nest_init_lock); mutex_unlock(&nest_init_lock);
break; break;
case IMC_DOMAIN_CORE: case IMC_DOMAIN_CORE:
ret = core_imc_pmu_cpumask_init(); ret = core_imc_pmu_cpumask_init();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment