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