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
This commit is contained in:
@@ -97,6 +97,8 @@ static inline void tlb_flush(struct mmu_gather *tlb)
|
||||
{
|
||||
if (radix_enabled())
|
||||
radix__tlb_flush(tlb);
|
||||
|
||||
return hash__tlb_flush(tlb);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
@@ -173,6 +173,15 @@ static inline notrace unsigned long irq_soft_mask_or_return(unsigned long mask)
|
||||
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)
|
||||
{
|
||||
return irq_soft_mask_return();
|
||||
@@ -192,7 +201,7 @@ static inline void arch_local_irq_enable(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)
|
||||
@@ -331,10 +340,11 @@ bool power_pmu_wants_prompt_pmi(void);
|
||||
* is a different soft-masked interrupt pending that requires hard
|
||||
* 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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -347,8 +357,17 @@ static inline bool should_hard_irq_enable(void)
|
||||
*
|
||||
* TODO: Add test for 64e
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !power_pmu_wants_prompt_pmi())
|
||||
return false;
|
||||
if (IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
|
||||
if (!power_pmu_wants_prompt_pmi())
|
||||
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)
|
||||
return false;
|
||||
@@ -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.
|
||||
* This allows PMI interrupts to profile irq handlers.
|
||||
*/
|
||||
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.
|
||||
* There is no other reason to enable this way.
|
||||
* Asynch interrupts come in with IRQS_ALL_DISABLED,
|
||||
* 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;
|
||||
__hard_irq_enable();
|
||||
}
|
||||
@@ -452,7 +469,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(doorbell_exception)
|
||||
|
||||
ppc_msgsync();
|
||||
|
||||
if (should_hard_irq_enable())
|
||||
if (should_hard_irq_enable(regs))
|
||||
do_hard_irq_enable();
|
||||
|
||||
kvmppc_clear_host_ipi(smp_processor_id());
|
||||
|
||||
@@ -864,7 +864,7 @@ _GLOBAL(load_up_spe)
|
||||
* SPE unavailable trap from kernel - print a message, but let
|
||||
* the task use SPE in the kernel until it returns to user mode.
|
||||
*/
|
||||
KernelSPE:
|
||||
SYM_FUNC_START_LOCAL(KernelSPE)
|
||||
lwz r3,_MSR(r1)
|
||||
oris r3,r3,MSR_SPE@h
|
||||
stw r3,_MSR(r1) /* enable use of SPE after return */
|
||||
@@ -881,6 +881,7 @@ KernelSPE:
|
||||
#endif
|
||||
.align 4,0
|
||||
|
||||
SYM_FUNC_END(KernelSPE)
|
||||
#endif /* CONFIG_SPE */
|
||||
|
||||
/*
|
||||
|
||||
@@ -238,7 +238,7 @@ static void __do_irq(struct pt_regs *regs, unsigned long oldsp)
|
||||
irq = static_call(ppc_get_irq)();
|
||||
|
||||
/* 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();
|
||||
|
||||
/* And finally process it */
|
||||
|
||||
@@ -515,7 +515,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
|
||||
}
|
||||
|
||||
/* 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
|
||||
* else some CPUs will continue to take decrementer exceptions.
|
||||
|
||||
@@ -989,10 +989,13 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
|
||||
* linux,drconf-usable-memory properties. Get an approximate on the
|
||||
* number of usable memory entries and use for FDT size estimation.
|
||||
*/
|
||||
usm_entries = ((memblock_end_of_DRAM() / drmem_lmb_size()) +
|
||||
(2 * (resource_size(&crashk_res) / drmem_lmb_size())));
|
||||
|
||||
extra_size = (unsigned int)(usm_entries * sizeof(u64));
|
||||
if (drmem_lmb_size()) {
|
||||
usm_entries = ((memory_hotplug_max() / drmem_lmb_size()) +
|
||||
(2 * (resource_size(&crashk_res) / drmem_lmb_size())));
|
||||
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
|
||||
|
||||
@@ -912,16 +912,15 @@ static int kvmppc_handle_debug(struct kvm_vcpu *vcpu)
|
||||
|
||||
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("mflr %0" : "=r"(lr));
|
||||
asm("mfmsr %0" : "=r"(msr));
|
||||
asm("bl 1f; 1: mflr %0" : "=r"(ip));
|
||||
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->gpr[1] = r1;
|
||||
regs->nip = ip;
|
||||
regs->nip = _THIS_IP_;
|
||||
regs->msr = msr;
|
||||
regs->link = lr;
|
||||
}
|
||||
|
||||
@@ -234,6 +234,14 @@ void radix__mark_rodata_ro(void)
|
||||
end = (unsigned long)__end_rodata;
|
||||
|
||||
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)
|
||||
@@ -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)
|
||||
{
|
||||
#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))
|
||||
return __pa_symbol(__srwx_boundary);
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* Used to avoid races in counting the nest-pmu units during hotplug
|
||||
* 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 struct imc_pmu **per_nest_pmu_arr;
|
||||
static cpumask_t nest_imc_cpumask;
|
||||
@@ -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)
|
||||
{
|
||||
if (pmu_ptr->domain == IMC_DOMAIN_NEST) {
|
||||
spin_lock(&nest_init_lock);
|
||||
mutex_lock(&nest_init_lock);
|
||||
if (nest_pmus == 1) {
|
||||
cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE);
|
||||
kfree(nest_imc_refc);
|
||||
@@ -1639,7 +1639,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
|
||||
|
||||
if (nest_pmus > 0)
|
||||
nest_pmus--;
|
||||
spin_unlock(&nest_init_lock);
|
||||
mutex_unlock(&nest_init_lock);
|
||||
}
|
||||
|
||||
/* Free core_imc memory */
|
||||
@@ -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
|
||||
* the number of nest pmus in "nest_pmus".
|
||||
*/
|
||||
spin_lock(&nest_init_lock);
|
||||
mutex_lock(&nest_init_lock);
|
||||
if (nest_pmus == 0) {
|
||||
ret = init_nest_pmu_ref();
|
||||
if (ret) {
|
||||
spin_unlock(&nest_init_lock);
|
||||
mutex_unlock(&nest_init_lock);
|
||||
kfree(per_nest_pmu_arr);
|
||||
per_nest_pmu_arr = NULL;
|
||||
goto err_free_mem;
|
||||
@@ -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. */
|
||||
ret = nest_pmu_cpumask_init();
|
||||
if (ret) {
|
||||
spin_unlock(&nest_init_lock);
|
||||
mutex_unlock(&nest_init_lock);
|
||||
kfree(nest_imc_refc);
|
||||
kfree(per_nest_pmu_arr);
|
||||
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
|
||||
}
|
||||
}
|
||||
nest_pmus++;
|
||||
spin_unlock(&nest_init_lock);
|
||||
mutex_unlock(&nest_init_lock);
|
||||
break;
|
||||
case IMC_DOMAIN_CORE:
|
||||
ret = core_imc_pmu_cpumask_init();
|
||||
|
||||
Reference in New Issue
Block a user