From d4a1bd480003f3e1a0590bc46fbcb24f05652ca7 Mon Sep 17 00:00:00 2001
From: tzh <tanzhtanzh@gmail.com>
Date: Thu, 15 Aug 2024 06:56:47 +0000
Subject: [PATCH] feat(wfit/bt): update aic8800 wifi/bt drive and hal

---
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c |  402 ++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 225 insertions(+), 177 deletions(-)

diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c
old mode 100644
new mode 100755
index 6d0bae9..034fc08
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c
@@ -25,6 +25,7 @@
 #include "mach/jzmmc.h"
 #endif /* CONFIG_INGENIC_T20 */
 #include "aic_bsp_export.h"
+#include "rwnx_wakelock.h"
 extern uint8_t scanning;
 
 int aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val)
@@ -45,7 +46,7 @@
 	return ret;
 }
 
-int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
+int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev)
 {
 	int ret = -1;
 	u8 fc_reg = 0;
@@ -69,9 +70,42 @@
 			if (count < 30)
 				udelay(200);
 			else if (count < 40)
-				mdelay(1);
+				msleep(2);
 			else
-				mdelay(10);
+				msleep(10);
+		}
+	}
+
+	return ret;
+}
+
+int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
+{
+	int ret = -1;
+	u8 fc_reg = 0;
+	u32 count = 0;
+
+	while (true) {
+		ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
+		if (ret) {
+			return -1;
+		}
+
+		if ((fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG) > DATA_FLOW_CTRL_THRESH) {
+			ret = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
+			return ret;
+		} else {
+			if (count >= FLOW_CTRL_RETRY_COUNT) {
+				ret = -fc_reg;
+				break;
+			}
+			count++;
+			if (count < 30)
+				udelay(200);
+			else if (count < 40)
+				msleep(2);
+			else
+				msleep(10);
 		}
 	}
 
@@ -110,8 +144,6 @@
 	return ret;
 }
 
-static int wakeup_enable;
-static u32 hostwake_irq_num;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
 extern int sunxi_wlan_get_oob_irq(int *, int *);
 #else
@@ -119,23 +151,11 @@
 extern int sunxi_wlan_get_oob_irq_flags(void);
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-static struct wakeup_source *ws;
-#else
-#include <linux/wakelock.h>
-static struct wake_lock irq_wakelock;
-#endif
-
 static irqreturn_t rwnx_hostwake_irq_handler(int irq, void *para)
 {
 	static int wake_cnt;
 	wake_cnt++;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-	__pm_wakeup_event(ws, HZ / 20);
-#else
-	wake_lock_timeout(&irq_wakelock, HZ / 20);
-#endif
-	printk("%s(%d): wake_irq_cnt = %d\n", __func__, __LINE__, wake_cnt);
+	rwnx_wakeup_lock_timeout(g_rwnx_plat->sdiodev->rwnx_hw->ws_rx, jiffies_to_msecs(5));
 	return IRQ_HANDLED;
 }
 
@@ -143,6 +163,8 @@
 {
 	int ret = -1;
 	int irq_flags;
+	int wakeup_enable;
+	u32 hostwake_irq_num;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
 	hostwake_irq_num = sunxi_wlan_get_oob_irq(&irq_flags, &wakeup_enable);
 #else
@@ -172,13 +194,10 @@
 			pr_err("%s(%d): request_irq fail! ret = %d\n", __func__, __LINE__, ret);
 			goto fail2;
 		}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-		ws = wakeup_source_register(dev, "wifisleep");
-#else
-		wake_lock_init(&irq_wakelock, WAKE_LOCK_SUSPEND, "wifisleep");
-#endif
 	}
-	disable_irq(hostwake_irq_num);
+	g_rwnx_plat->sdiodev->rwnx_hw->wakeup_enable = wakeup_enable;
+	g_rwnx_plat->sdiodev->rwnx_hw->hostwake_irq_num = hostwake_irq_num;
+
 	printk("%s(%d)\n", __func__, __LINE__);
 	return ret;
 
@@ -191,31 +210,14 @@
 
 static int rwnx_unregister_hostwake_irq(struct device *dev)
 {
+	int wakeup_enable = g_rwnx_plat->sdiodev->rwnx_hw->wakeup_enable;
+	u32 hostwake_irq_num = g_rwnx_plat->sdiodev->rwnx_hw->hostwake_irq_num;
 	if (wakeup_enable) {
+		free_irq(hostwake_irq_num, NULL);
 		device_init_wakeup(dev, false);
 		dev_pm_clear_wake_irq(dev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-		wakeup_source_unregister(ws);
-#else
-		wake_lock_destroy(&irq_wakelock);
-#endif
 	}
-	free_irq(hostwake_irq_num, NULL);
 	printk("%s(%d)\n", __func__, __LINE__);
-	return 0;
-}
-
-static int rwnx_enable_hostwake_irq(void)
-{
-	enable_irq(hostwake_irq_num);
-	printk("%s(%d)\n", __func__, __LINE__);
-	return 0;
-}
-
-static int rwnx_disable_hostwake_irq(void)
-{
-	printk("%s(%d)\n", __func__, __LINE__);
-	disable_irq(hostwake_irq_num);
 	return 0;
 }
 
@@ -257,19 +259,26 @@
 		goto fail;
 	}
 
-	aicwf_sdio_bus_init(sdiodev);
+	if (aicwf_sdio_bus_init(sdiodev) == NULL) {
+		sdio_err("sdio bus init fail\n");
+		err = -1;
+		goto fail;
+	}
+
 	host->caps |= MMC_CAP_NONREMOVABLE;
 	aicwf_rwnx_sdio_platform_init(sdiodev);
-	aicwf_hostif_ready();
 	err = rwnx_register_hostwake_irq(sdiodev->dev);
 	if (err != 0)
-		return err;
+		aicwf_hostif_fail();
+	else
+		aicwf_hostif_ready();
 	return 0;
 fail:
 	aicwf_sdio_func_deinit(sdiodev);
 	dev_set_drvdata(&func->dev, NULL);
 	kfree(sdiodev);
 	kfree(bus_if);
+	aicwf_hostif_fail();
 	return err;
 }
 
@@ -291,7 +300,6 @@
 	if (!sdiodev) {
 		return;
 	}
-	rwnx_unregister_hostwake_irq(sdiodev->dev);
 	sdiodev->bus_if->state = BUS_DOWN_ST;
 	aicwf_sdio_release(sdiodev);
 	aicwf_sdio_func_deinit(sdiodev);
@@ -331,7 +339,6 @@
 		up(&sdiodev->tx_priv->txctl_sema);
 		break;
 	}
-	rwnx_enable_hostwake_irq();
 
 	return 0;
 }
@@ -343,17 +350,11 @@
 	struct rwnx_vif *rwnx_vif, *tmp;
 
 	sdio_dbg("%s\n", __func__);
-	rwnx_disable_hostwake_irq();
 	list_for_each_entry_safe(rwnx_vif, tmp, &sdiodev->rwnx_hw->vifs, list) {
 		if (rwnx_vif->ndev)
 			netif_device_attach(rwnx_vif->ndev);
 	}
 	aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
-	__pm_relax(ws);
-#else
-	wake_unlock(&irq_wakelock);
-#endif
 
 	return 0;
 }
@@ -418,9 +419,12 @@
 
 void aicwf_sdio_exit(void)
 {
-	if (g_rwnx_plat && g_rwnx_plat->enabled)
+	if (g_rwnx_plat && g_rwnx_plat->enabled) {
+		rwnx_unregister_hostwake_irq(g_rwnx_plat->sdiodev->dev);
 		rwnx_platform_deinit(g_rwnx_plat->sdiodev->rwnx_hw);
+	}
 
+	udelay(500);
 	sdio_unregister_driver(&aicwf_sdio_driver);
 
 #ifdef CONFIG_PLATFORM_NANOPI
@@ -436,52 +440,44 @@
 		int write_retry = 20;
 
 	if (sdiodev->state == SDIO_SLEEP_ST) {
-		down(&sdiodev->pwrctl_wakeup_sema);
-		if (sdiodev->rwnx_hw->vif_started) {
-			if (sdiodev->state == SDIO_ACTIVE_ST) {
-				up(&sdiodev->pwrctl_wakeup_sema);
-				return 0;
-			}
-			sdio_info("w\n");
-			while (write_retry) {
-				ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
-				if (ret) {
-					txrx_err("sdio wakeup fail\n");
-					ret = -1;
-				} else {
-					read_retry = 10;
-					while (read_retry) {
-						u8 val;
-						ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
-						if ((ret == 0) && (val & 0x10)) {
-							break;
-						}
-						read_retry--;
-						udelay(200);
-					}
-					if (read_retry != 0)
+		sdio_info("w\n");
+		while (write_retry) {
+			ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
+			if (ret) {
+				txrx_err("sdio wakeup fail\n");
+				ret = -1;
+			} else {
+				read_retry = 10;
+				while (read_retry) {
+					u8 val;
+					ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
+					if (ret < 0)
+						txrx_err("sdio wakeup read fail\n");
+					else if (val & 0x10) {
 						break;
+					}
+					read_retry--;
+					udelay(200);
 				}
-				sdio_dbg("write retry:  %d \n", write_retry);
-				write_retry--;
-				udelay(100);
+				if (read_retry != 0)
+					break;
 			}
+			sdio_dbg("write retry:  %d \n", write_retry);
+			write_retry--;
+			udelay(100);
 		}
 
 		sdiodev->state = SDIO_ACTIVE_ST;
 		aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
-		up(&sdiodev->pwrctl_wakeup_sema);
 	}
 	return ret;
 }
 
-extern u8 dhcped;
 int aicwf_sdio_sleep_allow(struct aic_sdio_dev *sdiodev)
 {
 	int ret = 0;
 	struct aicwf_bus *bus_if = sdiodev->bus_if;
 	struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw;
-	struct rwnx_vif *rwnx_vif, *tmp;
 
 	if (bus_if->state == BUS_DOWN_ST) {
 		ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
@@ -492,36 +488,15 @@
 		return ret;
 	}
 
-	list_for_each_entry_safe(rwnx_vif, tmp, &rwnx_hw->vifs, list) {
-		if ((rwnx_hw->avail_idx_map & BIT(rwnx_vif->drv_vif_index)) == 0) {
-			switch (RWNX_VIF_TYPE(rwnx_vif)) {
-			case NL80211_IFTYPE_P2P_CLIENT:
-				rwnx_hw->is_p2p_alive = 1;
-				return ret;
-			case NL80211_IFTYPE_AP:
-				return ret;
-			case NL80211_IFTYPE_P2P_GO:
-				rwnx_hw->is_p2p_alive = 1;
-				return ret;
-			default:
-				break;
-			}
-		}
-	}
-
 	sdio_info("sleep: %d, %d\n", sdiodev->state, scanning);
 	if (sdiodev->state == SDIO_ACTIVE_ST  && !scanning && !rwnx_hw->is_p2p_alive \
-				&& !rwnx_hw->is_p2p_connected) {// && dhcped) {
-		down(&sdiodev->pwrctl_wakeup_sema);
-		if (rwnx_hw->vif_started) {
-			sdio_info("s\n");
-			ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
-			if (ret)
-				sdio_err("Write sleep fail!\n");
-		}
+				&& !rwnx_hw->is_p2p_connected) {
+		sdio_info("s\n");
+		ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
+		if (ret)
+			sdio_err("Write sleep fail!\n");
 		sdiodev->state = SDIO_SLEEP_ST;
 		aicwf_sdio_pwrctl_timer(sdiodev, 0);
-		up(&sdiodev->pwrctl_wakeup_sema);
 	} else {
 		aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
 	}
@@ -537,10 +512,13 @@
 		return -1;
 	}
 
+	down(&sdiodev->pwrctl_wakeup_sema);
+
 	if (sdiodev->state == target) {
 		if (target == SDIO_ACTIVE_ST) {
 			aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
 		}
+		up(&sdiodev->pwrctl_wakeup_sema);
 		return ret;
 	}
 
@@ -553,6 +531,7 @@
 		break;
 	}
 
+	up(&sdiodev->pwrctl_wakeup_sema);
 	return ret;
 }
 
@@ -599,30 +578,25 @@
 {
 	struct aicwf_bus *bus_if = dev_get_drvdata(dev);
 	struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
-	int ret;
+	int ret = 0;
 
 	aicwf_sdio_pwrctl_timer(sdiodev, 0);
-	if (timer_pending(&sdiodev->rwnx_hw->p2p_alive_timer)) {
-		ret = del_timer(&sdiodev->rwnx_hw->p2p_alive_timer);
-	}
 	sdio_dbg("%s\n", __func__);
-	if (sdiodev->pwrctl_tsk) {
-		complete(&sdiodev->pwrctrl_trgg);
-		kthread_stop(sdiodev->pwrctl_tsk);
-		sdiodev->pwrctl_tsk = NULL;
-	}
-
-	sdio_dbg("%s:pwrctl stopped\n", __func__);
 
 	bus_if->state = BUS_DOWN_ST;
-	ret = down_interruptible(&sdiodev->tx_priv->txctl_sema);
-	if (ret)
-	   sdio_err("down txctl_sema fail\n");
+	if (sdiodev->tx_priv) {
+		ret = down_interruptible(&sdiodev->tx_priv->txctl_sema);
+		if (ret)
+			sdio_err("down txctl_sema fail\n");
+	}
 
 	aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
-	if (!ret)
-		up(&sdiodev->tx_priv->txctl_sema);
-	aicwf_frame_queue_flush(&sdiodev->tx_priv->txq);
+
+	if (sdiodev->tx_priv) {
+		if (!ret)
+			up(&sdiodev->tx_priv->txctl_sema);
+		aicwf_frame_queue_flush(&sdiodev->tx_priv->txq);
+	}
 	sdio_dbg("exit %s\n", __func__);
 }
 
@@ -680,10 +654,10 @@
 	} else
 		len = payload_len;
 
-	buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
-	while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 5) {
+	buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
+	while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 10) {
 		retry++;
-		buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
+		buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
 		printk("buffer_cnt = %d\n", buffer_cnt);
 	}
 
@@ -756,9 +730,18 @@
 
 	sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
 	while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) {
-		aicwf_sdio_send(sdiodev->tx_priv);
-		if (sdiodev->tx_priv->cmd_txstate)
-			break;
+		if (sdiodev->tx_priv->fw_avail_bufcnt <= DATA_FLOW_CTRL_THRESH) {
+			if (sdiodev->tx_priv->cmd_txstate)
+				break;
+			sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
+		} else {
+			if (sdiodev->tx_priv->cmd_txstate) {
+				aicwf_sdio_send(sdiodev->tx_priv, 1);
+				break;
+			} else {
+				aicwf_sdio_send(sdiodev->tx_priv, 0);
+			}
+		}
 	}
 
 	up(&sdiodev->tx_priv->txctl_sema);
@@ -774,7 +757,11 @@
 	prio = (pkt->priority & 0x7);
 	spin_lock_bh(&sdiodev->tx_priv->txqlock);
 	if (!aicwf_frame_enq(sdiodev->dev, &sdiodev->tx_priv->txq, pkt, prio)) {
-		aicwf_dev_skb_free(pkt);
+		struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data;
+		int headroom = txhdr->sw_hdr->headroom;
+		kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
+		skb_pull(pkt, headroom);
+		consume_skb(pkt);
 		spin_unlock_bh(&sdiodev->tx_priv->txqlock);
 		return -ENOSR;
 	} else {
@@ -789,7 +776,8 @@
 
 	atomic_inc(&sdiodev->tx_priv->tx_pktcnt);
 	spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-	complete(&bus_if->bustx_trgg);
+	if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 1)
+		complete(&bus_if->bustx_trgg);
 
 	return ret;
 }
@@ -829,13 +817,11 @@
 	return 0;
 }
 
-int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv)
+int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv, u8 txnow)
 {
 	struct sk_buff *pkt;
 	struct aic_sdio_dev *sdiodev = tx_priv->sdiodev;
 	u32 aggr_len = 0;
-	int retry_times = 0;
-	int max_retry_times = 5;
 
 	aggr_len = (tx_priv->tail - tx_priv->head);
 	if (((atomic_read(&tx_priv->aggr_count) == 0) && (aggr_len != 0))
@@ -845,19 +831,7 @@
 		goto done;
 	}
 
-	if (tx_priv->fw_avail_bufcnt <= 0) { //flow control failed
-		tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
-		while (tx_priv->fw_avail_bufcnt <= 0 && retry_times < max_retry_times) {
-			retry_times++;
-			tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
-		}
-		if (tx_priv->fw_avail_bufcnt <= 0) {
-			sdio_err("fc retry %d fail\n", tx_priv->fw_avail_bufcnt);
-			goto done;
-		}
-	}
-
-	if (atomic_read(&tx_priv->aggr_count) == tx_priv->fw_avail_bufcnt) {
+	if (atomic_read(&tx_priv->aggr_count) == (tx_priv->fw_avail_bufcnt - DATA_FLOW_CTRL_THRESH)) {
 		if (atomic_read(&tx_priv->aggr_count) > 0) {
 			tx_priv->fw_avail_bufcnt -= atomic_read(&tx_priv->aggr_count);
 			aicwf_sdio_aggr_send(tx_priv); //send and check the next pkt;
@@ -882,7 +856,7 @@
 		}
 
 		//when aggr finish or there is cmd to send, just send this aggr pkt to fw
-		if ((int)atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 0 || sdiodev->tx_priv->cmd_txstate) { //no more pkt send it!
+		if ((int)atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 0 || txnow || (atomic_read(&tx_priv->aggr_count) == (tx_priv->fw_avail_bufcnt - DATA_FLOW_CTRL_THRESH))) {
 			tx_priv->fw_avail_bufcnt -= atomic_read(&tx_priv->aggr_count);
 			aicwf_sdio_aggr_send(tx_priv);
 		} else
@@ -893,6 +867,41 @@
 	return 0;
 }
 
+static void aicwf_count_tx_tp(struct aicwf_tx_priv *tx_priv, int len)
+{
+#ifdef AICWF_SDIO_SUPPORT
+	struct device *rwnx_dev = tx_priv->sdiodev->dev;
+#endif
+#ifdef AICWF_USB_SUPPORT
+	struct device *rwnx_dev = tx_priv->usbdev->dev;
+#endif
+	long long timeus = 0;
+	char *envp[] = {
+		"SYSTEM=WIFI",
+		"EVENT=BOOSTREQ",
+		"SUBEVENT=TX",
+		"TIMEOUT_SEC=5",
+		NULL};
+
+	tx_priv->tx_data_len += len;
+
+	tx_priv->txtimeend = ktime_get();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
+	timeus = div_u64(tx_priv->txtimeend.tv64 - tx_priv->txtimebegin.tv64, NSEC_PER_USEC);
+#else
+	timeus = ktime_to_us(tx_priv->txtimeend - tx_priv->txtimebegin);
+#endif
+
+	if (timeus >= USEC_PER_SEC) {
+		// calc & send uevent
+		if (div_u64(tx_priv->tx_data_len, timeus) >= 6)
+			kobject_uevent_env(&rwnx_dev->kobj, KOBJ_CHANGE, envp);
+
+		tx_priv->tx_data_len = 0;
+		tx_priv->txtimebegin = tx_priv->txtimeend;
+	}
+}
+
 int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt)
 {
 	struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data;
@@ -901,7 +910,9 @@
 	u8 adjust_str[4] = {0, 0, 0, 0};
 	u32 curr_len = 0;
 	int allign_len = 0;
+	int headroom;
 
+	aicwf_count_tx_tp(tx_priv, pkt->len);
 	sdio_header[0] = ((pkt->len - sizeof(struct rwnx_txhdr) + sizeof(struct txdesc_api)) & 0xff);
 	sdio_header[1] = (((pkt->len - sizeof(struct rwnx_txhdr) + sizeof(struct txdesc_api)) >> 8)&0x0f);
 	sdio_header[2] = 0x01; //data
@@ -928,8 +939,9 @@
 	tx_priv->aggr_buf->dev = pkt->dev;
 
 	if (!txhdr->sw_hdr->need_cfm) {
+		headroom = txhdr->sw_hdr->headroom;
 		kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
-		skb_pull(pkt, txhdr->sw_hdr->headroom);
+		skb_pull(pkt, headroom);
 		consume_skb(pkt);
 	}
 
@@ -984,10 +996,10 @@
 #endif
 	//enable sdio interrupt
 	ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x07);
-	sdio_release_host(sdiodev->func);
-
 	if (ret != 0)
 		sdio_err("intr register failed:%d\n", ret);
+
+	sdio_release_host(sdiodev->func);
 
 	bus_if->state = BUS_UP_ST;
 
@@ -1006,10 +1018,15 @@
 		}
 		if (!wait_for_completion_interruptible(&bus->bustx_trgg)) {
 			if (sdiodev->bus_if->state == BUS_DOWN_ST)
-				break;
+				continue;
 
-			if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true))
+			rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_tx);
+			while ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true)) {
 				aicwf_sdio_tx_process(sdiodev);
+				if (sdiodev->bus_if->state == BUS_DOWN_ST)
+					break;
+			}
+			rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_tx);
 		}
 	}
 
@@ -1020,6 +1037,7 @@
 {
 	struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data;
 	struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if;
+	struct aic_sdio_dev *sdiodev = rx_priv->sdiodev;
 
 	while (1) {
 		if (kthread_should_stop()) {
@@ -1028,8 +1046,10 @@
 		}
 		if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
 			if (bus_if->state == BUS_DOWN_ST)
-				break;
+				continue;
+			rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_rx);
 			aicwf_process_rxframes(rx_priv);
+			rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_rx);
 		}
 	}
 
@@ -1047,16 +1067,15 @@
 		}
 		if (!wait_for_completion_interruptible(&sdiodev->pwrctrl_trgg)) {
 			if (sdiodev->bus_if->state == BUS_DOWN_ST)
-				break;
-			if (sdiodev->state == SDIO_ACTIVE_ST) {
-				if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) <= 0) && (sdiodev->tx_priv->cmd_txstate == false) && \
-						atomic_read(&sdiodev->rx_priv->rx_cnt) == 0)
-					aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
-				else
-					aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
-			}
-		} else {
-			continue;
+				continue;
+
+			rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_pwrctrl);
+			if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) <= 0) && (sdiodev->tx_priv->cmd_txstate == false) && \
+					atomic_read(&sdiodev->rx_priv->rx_cnt) == 0)
+				aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
+			else
+				aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
+			rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_pwrctrl);
 		}
 	}
 
@@ -1142,7 +1161,8 @@
 	if (pkt)
 		aicwf_sdio_enq_rxpkt(sdiodev, pkt);
 
-	complete(&bus_if->busrx_trgg);
+	if (atomic_read(&sdiodev->rx_priv->rx_cnt) == 1)
+		complete(&bus_if->busrx_trgg);
 }
 
 void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration)
@@ -1174,7 +1194,6 @@
 void aicwf_sdio_release(struct aic_sdio_dev *sdiodev)
 {
 	struct aicwf_bus *bus_if;
-	struct aicwf_rx_priv *rx_priv = NULL;
 	int ret;
 	sdio_dbg("%s\n", __func__);
 
@@ -1193,11 +1212,22 @@
 	if (sdiodev->dev)
 		aicwf_bus_deinit(sdiodev->dev);
 
-	aicwf_tx_deinit(sdiodev->tx_priv);
-	rx_priv = sdiodev->rx_priv;
-	if (rx_priv != NULL)
-		aicwf_rx_deinit(rx_priv);
-	rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr);
+	if (sdiodev->tx_priv)
+		aicwf_tx_deinit(sdiodev->tx_priv);
+
+	if (sdiodev->rx_priv)
+		aicwf_rx_deinit(sdiodev->rx_priv);
+
+	if (sdiodev->pwrctl_tsk) {
+		complete_all(&sdiodev->pwrctrl_trgg);
+		kthread_stop(sdiodev->pwrctl_tsk);
+		sdiodev->pwrctl_tsk = NULL;
+	}
+
+	sdio_dbg("%s:pwrctl stopped\n", __func__);
+
+	if (sdiodev->cmd_mgr.state == RWNX_CMD_MGR_STATE_INITED)
+		rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr);
 	sdio_dbg("exit %s\n", __func__);
 }
 
@@ -1208,6 +1238,7 @@
 	u8 byte_mode_disable = 0x1;//1: no byte mode
 	int ret = 0;
 	struct aicbsp_feature_t feature;
+	u8 val = 0;
 
 	aicbsp_get_feature(&feature);
 	host = sdiodev->func->card->host;
@@ -1252,6 +1283,23 @@
 		return ret;
 	}
 
+	ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
+	if (ret < 0) {
+		sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+		return ret;
+	}
+
+	mdelay(5);
+	ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
+	if (ret < 0) {
+		sdio_err("reg:%d read failed!\n", SDIOWIFI_SLEEP_REG);
+		return ret;
+	}
+
+	if (!(val & 0x10))
+		sdio_dbg("wakeup fail\n");
+	else
+		sdio_info("sdio ready\n");
 	return ret;
 }
 

--
Gitblit v1.6.2