]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
wcn36xx: avoid alloc mem with GFP_KERNEL in smd callback.
authorYin, Fengwei <fengwei.yin@linaro.org>
Wed, 16 Sep 2015 15:37:31 +0000 (23:37 +0800)
committerStefan Bader <stefan.bader@canonical.com>
Tue, 12 Sep 2017 16:19:06 +0000 (18:19 +0200)
which will trigger warning when lockdep debugging is enabled.

Signed-off-by: Yin, Fengwei <fengwei.yin@linaro.org>
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
drivers/net/wireless/ath/wcn36xx/wcn36xx.h

index 36c2dbc8ed4ec3330892df371b52bacfaac3c3ea..d950f286a9d54695ea37513610a85ac976811188 100644 (file)
@@ -2101,6 +2101,7 @@ out:
        mutex_unlock(&wcn->hal_mutex);
        return ret;
 }
+
 static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
 {
        struct wcn36xx_hal_msg_header *msg_header = buf;
index 00cc658b8eee22a20218d1e4a0b9e983b9baae35..647f623f19857fa73ad4372862396e41fdf78b96 100644 (file)
 
 #define MAC_ADDR_0 "wlan/macaddr0"
 
+struct smd_packet_item {
+       struct list_head list;
+       void *buf;
+       size_t count;
+};
+
 static int wcn36xx_msm_smsm_change_state(u32 clear_mask, u32 set_mask)
 {
        return 0;
@@ -115,6 +121,28 @@ static struct wcn36xx_platform_data wcn36xx_data = {
        },
 };
 
+static void wlan_ctrl_smd_process(struct work_struct *worker)
+{
+       unsigned long flags;
+       struct wcn36xx_platform_data *pdata =
+               container_of(worker,
+                       struct wcn36xx_platform_data, packet_process_work);
+
+       spin_lock_irqsave(&pdata->packet_lock, flags);
+       while (!list_empty(&pdata->packet_list)) {
+               struct smd_packet_item *packet;
+
+               packet = list_first_entry(&pdata->packet_list,
+                               struct smd_packet_item, list);
+               list_del(&packet->list);
+               spin_unlock_irqrestore(&pdata->packet_lock, flags);
+               pdata->cb(pdata->wcn, packet->buf, packet->count);
+               kfree(packet->buf);
+               spin_lock_irqsave(&pdata->packet_lock, flags);
+       }
+       spin_unlock_irqrestore(&pdata->packet_lock, flags);
+}
+
 static int qcom_smd_wlan_ctrl_probe(struct qcom_smd_device *sdev)
 {
        pr_info("%s: enter\n", __func__);
@@ -122,6 +150,9 @@ static int qcom_smd_wlan_ctrl_probe(struct qcom_smd_device *sdev)
         init_completion(&wcn36xx_data.wlan_ctrl_ack);
 
        wcn36xx_data.sdev = sdev;
+       spin_lock_init(&wcn36xx_data.packet_lock);
+       INIT_LIST_HEAD(&wcn36xx_data.packet_list);
+       INIT_WORK(&wcn36xx_data.packet_process_work, wlan_ctrl_smd_process);
 
         dev_set_drvdata(&sdev->dev, &wcn36xx_data);
        wcn36xx_data.wlan_ctrl_channel = sdev->channel;
@@ -140,16 +171,27 @@ static int qcom_smd_wlan_ctrl_callback(struct qcom_smd_device *qsdev,
                                  const void *data,
                                  size_t count)
 {
+       unsigned long flags;
+       struct smd_packet_item *packet = NULL;
        struct wcn36xx_platform_data *pdata = dev_get_drvdata(&qsdev->dev);
-       void *buf = kzalloc(count, GFP_ATOMIC);
+       void *buf = kzalloc(count + sizeof(struct smd_packet_item),
+                               GFP_ATOMIC);
        if (!buf) {
                dev_err(&pdata->core->dev, "can't allocate buffer\n");
                return -ENOMEM;
        }
 
        memcpy_fromio(buf, data, count);
-       pdata->cb(pdata->wcn, buf, count);
-       kfree(buf);
+       packet = buf + count;
+       packet->buf = buf;
+       packet->count = count;
+
+       spin_lock_irqsave(&pdata->packet_lock, flags);
+       list_add_tail(&packet->list, &pdata->packet_list);
+       spin_unlock_irqrestore(&pdata->packet_lock, flags);
+       schedule_work(&pdata->packet_process_work);
+
+       /* buf will be freed in workqueue */
 
        return 0;
 }
index d9f8b6450487dd173f906313907bcceb7612cf7b..f88cf7e8715bfe0ccd484391ad35ce523baee7d3 100644 (file)
@@ -140,6 +140,10 @@ struct wcn36xx_platform_data {
 
        void (*cb)(struct wcn36xx *wcn, void *buf, size_t len);
        struct wcn36xx_platform_ctrl_ops ctrl_ops;
+
+       struct work_struct packet_process_work;
+       spinlock_t packet_lock;
+       struct list_head packet_list;
 };
 
 /**