]> Git Repo - linux.git/commitdiff
soc: qcom: pmic_glink: Make client-lock non-sleeping
authorBjorn Andersson <[email protected]>
Wed, 1 May 2024 03:38:57 +0000 (20:38 -0700)
committerBjorn Andersson <[email protected]>
Wed, 1 May 2024 18:39:51 +0000 (13:39 -0500)
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: 635ce0db8956 ("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]>
drivers/soc/qcom/pmic_glink.c

index e85a12ec2aab18d05b908efd761d3c5632e2bc1f..823fd108fa039ff65b7e577ceab44fbb47d55cce 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/soc/qcom/pdr.h>
 #include <linux/soc/qcom/pmic_glink.h>
+#include <linux/spinlock.h>
 
 enum {
        PMIC_GLINK_CLIENT_BATT = 0,
@@ -36,7 +37,7 @@ struct pmic_glink {
        unsigned int pdr_state;
 
        /* serializing clients list updates */
-       struct mutex client_lock;
+       spinlock_t client_lock;
        struct list_head clients;
 };
 
@@ -58,10 +59,11 @@ static void _devm_pmic_glink_release_client(struct device *dev, void *res)
 {
        struct pmic_glink_client *client = (struct pmic_glink_client *)res;
        struct pmic_glink *pg = client->pg;
+       unsigned long flags;
 
-       mutex_lock(&pg->client_lock);
+       spin_lock_irqsave(&pg->client_lock, flags);
        list_del(&client->node);
-       mutex_unlock(&pg->client_lock);
+       spin_unlock_irqrestore(&pg->client_lock, flags);
 }
 
 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,
 {
        struct pmic_glink_client *client;
        struct pmic_glink *pg = dev_get_drvdata(dev->parent);
+       unsigned long flags;
 
        client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
        if (!client)
@@ -84,12 +87,12 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
        client->priv = priv;
 
        mutex_lock(&pg->state_lock);
-       mutex_lock(&pg->client_lock);
+       spin_lock_irqsave(&pg->client_lock, flags);
 
        list_add(&client->node, &pg->clients);
        client->pdr_notify(client->priv, pg->client_state);
 
-       mutex_unlock(&pg->client_lock);
+       spin_unlock_irqrestore(&pg->client_lock, flags);
        mutex_unlock(&pg->state_lock);
 
        devres_add(dev, client);
@@ -112,6 +115,7 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
        struct pmic_glink_client *client;
        struct pmic_glink_hdr *hdr;
        struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
+       unsigned long flags;
 
        if (len < sizeof(*hdr)) {
                dev_warn(pg->dev, "ignoring truncated message\n");
@@ -120,12 +124,12 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
 
        hdr = data;
 
-       mutex_lock(&pg->client_lock);
+       spin_lock_irqsave(&pg->client_lock, flags);
        list_for_each_entry(client, &pg->clients, node) {
                if (client->id == le32_to_cpu(hdr->owner))
                        client->cb(data, len, client->priv);
        }
-       mutex_unlock(&pg->client_lock);
+       spin_unlock_irqrestore(&pg->client_lock, flags);
 
        return 0;
 }
@@ -165,6 +169,7 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
 {
        struct pmic_glink_client *client;
        unsigned int new_state = pg->client_state;
+       unsigned long flags;
 
        if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
                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)
        }
 
        if (new_state != pg->client_state) {
-               mutex_lock(&pg->client_lock);
+               spin_lock_irqsave(&pg->client_lock, flags);
                list_for_each_entry(client, &pg->clients, node)
                        client->pdr_notify(client->priv, new_state);
-               mutex_unlock(&pg->client_lock);
+               spin_unlock_irqrestore(&pg->client_lock, flags);
                pg->client_state = new_state;
        }
 }
@@ -265,7 +270,7 @@ static int pmic_glink_probe(struct platform_device *pdev)
        pg->dev = &pdev->dev;
 
        INIT_LIST_HEAD(&pg->clients);
-       mutex_init(&pg->client_lock);
+       spin_lock_init(&pg->client_lock);
        mutex_init(&pg->state_lock);
 
        match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);
This page took 0.062109 seconds and 4 git commands to generate.