Commit ad53db4a authored by Michael Ellerman's avatar Michael Ellerman

powerpc/imc-pmu: Revert nest_init_lock to being a mutex

The recent commit 76d588dd ("powerpc/imc-pmu: Fix use of mutex in
IRQs disabled section") fixed warnings (and possible deadlocks) in the
IMC PMU driver by converting the locking to use spinlocks.

It also converted the init-time nest_init_lock to a spinlock, even
though it's not used at runtime in IRQ disabled sections or while
holding other spinlocks.

This leads to warnings such as:

  BUG: sleeping function called from invalid context at include/linux/percpu-rwsem.h:49
  in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1, name: swapper/0
  preempt_count: 1, expected: 0
  CPU: 7 PID: 1 Comm: swapper/0 Not tainted 6.2.0-rc2-14719-gf12cd061-dirty #1
  Hardware name: Mambo,Simulated-System POWER9 0x4e1203 opal:v6.6.6 PowerNV
  Call Trace:
    dump_stack_lvl+0x74/0xa8 (unreliable)
    __might_resched+0x178/0x1a0
    __cpuhp_setup_state+0x64/0x1e0
    init_imc_pmu+0xe48/0x1250
    opal_imc_counters_probe+0x30c/0x6a0
    platform_probe+0x78/0x110
    really_probe+0x104/0x420
    __driver_probe_device+0xb0/0x170
    driver_probe_device+0x58/0x180
    __driver_attach+0xd8/0x250
    bus_for_each_dev+0xb4/0x140
    driver_attach+0x34/0x50
    bus_add_driver+0x1e8/0x2d0
    driver_register+0xb4/0x1c0
    __platform_driver_register+0x38/0x50
    opal_imc_driver_init+0x2c/0x40
    do_one_initcall+0x80/0x360
    kernel_init_freeable+0x310/0x3b8
    kernel_init+0x30/0x1a0
    ret_from_kernel_thread+0x5c/0x64

Fix it by converting nest_init_lock back to a mutex, so that we can call
sleeping functions while holding it. There is no interaction between
nest_init_lock and the runtime spinlocks used by the actual PMU routines.

Fixes: 76d588dd ("powerpc/imc-pmu: Fix use of mutex in IRQs disabled section")
Tested-by: Kajol Jain<kjain@linux.ibm.com>
Reviewed-by: Kajol Jain<kjain@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20230130014401.540543-1-mpe@ellerman.id.au
parent c2854801
...@@ -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