aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYin, Fengwei <fengwei.yin@linaro.org>2015-09-16 23:37:31 +0800
committerYin, Fengwei <fengwei.yin@linaro.org>2015-10-23 16:38:59 +0800
commit5a6018da3c4915cda70e1ccebedf28d7042a2194 (patch)
tree43935c1ce8c835cac3e69a272a747c5573d0ac9c
parentaf7baa2f197c52200a23e36d299a6cc24da8a047 (diff)
wcn36xx: avoid alloc mem with GFP_KERNEL in smd callback.bt_wifi_for_k43
which will trigger warning when lockdep debugging is enabled. Signed-off-by: Yin, Fengwei <fengwei.yin@linaro.org>
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c1
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c48
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h4
3 files changed, 50 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 36c2dbc8ed4e..d950f286a9d5 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -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;
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
index 00cc658b8eee..647f623f1985 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
@@ -31,6 +31,12 @@
#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;
}
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index d9f8b6450487..f88cf7e8715b 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -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;
};
/**