[PATCH linux dev-4.13 10/16] hwmon (p9_sbe): Convert client_lock from a spinlock to a mutex
Andrew Jeffery
andrew at aj.id.au
Tue Feb 20 15:18:38 AEDT 2018
The hwmon occ implementation allocates GFP_KERNEL memory in occ_open_common(),
therefore we cannot call it under a spinlock as it may sleep. Compiling with
lock debugging enabled gives us the following warning:
[ 4.420000] WARNING: CPU: 0 PID: 1 at kernel/locking/lockdep.c:2879 lockdep_trace_alloc+0xf0/0x124
[ 4.420000] DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags))
[ 4.420000] CPU: 0 PID: 1 Comm: swapper Not tainted 4.10.17-00526-g1cbacc6bd3a1 #2334
[ 4.420000] Hardware name: ASpeed SoC
[ 4.420000] [<80010eec>] (unwind_backtrace) from [<8000e664>] (show_stack+0x20/0x24)
[ 4.420000] [<8000e664>] (show_stack) from [<80249160>] (dump_stack+0x20/0x28)
[ 4.420000] [<80249160>] (dump_stack) from [<8001d3a0>] (__warn+0xe0/0x108)
[ 4.420000] [<8001d3a0>] (__warn) from [<8001d40c>] (warn_slowpath_fmt+0x44/0x4c)
[ 4.420000] [<8001d40c>] (warn_slowpath_fmt) from [<8005d2cc>] (lockdep_trace_alloc+0xf0/0x124)
[ 4.420000] [<8005d2cc>] (lockdep_trace_alloc) from [<8012bb1c>] (kmem_cache_alloc_trace+0x3c/0x284)
[ 4.420000] [<8012bb1c>] (kmem_cache_alloc_trace) from [<8034fa2c>] (occ_open_common+0x30/0xac)
[ 4.420000] [<8034fa2c>] (occ_open_common) from [<80350bac>] (occ_drv_open+0x24/0x28)
[ 4.420000] [<80350bac>] (occ_drv_open) from [<803638fc>] (p9_sbe_occ_send_cmd+0x44/0x13c)
[ 4.420000] [<803638fc>] (p9_sbe_occ_send_cmd) from [<803615b8>] (occ_poll+0x6c/0x1c0)
[ 4.420000] [<803615b8>] (occ_poll) from [<80363a84>] (p9_sbe_occ_probe+0x90/0x178)
[ 4.420000] [<80363a84>] (p9_sbe_occ_probe) from [<802b9850>] (platform_drv_probe+0x60/0xbc)
[ 4.420000] [<802b9850>] (platform_drv_probe) from [<802b76b0>] (driver_probe_device+0x114/0x430)
[ 4.420000] [<802b76b0>] (driver_probe_device) from [<802b7a98>] (__driver_attach+0xcc/0x10c)
[ 4.420000] [<802b7a98>] (__driver_attach) from [<802b5770>] (bus_for_each_dev+0x5c/0xac)
[ 4.420000] [<802b5770>] (bus_for_each_dev) from [<802b7c74>] (driver_attach+0x28/0x30)
[ 4.420000] [<802b7c74>] (driver_attach) from [<802b6268>] (bus_add_driver+0x19c/0x25c)
[ 4.420000] [<802b6268>] (bus_add_driver) from [<802b8abc>] (driver_register+0x88/0x104)
[ 4.420000] [<802b8abc>] (driver_register) from [<802ba468>] (__platform_driver_register+0x3c/0x50)
[ 4.420000] [<802ba468>] (__platform_driver_register) from [<8066d804>] (p9_sbe_occ_driver_init+0x18/0x20)
[ 4.420000] [<8066d804>] (p9_sbe_occ_driver_init) from [<8064ae7c>] (do_one_initcall+0xa8/0x168)
[ 4.420000] [<8064ae7c>] (do_one_initcall) from [<8064b04c>] (kernel_init_freeable+0x110/0x1c8)
[ 4.420000] [<8064b04c>] (kernel_init_freeable) from [<804a9034>] (kernel_init+0x18/0x104)
[ 4.420000] [<804a9034>] (kernel_init) from [<8000a888>] (ret_from_fork+0x14/0x2c)
Avoid the warning (or the need for GFP_ATOMIC) and allow for reduced system
latency by using a mutex instead. Mutual exclusion is the only requirement, we
do not need to block pre-emption.
Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
---
drivers/hwmon/occ/p9_sbe.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c
index 51bdfa89f1a6..38cf57ad1bb8 100644
--- a/drivers/hwmon/occ/p9_sbe.c
+++ b/drivers/hwmon/occ/p9_sbe.c
@@ -34,34 +34,32 @@ struct p9_sbe_occ {
* open, close and NULL assignment. This prevents simultaneous opening
* and closing of the client, or closing multiple times.
*/
- spinlock_t client_lock;
+ struct mutex client_lock;
};
#define to_p9_sbe_occ(x) container_of((x), struct p9_sbe_occ, occ)
static void p9_sbe_occ_close_client(struct p9_sbe_occ *ctx)
{
- unsigned long flags;
struct occ_client *tmp_client;
- spin_lock_irqsave(&ctx->client_lock, flags);
+ mutex_lock(&ctx->client_lock);
tmp_client = ctx->client;
ctx->client = NULL;
occ_drv_release(tmp_client);
- spin_unlock_irqrestore(&ctx->client_lock, flags);
+ mutex_unlock(&ctx->client_lock);
}
static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd)
{
int rc;
- unsigned long flags;
struct occ_response *resp = &occ->resp;
struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
- spin_lock_irqsave(&ctx->client_lock, flags);
+ mutex_lock(&ctx->client_lock);
if (ctx->sbe)
ctx->client = occ_drv_open(ctx->sbe, 0);
- spin_unlock_irqrestore(&ctx->client_lock, flags);
+ mutex_unlock(&ctx->client_lock);
if (!ctx->client)
return -ENODEV;
@@ -115,7 +113,7 @@ static int p9_sbe_occ_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- spin_lock_init(&ctx->lock);
+ mutex_init(&ctx->client_lock);
ctx->sbe = pdev->dev.parent;
occ = &ctx->occ;
occ->bus_dev = &pdev->dev;
--
2.14.1
More information about the openbmc
mailing list