rtlwifi: Add work queue for c2h cmd.
authorPing-Ke Shih <pkshih@realtek.com>
Tue, 7 Feb 2017 03:30:08 +0000 (21:30 -0600)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 7 Feb 2017 07:25:08 +0000 (09:25 +0200)
btcoex needs to sleep, thus it must run in thread context.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
12 files changed:
drivers/net/wireless/realtek/rtlwifi/base.c
drivers/net/wireless/realtek/rtlwifi/base.h
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h
drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
drivers/net/wireless/realtek/rtlwifi/wifi.h

index 01cf0a9aa31b6e0211e3566baba84d5f749f8881..caea350f05aac7b2e3dc7137b0b4363abcd8c2d4 100644 (file)
@@ -475,6 +475,8 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
                          (void *)rtl_swlps_rfon_wq_callback);
        INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq,
                          (void *)rtl_fwevt_wq_callback);
+       INIT_DELAYED_WORK(&rtlpriv->works.c2hcmd_wq,
+                         (void *)rtl_c2hcmd_wq_callback);
 
 }
 
@@ -489,6 +491,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
        cancel_delayed_work(&rtlpriv->works.ps_work);
        cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
        cancel_delayed_work(&rtlpriv->works.fwevt_wq);
+       cancel_delayed_work(&rtlpriv->works.c2hcmd_wq);
 }
 EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
 
@@ -556,6 +559,7 @@ int rtl_init_core(struct ieee80211_hw *hw)
        spin_lock_init(&rtlpriv->locks.rf_lock);
        spin_lock_init(&rtlpriv->locks.waitq_lock);
        spin_lock_init(&rtlpriv->locks.entry_list_lock);
+       spin_lock_init(&rtlpriv->locks.c2hcmd_lock);
        spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
        spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
        spin_lock_init(&rtlpriv->locks.fw_ps_lock);
@@ -563,6 +567,7 @@ int rtl_init_core(struct ieee80211_hw *hw)
        spin_lock_init(&rtlpriv->locks.iqk_lock);
        /* <5> init list */
        INIT_LIST_HEAD(&rtlpriv->entry_list);
+       INIT_LIST_HEAD(&rtlpriv->c2hcmd_list);
 
        rtlmac->link_state = MAC80211_NOLINK;
 
@@ -575,6 +580,7 @@ EXPORT_SYMBOL_GPL(rtl_init_core);
 
 void rtl_deinit_core(struct ieee80211_hw *hw)
 {
+       rtl_c2hcmd_launcher(hw, 0);
 }
 EXPORT_SYMBOL_GPL(rtl_deinit_core);
 
@@ -1729,6 +1735,93 @@ void rtl_fwevt_wq_callback(void *data)
 
        rtlpriv->cfg->ops->c2h_command_handle(hw);
 }
+
+void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       unsigned long flags;
+       struct rtl_c2hcmd *c2hcmd;
+
+       c2hcmd = kmalloc(sizeof(*c2hcmd), GFP_KERNEL);
+
+       if (!c2hcmd)
+               goto label_err;
+
+       c2hcmd->val = kmalloc(len, GFP_KERNEL);
+
+       if (!c2hcmd->val)
+               goto label_err2;
+
+       /* fill data */
+       c2hcmd->tag = tag;
+       c2hcmd->len = len;
+       memcpy(c2hcmd->val, val, len);
+
+       /* enqueue */
+       spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags);
+
+       list_add_tail(&c2hcmd->list, &rtlpriv->c2hcmd_list);
+
+       spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags);
+
+       /* wake up wq */
+       queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.c2hcmd_wq, 0);
+
+       return;
+
+label_err2:
+       kfree(c2hcmd);
+
+label_err:
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_WARNING,
+                "C2H cmd enqueue fail.\n");
+}
+EXPORT_SYMBOL(rtl_c2hcmd_enqueue);
+
+void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       unsigned long flags;
+       struct rtl_c2hcmd *c2hcmd;
+       int i;
+
+       for (i = 0; i < 200; i++) {
+               /* dequeue a task */
+               spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags);
+
+               c2hcmd = list_first_entry_or_null(&rtlpriv->c2hcmd_list,
+                                                 struct rtl_c2hcmd, list);
+
+               if (c2hcmd)
+                       list_del(&c2hcmd->list);
+
+               spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags);
+
+               /* do it */
+               if (!c2hcmd)
+                       break;
+
+               if (rtlpriv->cfg->ops->c2h_content_parsing && exec)
+                       rtlpriv->cfg->ops->c2h_content_parsing(hw,
+                                       c2hcmd->tag, c2hcmd->len, c2hcmd->val);
+
+               /* free */
+               kfree(c2hcmd->val);
+
+               kfree(c2hcmd);
+       }
+}
+
+void rtl_c2hcmd_wq_callback(void *data)
+{
+       struct rtl_works *rtlworks = container_of_dwork_rtl(data,
+                                                           struct rtl_works,
+                                                           c2hcmd_wq);
+       struct ieee80211_hw *hw = rtlworks->hw;
+
+       rtl_c2hcmd_launcher(hw, 1);
+}
+
 void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
 {
        struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
index 6c770aecebe79b1212add4be0eacf2145849448a..02ff0c5624a773fa0119a616b3bb3e6be42bf0e5 100644 (file)
@@ -136,6 +136,9 @@ int rtl_rx_agg_stop(struct ieee80211_hw *hw,
                    struct ieee80211_sta *sta, u16 tid);
 void rtl_watchdog_wq_callback(void *data);
 void rtl_fwevt_wq_callback(void *data);
+void rtl_c2hcmd_wq_callback(void *data);
+void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec);
+void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val);
 
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
                      struct ieee80211_tx_info *info,
index 9d7a16c9e74ef9186dada1f2dba9230f36fbc8ad..9fec345a42a01c1a03fd74f6b4b9f14cfd148598 100644 (file)
@@ -764,8 +764,8 @@ static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
        rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
 }
 
-static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
-                                        u8 c2h_cmd_len, u8 *tmp_buf)
+void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
+                                u8 c2h_cmd_len, u8 *tmp_buf)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -820,5 +820,14 @@ void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
        RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
                      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
 
-       _rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+       switch (c2h_cmd_id) {
+       case C2H_8192E_BT_INFO:
+       case C2H_8192E_BT_MP:
+               rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+               break;
+       default:
+               rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len,
+                                           tmp_buf);
+               break;
+       }
 }
index 069da1e7e80a481fbd17179917fdca018536a77d..72da3f92f02c57911ee307e5c74e22d8750e97fb 100644 (file)
@@ -185,5 +185,6 @@ void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus);
 void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
 void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
 void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len);
-
+void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
+                                u8 c2h_cmd_len, u8 *tmp_buf);
 #endif
index 554f2dc86bc5acd3f2877f41e77a03e517cb724d..48820bc497d805716a6c0f018feaf8fad97d8917 100644 (file)
@@ -248,6 +248,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = {
        .fill_h2c_cmd = rtl92ee_fill_h2c_cmd,
        .get_btc_status = rtl92ee_get_btc_status,
        .rx_command_packet = rtl92ee_rx_command_packet,
+       .c2h_content_parsing = rtl92ee_c2h_content_parsing,
 };
 
 static struct rtl_mod_params rtl92ee_mod_params = {
index fbf396143985f47f4989547e26ae323dae3f6592..c7ee9ba5e26ea15e4152e2ed4110e946f4d5b78a 100644 (file)
@@ -585,9 +585,9 @@ void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
                               (u8 *)p2p_ps_offload);
 }
 
-static void _rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
-                                          u8 c2h_cmd_id,
-                                          u8 c2h_cmd_len, u8 *tmp_buf)
+void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
+                                  u8 c2h_cmd_id,
+                                  u8 c2h_cmd_len, u8 *tmp_buf)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -635,5 +635,15 @@ void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
        RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
                      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
 
-       _rtl8723be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+       switch (c2h_cmd_id) {
+       case C2H_8723B_BT_INFO:
+       case C2H_8723B_BT_MP:
+               rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+               break;
+
+       default:
+               rtl8723be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len,
+                                             tmp_buf);
+               break;
+       }
 }
index 067429669bdad6f3382136a87db11033d9d0eb6e..c652fa1339a760642a8c021c8200ba4777de49ed 100644 (file)
@@ -148,5 +148,6 @@ void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus);
 void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
 void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
 void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len);
-
+void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
+                                  u8 c2h_cmd_len, u8 *tmp_buf);
 #endif
index e571b876f0af9cbaaefd30a96bbdbfc7db402c63..92dbfa8f297f318a766506e50be2d102c312f470 100644 (file)
@@ -260,6 +260,7 @@ static struct rtl_hal_ops rtl8723be_hal_ops = {
        .get_btc_status = rtl8723be_get_btc_status,
        .rx_command_packet = rtl8723be_rx_command_packet,
        .is_fw_header = is_fw_header,
+       .c2h_content_parsing = rtl8723be_c2h_content_parsing,
 };
 
 static struct rtl_mod_params rtl8723be_mod_params = {
index 328c64d465ba40829eb3682c0cd289f58b227302..a504dfae4ed37486ea90451bd000022c4eac56f4 100644 (file)
@@ -1740,9 +1740,9 @@ static void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw,
        rtl8821ae_dm_update_init_rate(hw, rate);
 }
 
-static void _rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw,
-                                          u8 c2h_cmd_id, u8 c2h_cmd_len,
-                                          u8 *tmp_buf)
+void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw,
+                                  u8 c2h_cmd_id, u8 c2h_cmd_len,
+                                  u8 *tmp_buf)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -1784,5 +1784,15 @@ void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer,
 
        RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD,
                      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
-       _rtl8821ae_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+
+       switch (c2h_cmd_id) {
+       case C2H_8812_BT_INFO:
+               rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+               break;
+
+       default:
+               rtl8821ae_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len,
+                                             tmp_buf);
+               break;
+       }
 }
index 8f5b4aade3c91f356748dffa41318ce557c10bd5..90a98ed879f7e839b6f85a12240a673f4a18c5b6 100644 (file)
@@ -329,4 +329,7 @@ void rtl8821ae_set_fw_disconnect_decision_ctrl_cmd(struct ieee80211_hw *hw,
 void rtl8821ae_set_fw_global_info_cmd(struct ieee80211_hw *hw);
 void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw,
                                  u8 *buffer, u8 length);
+void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw,
+                                  u8 c2h_cmd_id, u8 c2h_cmd_len,
+                                  u8 *tmp_buf);
 #endif
index cd2a53b7e053cf3fafb1dcd03434bd75f4da2451..77cf3b2cd3f1f4c7ba93437996efe55ad3d94fb5 100644 (file)
@@ -297,6 +297,7 @@ static struct rtl_hal_ops rtl8821ae_hal_ops = {
        .fill_h2c_cmd = rtl8821ae_fill_h2c_cmd,
        .get_btc_status = rtl8821ae_get_btc_status,
        .rx_command_packet = rtl8821ae_rx_command_packet,
+       .c2h_content_parsing = rtl8821ae_c2h_content_parsing,
        .add_wowlan_pattern = rtl8821ae_add_wowlan_pattern,
 };
 
index 4dad962f9a616ef6224558d5534e58cb2df26710..e6be5641d4da25b70ffadde357b58630f74faa9f 100644 (file)
@@ -2202,6 +2202,8 @@ struct rtl_hal_ops {
                                   struct rtl_wow_pattern *rtl_pattern,
                                   u8 index);
        u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx);
+       void (*c2h_content_parsing)(struct ieee80211_hw *hw, u8 tag, u8 len,
+                                   u8 *val);
 };
 
 struct rtl_intf_ops {
@@ -2317,6 +2319,7 @@ struct rtl_locks {
        spinlock_t waitq_lock;
        spinlock_t entry_list_lock;
        spinlock_t usb_lock;
+       spinlock_t c2hcmd_lock;
 
        /*FW clock change */
        spinlock_t fw_ps_lock;
@@ -2346,6 +2349,7 @@ struct rtl_works {
        struct workqueue_struct *rtl_wq;
        struct delayed_work watchdog_wq;
        struct delayed_work ips_nic_off_wq;
+       struct delayed_work c2hcmd_wq;
 
        /* For SW LPS */
        struct delayed_work ps_work;
@@ -2553,6 +2557,13 @@ struct proxim {
        u8  (*proxim_get_var)(struct ieee80211_hw *hw, u8 type);
 };
 
+struct rtl_c2hcmd {
+       struct list_head list;
+       u8 tag;
+       u8 len;
+       u8 *val;
+};
+
 struct rtl_priv {
        struct ieee80211_hw *hw;
        struct completion firmware_loading_complete;
@@ -2585,6 +2596,9 @@ struct rtl_priv {
        /* sta entry list for ap adhoc or mesh */
        struct list_head entry_list;
 
+       /* c2hcmd list for kthread level access */
+       struct list_head c2hcmd_list;
+
        int max_fw_size;
 
        /*