Skip to content

Commit 9329933

Browse files
quic-bjorandeandersson
authored andcommitted
soc: qcom: pmic_glink: Make client-lock non-sleeping
The recently introduced commit '635ce0db8956 ("soc: qcom: pmic_glink: don't traverse clients list without a lock")' ensured that the clients list is not modified while traversed. But the callback is made from the GLINK IRQ handler and as such this mutual exclusion can not be provided by a (sleepable) mutex. Replace the mutex with a spinlock. Fixes: 635ce0d ("soc: qcom: pmic_glink: don't traverse clients list without a lock") Signed-off-by: Bjorn Andersson <[email protected]> Reviewed-by: Dmitry Baryshkov <[email protected]> Link: https://lore.kernel.org/r/20240430-pmic-glink-sleep-while-atomic-v1-1-88fb493e8545@quicinc.com Signed-off-by: Bjorn Andersson <[email protected]>
1 parent dff55f6 commit 9329933

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

drivers/soc/qcom/pmic_glink.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/slab.h>
1212
#include <linux/soc/qcom/pdr.h>
1313
#include <linux/soc/qcom/pmic_glink.h>
14+
#include <linux/spinlock.h>
1415

1516
enum {
1617
PMIC_GLINK_CLIENT_BATT = 0,
@@ -36,7 +37,7 @@ struct pmic_glink {
3637
unsigned int pdr_state;
3738

3839
/* serializing clients list updates */
39-
struct mutex client_lock;
40+
spinlock_t client_lock;
4041
struct list_head clients;
4142
};
4243

@@ -58,10 +59,11 @@ static void _devm_pmic_glink_release_client(struct device *dev, void *res)
5859
{
5960
struct pmic_glink_client *client = (struct pmic_glink_client *)res;
6061
struct pmic_glink *pg = client->pg;
62+
unsigned long flags;
6163

62-
mutex_lock(&pg->client_lock);
64+
spin_lock_irqsave(&pg->client_lock, flags);
6365
list_del(&client->node);
64-
mutex_unlock(&pg->client_lock);
66+
spin_unlock_irqrestore(&pg->client_lock, flags);
6567
}
6668

6769
struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
@@ -72,6 +74,7 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
7274
{
7375
struct pmic_glink_client *client;
7476
struct pmic_glink *pg = dev_get_drvdata(dev->parent);
77+
unsigned long flags;
7578

7679
client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
7780
if (!client)
@@ -84,12 +87,12 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
8487
client->priv = priv;
8588

8689
mutex_lock(&pg->state_lock);
87-
mutex_lock(&pg->client_lock);
90+
spin_lock_irqsave(&pg->client_lock, flags);
8891

8992
list_add(&client->node, &pg->clients);
9093
client->pdr_notify(client->priv, pg->client_state);
9194

92-
mutex_unlock(&pg->client_lock);
95+
spin_unlock_irqrestore(&pg->client_lock, flags);
9396
mutex_unlock(&pg->state_lock);
9497

9598
devres_add(dev, client);
@@ -112,6 +115,7 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
112115
struct pmic_glink_client *client;
113116
struct pmic_glink_hdr *hdr;
114117
struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
118+
unsigned long flags;
115119

116120
if (len < sizeof(*hdr)) {
117121
dev_warn(pg->dev, "ignoring truncated message\n");
@@ -120,12 +124,12 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
120124

121125
hdr = data;
122126

123-
mutex_lock(&pg->client_lock);
127+
spin_lock_irqsave(&pg->client_lock, flags);
124128
list_for_each_entry(client, &pg->clients, node) {
125129
if (client->id == le32_to_cpu(hdr->owner))
126130
client->cb(data, len, client->priv);
127131
}
128-
mutex_unlock(&pg->client_lock);
132+
spin_unlock_irqrestore(&pg->client_lock, flags);
129133

130134
return 0;
131135
}
@@ -165,6 +169,7 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
165169
{
166170
struct pmic_glink_client *client;
167171
unsigned int new_state = pg->client_state;
172+
unsigned long flags;
168173

169174
if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
170175
if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
@@ -175,10 +180,10 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
175180
}
176181

177182
if (new_state != pg->client_state) {
178-
mutex_lock(&pg->client_lock);
183+
spin_lock_irqsave(&pg->client_lock, flags);
179184
list_for_each_entry(client, &pg->clients, node)
180185
client->pdr_notify(client->priv, new_state);
181-
mutex_unlock(&pg->client_lock);
186+
spin_unlock_irqrestore(&pg->client_lock, flags);
182187
pg->client_state = new_state;
183188
}
184189
}
@@ -265,7 +270,7 @@ static int pmic_glink_probe(struct platform_device *pdev)
265270
pg->dev = &pdev->dev;
266271

267272
INIT_LIST_HEAD(&pg->clients);
268-
mutex_init(&pg->client_lock);
273+
spin_lock_init(&pg->client_lock);
269274
mutex_init(&pg->state_lock);
270275

271276
match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);

0 commit comments

Comments
 (0)