From 8777e41f161c3a785d04d439ceec2657492802ba Mon Sep 17 00:00:00 2001 From: Dmitry Tarnyagin Date: Wed, 13 Jul 2011 23:03:17 +0200 Subject: cw1200: Wakeup on wireless (WoW) is implemented. + Core and SDIO power management is implemented as defined in wireless-next v3.0-rc4. + SDD is cached to avoid disk access at suspend/resume time. TODO: - WoW conditions and filtering are not yet implemented. - BUG: Late interrupts (coming after suspend() callback but before the actual suspend) are not detected as wakeup sources. Universal (Android/GLK) way of waking up halfly-suspended system to be found. Signed-off-by: Dmitry Tarnyagin Change-Id: Ib4931a261e592f2927455e988055cd673250ec81 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/27297 Tested-by: Bartosz MARKOWSKI Reviewed-by: Bartosz MARKOWSKI Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33484 Reviewed-by: Philippe LANGLAIS --- drivers/staging/cw1200/Makefile | 3 +- drivers/staging/cw1200/bh.c | 70 +++++++++++++++-- drivers/staging/cw1200/bh.h | 2 + drivers/staging/cw1200/cw1200.h | 17 +++-- drivers/staging/cw1200/cw1200_plat.h | 5 ++ drivers/staging/cw1200/cw1200_sdio.c | 45 +++++++---- drivers/staging/cw1200/main.c | 25 ++++-- drivers/staging/cw1200/pm.c | 142 +++++++++++++++++++++++++++++++++++ drivers/staging/cw1200/pm.h | 23 ++++++ drivers/staging/cw1200/sbus.h | 1 + drivers/staging/cw1200/sta.c | 58 +++++++------- drivers/staging/cw1200/sta.h | 1 + drivers/staging/cw1200/wsm.c | 4 +- 13 files changed, 329 insertions(+), 67 deletions(-) create mode 100644 drivers/staging/cw1200/pm.c create mode 100644 drivers/staging/cw1200/pm.h diff --git a/drivers/staging/cw1200/Makefile b/drivers/staging/cw1200/Makefile index fae984d10ce..c0e88bd0f11 100644 --- a/drivers/staging/cw1200/Makefile +++ b/drivers/staging/cw1200/Makefile @@ -9,7 +9,8 @@ cw1200_core-y := \ sta.o \ ap.o \ scan.o -cw1200_core-$(CONFIG_CW1200_DEBUGFS) += debug.o +cw1200_core-$(CONFIG_CW1200_DEBUGFS) += debug.o +cw1200_core-$(CONFIG_PM) += pm.o cw1200_wlan-y := cw1200_sdio.o diff --git a/drivers/staging/cw1200/bh.c b/drivers/staging/cw1200/bh.c index d49f9fdf732..2d438a96e38 100644 --- a/drivers/staging/cw1200/bh.c +++ b/drivers/staging/cw1200/bh.c @@ -39,6 +39,14 @@ static int cw1200_bh(void *arg); #define PIGGYBACK_CTRL_REG (2) #define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) +/* Suspend state privates */ +enum cw1200_bh_pm_state { + CW1200_BH_RESUMED = 0, + CW1200_BH_SUSPEND, + CW1200_BH_SUSPENDED, + CW1200_BH_RESUME, +}; + typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv, u8 *data, size_t size); @@ -52,10 +60,11 @@ int cw1200_register_bh(struct cw1200_common *priv) atomic_set(&priv->bh_rx, 0); atomic_set(&priv->bh_tx, 0); atomic_set(&priv->bh_term, 0); + atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); priv->buf_id_tx = 0; priv->buf_id_rx = 0; init_waitqueue_head(&priv->bh_wq); - init_waitqueue_head(&priv->hw_bufs_used_wq); + init_waitqueue_head(&priv->bh_evt_wq); priv->bh_thread = kthread_create(&cw1200_bh, priv, "cw1200_bh"); if (IS_ERR(priv->bh_thread)) { err = PTR_ERR(priv->bh_thread); @@ -107,6 +116,30 @@ void cw1200_bh_wakeup(struct cw1200_common *priv) wake_up_interruptible(&priv->bh_wq); } +void cw1200_bh_suspend(struct cw1200_common *priv) +{ + bh_printk(KERN_DEBUG "[BH] suspend.\n"); + if (WARN_ON(priv->bh_error)) + return; + + atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND); + wake_up_interruptible(&priv->bh_wq); + wait_event_interruptible(priv->bh_evt_wq, priv->bh_error || + (CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend))); +} + +void cw1200_bh_resume(struct cw1200_common *priv) +{ + bh_printk(KERN_DEBUG "[BH] resume.\n"); + if (WARN_ON(priv->bh_error)) + return; + + atomic_set(&priv->bh_suspend, CW1200_BH_RESUME); + wake_up_interruptible(&priv->bh_wq); + wait_event_interruptible(priv->bh_evt_wq, priv->bh_error || + (CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend))); +} + static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv) { ++priv->hw_bufs_used; @@ -123,7 +156,7 @@ int wsm_release_tx_buffer(struct cw1200_common *priv, int count) else if (hw_bufs_used >= priv->wsm_caps.numInpChBufs) ret = 1; if (!priv->hw_bufs_used) - wake_up_interruptible(&priv->hw_bufs_used_wq); + wake_up_interruptible(&priv->bh_evt_wq); return ret; } @@ -221,7 +254,7 @@ static int cw1200_bh(void *arg) struct cw1200_common *priv = arg; struct sk_buff *skb_rx = NULL; size_t read_len = 0; - int rx, tx, term; + int rx, tx, term, suspend; struct wsm_hdr *wsm; size_t wsm_len; int wsm_id; @@ -244,7 +277,8 @@ static int cw1200_bh(void *arg) rx = atomic_xchg(&priv->bh_rx, 0); tx = atomic_xchg(&priv->bh_tx, 0); term = atomic_xchg(&priv->bh_term, 0); - (rx || tx || term); + suspend = atomic_read(&priv->bh_suspend); + (rx || tx || term || suspend); }), status); if (status < 0 || term) @@ -252,9 +286,35 @@ static int cw1200_bh(void *arg) if (!status) { bh_printk(KERN_DEBUG "[BH] Device wakedown.\n"); - WARN_ON(cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0)); + WARN_ON(cw1200_reg_write_16(priv, + ST90TDS_CONTROL_REG_ID, 0)); priv->device_can_sleep = true; continue; + } else if (suspend) { + bh_printk(KERN_DEBUG "[BH] Device suspend.\n"); + if (priv->powersave_enabled && + !priv->device_can_sleep) { + WARN_ON(cw1200_reg_write_16(priv, + ST90TDS_CONTROL_REG_ID, 0)); + priv->device_can_sleep = true; + } + + atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED); + wake_up_interruptible(&priv->bh_evt_wq); + status = wait_event_interruptible(priv->bh_wq, + CW1200_BH_RESUME == atomic_read( + &priv->bh_suspend)); + if (status < 0) { + wiphy_err(priv->hw->wiphy, + "%s: Failed to wait for resume: %ld.\n", + __func__, status); + break; + } + bh_printk(KERN_DEBUG "[BH] Device resume.\n"); + atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); + wake_up_interruptible(&priv->bh_evt_wq); + atomic_add(1, &priv->bh_rx); + continue; } tx += pending_tx; diff --git a/drivers/staging/cw1200/bh.h b/drivers/staging/cw1200/bh.h index 14b641fbe1d..a19393c61dd 100644 --- a/drivers/staging/cw1200/bh.h +++ b/drivers/staging/cw1200/bh.h @@ -22,6 +22,8 @@ int cw1200_register_bh(struct cw1200_common *priv); void cw1200_unregister_bh(struct cw1200_common *priv); void cw1200_irq_handler(struct cw1200_common *priv); void cw1200_bh_wakeup(struct cw1200_common *priv); +void cw1200_bh_suspend(struct cw1200_common *priv); +void cw1200_bh_resume(struct cw1200_common *priv); /* Must be called from BH thread. */ void cw1200_enable_powersave(struct cw1200_common *priv, bool enable); diff --git a/drivers/staging/cw1200/cw1200.h b/drivers/staging/cw1200/cw1200.h index 97afb8c1392..68d82874765 100644 --- a/drivers/staging/cw1200/cw1200.h +++ b/drivers/staging/cw1200/cw1200.h @@ -33,6 +33,8 @@ /* extern */ struct sbus_ops; /* extern */ struct task_struct; /* extern */ struct cw1200_debug_priv; +/* extern */ struct cw1200_suspend_state; +/* extern */ struct firmware; #if defined(CONFIG_CW1200_TXRX_DEBUG) #define txrx_printk(...) printk(__VA_ARGS__) @@ -81,6 +83,7 @@ struct cw1200_common { /* calibration, output power limit and rssi<->dBm conversation data */ /* BBP/MAC state */ + const struct firmware *sdd; struct ieee80211_rate *rates; struct ieee80211_rate *mcs_rates; u8 mac_addr[ETH_ALEN]; @@ -110,20 +113,22 @@ struct cw1200_common { struct wsm_beacon_filter_control bf_control; u8 ba_tid_mask; struct wsm_multicast_filter multicast_filter; + struct cw1200_suspend_state *suspend_state; /* BH */ atomic_t bh_rx; atomic_t bh_tx; atomic_t bh_term; + atomic_t bh_suspend; struct task_struct *bh_thread; int bh_error; wait_queue_head_t bh_wq; + wait_queue_head_t bh_evt_wq; int buf_id_tx; /* byte */ int buf_id_rx; /* byte */ int wsm_rx_seq; /* byte */ int wsm_tx_seq; /* byte */ int hw_bufs_used; - wait_queue_head_t hw_bufs_used_wq; struct sk_buff *skb_cache; bool powersave_enabled; bool device_can_sleep; @@ -194,11 +199,11 @@ struct cw1200_sta_priv { }; /* interfaces for the drivers */ -int cw1200_probe(const struct sbus_ops *sbus_ops, - struct sbus_priv *sbus, - struct device *pdev, - struct cw1200_common **pself); -void cw1200_release(struct cw1200_common *self); +int cw1200_core_probe(const struct sbus_ops *sbus_ops, + struct sbus_priv *sbus, + struct device *pdev, + struct cw1200_common **pself); +void cw1200_core_release(struct cw1200_common *self); #define CW1200_DBG_MSG 0x00000001 #define CW1200_DBG_NIY 0x00000002 diff --git a/drivers/staging/cw1200/cw1200_plat.h b/drivers/staging/cw1200/cw1200_plat.h index ed354de0edf..e79794f42a3 100644 --- a/drivers/staging/cw1200/cw1200_plat.h +++ b/drivers/staging/cw1200/cw1200_plat.h @@ -5,6 +5,9 @@ * License terms: GNU General Public License (GPL) version 2 */ +#ifndef CW1200_PLAT_H_INCLUDED +#define CW1200_PLAT_H_INCLUDED + #include struct cw1200_platform_data { @@ -17,3 +20,5 @@ struct cw1200_platform_data { /* Declaration only. Should be implemented in arch/xxx/mach-yyy */ const struct cw1200_platform_data *cw1200_get_platform_data(void); + +#endif /* CW1200_PLAT_H_INCLUDED */ diff --git a/drivers/staging/cw1200/cw1200_sdio.c b/drivers/staging/cw1200/cw1200_sdio.c index ae07267dc99..cf5c5c185be 100644 --- a/drivers/staging/cw1200/cw1200_sdio.c +++ b/drivers/staging/cw1200/cw1200_sdio.c @@ -39,7 +39,7 @@ struct sbus_priv { void *irq_priv; }; -static const struct sdio_device_id if_sdio_ids[] = { +static const struct sdio_device_id cw1200_sdio_ids[] = { { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, { /* end: all zeroes */ }, }; @@ -52,7 +52,8 @@ static int cw1200_sdio_memcpy_fromio(struct sbus_priv *self, { int ret = sdio_memcpy_fromio(self->func, dst, addr, count); if (ret) { - printk(KERN_ERR "!!! Can't read %d bytes from 0x%.8X. Err %d.\n", + printk(KERN_ERR "!!! Can't read %d bytes from 0x%.8X." + " Err %d.\n", count, addr, ret); } return ret; @@ -111,10 +112,6 @@ static int cw1200_request_irq(struct sbus_priv *self, if (WARN_ON(ret < 0)) goto exit; - ret = enable_irq_wake(irq->start); - if (WARN_ON(ret)) - goto free_irq; - /* Hack to access Fuction-0 */ func_num = self->func->num; self->func->num = 0; @@ -139,8 +136,6 @@ static int cw1200_request_irq(struct sbus_priv *self, set_func: self->func->num = func_num; - disable_irq_wake(irq->start); -free_irq: free_irq(irq->start, self); exit: return ret; @@ -191,7 +186,6 @@ static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self) ret = sdio_release_irq(self->func); sdio_release_host(self->func); #else - disable_irq_wake(irq->start); free_irq(irq->start, self); #endif @@ -283,7 +277,7 @@ static int cw1200_sdio_reset(struct sbus_priv *self) return 0; } -static size_t cw1200_align_size(struct sbus_priv *self, size_t size) +static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size) { size_t aligned = sdio_align_size(self->func, size); /* HACK!!! Problems with DMA size on u8500 platform */ @@ -295,6 +289,25 @@ static size_t cw1200_align_size(struct sbus_priv *self, size_t size) return aligned; } +static int cw1200_sdio_pm(struct sbus_priv *self, bool suspend) +{ + int ret; + const struct resource *irq = self->pdata->irq; + struct sdio_func *func = self->func; + + sdio_claim_host(func); + if (suspend) + ret = mmc_host_disable(func->card->host); + else + ret = mmc_host_enable(func->card->host); + sdio_release_host(func); + + if (!ret && irq) + ret = set_irq_wake(irq->start, suspend); + + return ret; +} + static struct sbus_ops cw1200_sdio_sbus_ops = { .sbus_memcpy_fromio = cw1200_sdio_memcpy_fromio, .sbus_memcpy_toio = cw1200_sdio_memcpy_toio, @@ -303,7 +316,8 @@ static struct sbus_ops cw1200_sdio_sbus_ops = { .irq_subscribe = cw1200_sdio_irq_subscribe, .irq_unsubscribe = cw1200_sdio_irq_unsubscribe, .reset = cw1200_sdio_reset, - .align_size = cw1200_align_size, + .align_size = cw1200_sdio_align_size, + .power_mgmt = cw1200_sdio_pm, }; /* Probe Function to be called by SDIO stack when device is discovered */ @@ -329,7 +343,7 @@ static int cw1200_sdio_probe(struct sdio_func *func, sdio_enable_func(func); sdio_release_host(func); - status = cw1200_probe(&cw1200_sdio_sbus_ops, + status = cw1200_core_probe(&cw1200_sdio_sbus_ops, self, &func->dev, &self->core); if (status) { sdio_claim_host(func); @@ -342,14 +356,15 @@ static int cw1200_sdio_probe(struct sdio_func *func, return status; } -/* Disconnect Function to be called by SDIO stack when device is disconnected */ +/* Disconnect Function to be called by SDIO stack when + * device is disconnected */ static void cw1200_sdio_disconnect(struct sdio_func *func) { struct sbus_priv *self = sdio_get_drvdata(func); if (self) { if (self->core) { - cw1200_release(self->core); + cw1200_core_release(self->core); self->core = NULL; } sdio_claim_host(func); @@ -362,7 +377,7 @@ static void cw1200_sdio_disconnect(struct sdio_func *func) static struct sdio_driver sdio_driver = { .name = "cw1200_wlan", - .id_table = if_sdio_ids, + .id_table = cw1200_sdio_ids, .probe = cw1200_sdio_probe, .remove = cw1200_sdio_disconnect, }; diff --git a/drivers/staging/cw1200/main.c b/drivers/staging/cw1200/main.c index 15dd4fd5a1b..8a621ff2b06 100644 --- a/drivers/staging/cw1200/main.c +++ b/drivers/staging/cw1200/main.c @@ -26,7 +26,6 @@ #include #include #include - #include #include "cw1200.h" @@ -39,6 +38,7 @@ #include "ap.h" #include "scan.h" #include "debug.h" +#include "pm.h" MODULE_AUTHOR("Dmitry Tarnyagin "); MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code"); @@ -220,6 +220,10 @@ static const struct ieee80211_ops cw1200_ops = { .get_stats = cw1200_get_stats, .ampdu_action = cw1200_ampdu_action, .flush = cw1200_flush, +#ifdef CONFIG_PM + .suspend = cw1200_wow_suspend, + .resume = cw1200_wow_resume, +#endif /* CONFIG_PM */ /* Intentionally not offloaded: */ /*.channel_switch = cw1200_channel_switch, */ /*.remain_on_channel = cw1200_remain_on_channel, */ @@ -412,16 +416,21 @@ void cw1200_unregister_common(struct ieee80211_hw *dev) priv->skb_cache = NULL; } + if (priv->sdd) { + release_firmware(priv->sdd); + priv->sdd = NULL; + } + for (i = 0; i < 4; ++i) cw1200_queue_deinit(&priv->tx_queue[i]); cw1200_queue_stats_deinit(&priv->tx_queue_stats); } EXPORT_SYMBOL_GPL(cw1200_unregister_common); -int cw1200_probe(const struct sbus_ops *sbus_ops, - struct sbus_priv *sbus, - struct device *pdev, - struct cw1200_common **pself) +int cw1200_core_probe(const struct sbus_ops *sbus_ops, + struct sbus_priv *sbus, + struct device *pdev, + struct cw1200_common **pself) { int err = -ENOMEM; struct ieee80211_hw *dev; @@ -489,12 +498,12 @@ err1: err: return err; } -EXPORT_SYMBOL_GPL(cw1200_probe); +EXPORT_SYMBOL_GPL(cw1200_core_probe); -void cw1200_release(struct cw1200_common *self) +void cw1200_core_release(struct cw1200_common *self) { cw1200_unregister_common(self->hw); cw1200_free_common(self->hw); return; } -EXPORT_SYMBOL_GPL(cw1200_release); +EXPORT_SYMBOL_GPL(cw1200_core_release); diff --git a/drivers/staging/cw1200/pm.c b/drivers/staging/cw1200/pm.c new file mode 100644 index 00000000000..72f11e09d50 --- /dev/null +++ b/drivers/staging/cw1200/pm.c @@ -0,0 +1,142 @@ +/* + * Mac80211 power management API for ST-Ericsson CW1200 drivers + * + * Copyright (c) 2011, ST-Ericsson + * Author: Dmitry Tarnyagin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "cw1200.h" +#include "pm.h" +#include "sta.h" +#include "bh.h" +#include "sbus.h" + +/* private */ +struct cw1200_suspend_state { + unsigned long bss_loss_tmo; + unsigned long connection_loss_tmo; + unsigned long join_tmo; +}; + +static long cw1200_suspend_work(struct delayed_work *work) +{ + int ret = cancel_delayed_work(work); + long tmo; + if (ret > 0) { + /* Timer is pending */ + tmo = work->timer.expires - jiffies; + if (tmo < 0) + tmo = 0; + } else { + tmo = -1; + } + return tmo; +} + +static int cw1200_resume_work(struct cw1200_common *priv, + struct delayed_work *work, + unsigned long tmo) +{ + if ((long)tmo < 0) + return 1; + + return queue_delayed_work(priv->workqueue, work, tmo); +} + +int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) +{ + struct cw1200_common *priv = hw->priv; + struct cw1200_suspend_state *state; + int ret; + + /* Ensure pending operations are done. */ + ret = wait_event_interruptible_timeout( + priv->channel_switch_done, + !priv->channel_switch_in_progress, 3 * HZ); + if (WARN_ON(!ret)) + return -ETIMEDOUT; + else if (WARN_ON(ret < 0)) + return ret; + + /* Flush and lock TX. */ + ret = __cw1200_flush(priv, false); + if (WARN_ON(ret < 0)) + return ret; + + /* Allocate state */ + state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL); + if (!state) { + wsm_unlock_tx(priv); + return -ENOMEM; + } + + /* Store delayed work states. */ + state->bss_loss_tmo = + cw1200_suspend_work(&priv->bss_loss_work); + state->connection_loss_tmo = + cw1200_suspend_work(&priv->connection_loss_work); + state->join_tmo = + cw1200_suspend_work(&priv->join_timeout); + + /* Flush workqueue */ + flush_workqueue(priv->workqueue); + + /* Stop serving thread */ + cw1200_bh_suspend(priv); + + /* Store suspend state */ + priv->suspend_state = state; + + /* Enable IRQ wake */ + ret = priv->sbus_ops->power_mgmt(priv->sbus_priv, true); + if (ret) { + wiphy_err(priv->hw->wiphy, + "%s: PM request failed: %d. WoW is disabled.\n", + __func__, ret); + cw1200_wow_resume(hw); + return -EBUSY; + } + + /* Force resume if event is coming from the device. */ + if (atomic_read(&priv->bh_rx)) { + cw1200_wow_resume(hw); + return -EAGAIN; + } + + return 0; +} + +int cw1200_wow_resume(struct ieee80211_hw *hw) +{ + struct cw1200_common *priv = hw->priv; + struct cw1200_suspend_state *state; + + state = priv->suspend_state; + priv->suspend_state = NULL; + + /* Disable IRQ wake */ + priv->sbus_ops->power_mgmt(priv->sbus_priv, false); + + /* Resume BH thread */ + cw1200_bh_resume(priv); + + /* Resume delayed work */ + cw1200_resume_work(priv, &priv->bss_loss_work, + state->bss_loss_tmo); + cw1200_resume_work(priv, &priv->connection_loss_work, + state->connection_loss_tmo); + cw1200_resume_work(priv, &priv->join_timeout, + state->join_tmo); + + /* Unlock datapath */ + wsm_unlock_tx(priv); + + /* Free memory */ + kfree(state); + + return 0; +} diff --git a/drivers/staging/cw1200/pm.h b/drivers/staging/cw1200/pm.h new file mode 100644 index 00000000000..841b609457f --- /dev/null +++ b/drivers/staging/cw1200/pm.h @@ -0,0 +1,23 @@ +/* + * Mac80211 power management interface for ST-Ericsson CW1200 mac80211 drivers + * + * Copyright (c) 2011, ST-Ericsson + * Author: Dmitry Tarnyagin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef PM_H_INCLUDED +#define PM_H_INCLUDED + +/* ******************************************************************** */ +/* mac80211 API */ + +#ifdef CONFIG_PM +int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); +int cw1200_wow_resume(struct ieee80211_hw *hw); +#endif /* CONFIG_PM */ + +#endif diff --git a/drivers/staging/cw1200/sbus.h b/drivers/staging/cw1200/sbus.h index c31a2f30a22..a911ef1a0e6 100644 --- a/drivers/staging/cw1200/sbus.h +++ b/drivers/staging/cw1200/sbus.h @@ -32,6 +32,7 @@ struct sbus_ops { int (*irq_unsubscribe)(struct sbus_priv *self); int (*reset)(struct sbus_priv *self); size_t (*align_size)(struct sbus_priv *self, size_t size); + int (*power_mgmt)(struct sbus_priv *self, bool suspend); }; #endif /* CW1200_SBUS_H */ diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c index 50f447fb46b..fe2cd5cc982 100644 --- a/drivers/staging/cw1200/sta.c +++ b/drivers/staging/cw1200/sta.c @@ -27,7 +27,6 @@ static int cw1200_cancel_scan(struct cw1200_common *priv); -static int __cw1200_flush(struct cw1200_common *priv, bool drop); static inline void __cw1200_free_event_queue(struct list_head *list) { @@ -652,7 +651,7 @@ int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static int __cw1200_flush(struct cw1200_common *priv, bool drop) +int __cw1200_flush(struct cw1200_common *priv, bool drop) { int i, ret; @@ -859,43 +858,42 @@ int cw1200_setup_mac(struct cw1200_common *priv) if (wsm_get_station_id(priv, &prev_mac[0]) || memcmp(prev_mac, priv->mac_addr, ETH_ALEN)) { const char *sdd_path = NULL; - const struct firmware *firmware = NULL; struct wsm_configuration cfg = { .dot11StationId = &priv->mac_addr[0], }; - switch (priv->hw_revision) { - case CW1200_HW_REV_CUT10: - sdd_path = SDD_FILE_10; - break; - case CW1200_HW_REV_CUT11: - sdd_path = SDD_FILE_11; - break; - case CW1200_HW_REV_CUT20: - sdd_path = SDD_FILE_20; - break; - case CW1200_HW_REV_CUT22: - sdd_path = SDD_FILE_22; - break; - default: - BUG_ON(1); - } + if (!priv->sdd) { + switch (priv->hw_revision) { + case CW1200_HW_REV_CUT10: + sdd_path = SDD_FILE_10; + break; + case CW1200_HW_REV_CUT11: + sdd_path = SDD_FILE_11; + break; + case CW1200_HW_REV_CUT20: + sdd_path = SDD_FILE_20; + break; + case CW1200_HW_REV_CUT22: + sdd_path = SDD_FILE_22; + break; + default: + BUG_ON(1); + } - ret = request_firmware(&firmware, - sdd_path, priv->pdev); + ret = request_firmware(&priv->sdd, + sdd_path, priv->pdev); - if (unlikely(ret)) { - cw1200_dbg(CW1200_DBG_ERROR, - "%s: can't load sdd file %s.\n", - __func__, sdd_path); - return ret; + if (unlikely(ret)) { + cw1200_dbg(CW1200_DBG_ERROR, + "%s: can't load sdd file %s.\n", + __func__, sdd_path); + return ret; + } } - cfg.dpdData = firmware->data; - cfg.dpdData_size = firmware->size; + cfg.dpdData = priv->sdd->data; + cfg.dpdData_size = priv->sdd->size; ret = WARN_ON(wsm_configuration(priv, &cfg)); - - release_firmware(firmware); } if (ret) return ret; diff --git a/drivers/staging/cw1200/sta.h b/drivers/staging/cw1200/sta.h index 8951a4a176b..8d0cc5d4c12 100644 --- a/drivers/staging/cw1200/sta.h +++ b/drivers/staging/cw1200/sta.h @@ -72,5 +72,6 @@ void cw1200_unjoin_work(struct work_struct *work); void cw1200_wep_key_work(struct work_struct *work); void cw1200_update_listening(struct cw1200_common *priv, bool enabled); void cw1200_update_filtering(struct cw1200_common *priv); +int __cw1200_flush(struct cw1200_common *priv, bool drop); #endif diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c index e8662fa6054..46280046bae 100644 --- a/drivers/staging/cw1200/wsm.c +++ b/drivers/staging/cw1200/wsm.c @@ -1060,7 +1060,7 @@ void wsm_lock_tx(struct cw1200_common *priv) { wsm_cmd_lock(priv); if (atomic_add_return(1, &priv->tx_lock) == 1) { - WARN_ON(wait_event_interruptible_timeout(priv->hw_bufs_used_wq, + WARN_ON(wait_event_interruptible_timeout(priv->bh_evt_wq, !priv->hw_bufs_used, WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0); wsm_printk(KERN_DEBUG "[WSM] TX is locked.\n"); } @@ -1076,7 +1076,7 @@ void wsm_lock_tx_async(struct cw1200_common *priv) void wsm_flush_tx(struct cw1200_common *priv) { BUG_ON(!atomic_read(&priv->tx_lock)); - WARN_ON(wait_event_interruptible_timeout(priv->hw_bufs_used_wq, + WARN_ON(wait_event_interruptible_timeout(priv->bh_evt_wq, !priv->hw_bufs_used, WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0); } -- cgit v1.2.3