From 3dded119d7f7479e563b20d89aafa0b165249e36 Mon Sep 17 00:00:00 2001 From: Amit Date: Thu, 11 Aug 2011 19:33:19 +0530 Subject: cw1200: Add changes for UAPSD * Added OID configuration for UAPSD configuration and related data structure updates * Added code to disable FastPS at FW in driver when UAPSD is enabled. * Restructured the code Change-Id: Ia64533960698646494268599c7f8f9aea57e4d88 Signed-off-by: Amit Shakya Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/29063 Reviewed-by: Dmitry TARNYAGIN Reviewed-by: Bartosz MARKOWSKI Tested-by: Bartosz MARKOWSKI Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33509 Tested-by: Dmitry TARNYAGIN Reviewed-by: Philippe LANGLAIS --- drivers/staging/cw1200/ap.c | 4 ++- drivers/staging/cw1200/cw1200.h | 2 ++ drivers/staging/cw1200/main.c | 2 +- drivers/staging/cw1200/sta.c | 76 +++++++++++++++++++++++++++++++++++++---- drivers/staging/cw1200/sta.h | 4 +++ drivers/staging/cw1200/wsm.h | 28 ++++++++++++++- 6 files changed, 107 insertions(+), 9 deletions(-) diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c index 28cb11faa35..2a6d27f212f 100755 --- a/drivers/staging/cw1200/ap.c +++ b/drivers/staging/cw1200/ap.c @@ -352,9 +352,10 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, WARN_ON(wsm_set_association_mode(priv, &priv->association_mode)); WARN_ON(wsm_set_bss_params(priv, &priv->bss_params)); + priv->setbssparams_done = true; WARN_ON(wsm_set_beacon_wakeup_period(priv, dtim_interval, listen_interval)); - WARN_ON(wsm_set_pm(priv, &priv->powersave_mode)); + cw1200_set_pm(priv, &priv->powersave_mode); #if 0 /* It's better to override internal TX rete; otherwise * device sends RTS at too high rate. However device @@ -460,6 +461,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, priv->cqm_beacon_loss_count : priv->cqm_link_loss_count; WARN_ON(wsm_set_bss_params(priv, &priv->bss_params)); + priv->setbssparams_done = true; } #endif /* CONFIG_CW1200_USE_STE_EXTENSIONS */ } diff --git a/drivers/staging/cw1200/cw1200.h b/drivers/staging/cw1200/cw1200.h index 80eb3c49f81..e4fda896b78 100644 --- a/drivers/staging/cw1200/cw1200.h +++ b/drivers/staging/cw1200/cw1200.h @@ -118,6 +118,8 @@ struct cw1200_common { struct wsm_multicast_filter multicast_filter; struct cw1200_pm_state pm_state; struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; + struct wsm_uapsd_info uapsd_info; + bool setbssparams_done; /* BH */ atomic_t bh_rx; diff --git a/drivers/staging/cw1200/main.c b/drivers/staging/cw1200/main.c index 8ba8629cb03..e9e6806e811 100644 --- a/drivers/staging/cw1200/main.c +++ b/drivers/staging/cw1200/main.c @@ -251,7 +251,7 @@ struct ieee80211_hw *cw1200_init_common(size_t priv_data_len) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - /* IEEE80211_HW_SUPPORTS_UAPSD | */ + IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | /* Aggregation is fully controlled by firmware. diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c index df9a8ead315..055d231fc01 100644 --- a/drivers/staging/cw1200/sta.c +++ b/drivers/staging/cw1200/sta.c @@ -50,14 +50,20 @@ int cw1200_start(struct ieee80211_hw *dev) mutex_lock(&priv->conf_mutex); /* default ECDA */ - WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007, 47); - WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f, 94); - WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff, 0); - WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff, 0); + WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007, 47, false); + WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f, 94, false); + WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff, 0, false); + WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff, 0, false); ret = wsm_set_edca_params(priv, &priv->edca); if (WARN_ON(ret)) goto out; + ret = cw1200_set_uapsd_param(priv, &priv->edca); + if (WARN_ON(ret)) + goto out; + + priv->setbssparams_done = false; + memset(priv->bssid, ~0, ETH_ALEN); memcpy(priv->mac_addr, dev->wiphy->perm_addr, ETH_ALEN); priv->mode = NL80211_IFTYPE_MONITOR; @@ -315,7 +321,7 @@ int cw1200_config(struct ieee80211_hw *dev, u32 changed) conf->dynamic_ps_timeout << 1; if (priv->join_status == CW1200_JOIN_STATUS_STA) - WARN_ON(wsm_set_pm(priv, &priv->powersave_mode)); + cw1200_set_pm(priv, &priv->powersave_mode); } if (changed & IEEE80211_CONF_CHANGE_P2P_PS) { @@ -505,13 +511,26 @@ int cw1200_conf_tx(struct ieee80211_hw *dev, u16 queue, { struct cw1200_common *priv = dev->priv; int ret = 0; + /* To prevent re-applying PM request OID again and again*/ + bool old_uapsdFlags; mutex_lock(&priv->conf_mutex); if (queue < dev->queues) { + old_uapsdFlags = priv->uapsd_info.uapsdFlags; + WSM_EDCA_SET(&priv->edca, queue, params->aifs, - params->cw_min, params->cw_max, params->txop); + params->cw_min, params->cw_max, params->txop, + params->uapsd); ret = wsm_set_edca_params(priv, &priv->edca); + + if (!ret && (priv->mode == NL80211_IFTYPE_STATION)) { + ret = cw1200_set_uapsd_param(priv, &priv->edca); + if (!ret && priv->setbssparams_done && + (priv->join_status == CW1200_JOIN_STATUS_STA) && + (old_uapsdFlags != priv->uapsd_info.uapsdFlags)) + cw1200_set_pm(priv, &priv->powersave_mode); + } } else ret = -EINVAL; @@ -542,6 +561,16 @@ int cw1200_get_tx_stats(struct ieee80211_hw *dev, } */ +int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) +{ + struct wsm_set_pm pm = *arg; + + if (priv->uapsd_info.uapsdFlags != 0) + pm.pmMode &= ~WSM_PSM_FAST_PS_FLAG; + + return wsm_set_pm(priv, &pm); +} + int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) @@ -1169,6 +1198,8 @@ void cw1200_unjoin_work(struct work_struct *work) cancel_delayed_work_sync(&priv->connection_loss_work); cw1200_update_listening(priv, priv->listening); cw1200_update_filtering(priv); + priv->setbssparams_done = false; + sta_printk(KERN_DEBUG "[STA] Unjoin.\n"); } mutex_unlock(&priv->conf_mutex); @@ -1222,6 +1253,39 @@ void cw1200_update_listening(struct cw1200_common *priv, bool enabled) } } +int cw1200_set_uapsd_param(struct cw1200_common *priv, + const struct wsm_edca_params *arg) +{ + int ret; + u16 uapsdFlags = 0; + + /* Here's the mapping AC [queue, bit] + VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0]*/ + + if (arg->params[0].uapsdEnable) + uapsdFlags |= 1 << 3; + + if (arg->params[1].uapsdEnable) + uapsdFlags |= 1 << 2; + + if (arg->params[2].uapsdEnable) + uapsdFlags |= 1 << 1; + + if (arg->params[3].uapsdEnable) + uapsdFlags |= 1; + + /* Currently pseudo U-APSD operation is not supported, so setting + * MinAutoTriggerInterval, MaxAutoTriggerInterval and + * AutoTriggerStep to 0 */ + + priv->uapsd_info.uapsdFlags = cpu_to_le16(uapsdFlags); + priv->uapsd_info.minAutoTriggerInterval = 0; + priv->uapsd_info.maxAutoTriggerInterval = 0; + priv->uapsd_info.autoTriggerStep = 0; + + ret = wsm_set_uapsd_info(priv, &priv->uapsd_info); + return ret; +} /* ******************************************************************** */ /* STA privates */ diff --git a/drivers/staging/cw1200/sta.h b/drivers/staging/cw1200/sta.h index 88c1cf6a34b..88a08aaceaf 100644 --- a/drivers/staging/cw1200/sta.h +++ b/drivers/staging/cw1200/sta.h @@ -45,6 +45,8 @@ void cw1200_flush(struct ieee80211_hw *hw, bool drop); u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); +int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg); + /* ******************************************************************** */ /* WSM callbacks */ @@ -76,5 +78,7 @@ void cw1200_update_filtering(struct cw1200_common *priv); int __cw1200_flush(struct cw1200_common *priv, bool drop); int cw1200_enable_listening(struct cw1200_common *priv); int cw1200_disable_listening(struct cw1200_common *priv); +int cw1200_set_uapsd_param(struct cw1200_common *priv, + const struct wsm_edca_params *arg); #endif diff --git a/drivers/staging/cw1200/wsm.h b/drivers/staging/cw1200/wsm.h index 542eededffc..30db888e535 100644 --- a/drivers/staging/cw1200/wsm.h +++ b/drivers/staging/cw1200/wsm.h @@ -135,6 +135,9 @@ struct cw1200_common; /* 802.11 PS mode */ #define WSM_PSM_PS BIT(0) +/* Fast Power Save bit */ +#define WSM_PSM_FAST_PS_FLAG BIT(7) + /* Dynamic aka Fast power save */ #define WSM_PSM_FAST_PS (BIT(0) | BIT(7)) @@ -1044,6 +1047,9 @@ struct wsm_edca_queue_params { /* the access class. Overrides the global */ /* dot11MaxReceiveLifetime value */ /* [in] */ u32 maxReceiveLifetime; + + /* UAPSD trigger support for the access class. */ + /* [in] */ bool uapsdEnable; }; struct wsm_edca_params { @@ -1051,18 +1057,22 @@ struct wsm_edca_params { struct wsm_edca_queue_params params[4]; }; -#define WSM_EDCA_SET(edca, queue, aifs, cw_min, cw_max, txop) \ +#define WSM_EDCA_SET(edca, queue, aifs, cw_min, cw_max, txop, uapsd) \ do { \ struct wsm_edca_queue_params *p = &(edca)->params[queue]; \ p->cwMin = (cw_min); \ p->cwMax = (cw_max); \ p->aifns = (aifs); \ p->txOpLimit = (txop); \ + p->uapsdEnable = (uapsd); \ } while (0) int wsm_set_edca_params(struct cw1200_common *priv, const struct wsm_edca_params *arg); +int wsm_set_uapsd_param(struct cw1200_common *priv, + const struct wsm_edca_params *arg); + /* 3.38 */ /* Set-System info. Skipped for now. Irrelevent. */ @@ -1548,6 +1558,22 @@ static inline int wsm_use_multi_tx_conf(struct cw1200_common *priv, &arg, sizeof(arg)); } + +/* 4.26 SetUpasdInformation */ +struct wsm_uapsd_info { + __le16 uapsdFlags; + __le16 minAutoTriggerInterval; + __le16 maxAutoTriggerInterval; + __le16 autoTriggerStep; +}; + +static inline int wsm_set_uapsd_info(struct cw1200_common *priv, + struct wsm_uapsd_info *arg) +{ + return wsm_write_mib(priv, WSM_MIB_ID_SET_UAPSD_INFORMATION, + arg, sizeof(*arg)); +} + /* ******************************************************************** */ /* WSM TX port control */ -- cgit v1.2.3