From 50ea05efaf3bed7dd34bcc2635a8b3f53bd0ccc1 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 30 Dec 2015 16:06:04 +0200 Subject: mac80211: pass block ack session timeout to to driver Currently mac80211 does not inform the driver of the session block ack timeout when starting a rx aggregation session. Drivers that manage the reorder buffer need to know this parameter. Seeing that there are now too many arguments for the drv_ampdu_action() function, wrap them inside a structure. Signed-off-by: Sara Sharon Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 7 ++++--- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 7 ++++--- drivers/net/wireless/ath/ath9k/main.c | 8 +++++--- drivers/net/wireless/ath/carl9170/main.c | 8 +++++--- drivers/net/wireless/ath/wcn36xx/main.c | 8 +++++--- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 8 +++++--- drivers/net/wireless/intel/iwlegacy/4965-mac.c | 8 +++++--- drivers/net/wireless/intel/iwlegacy/4965.h | 4 +--- drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 9 ++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 ++++++--- drivers/net/wireless/mac80211_hwsim.c | 8 +++++--- drivers/net/wireless/marvell/mwl8k.c | 10 ++++++---- drivers/net/wireless/mediatek/mt7601u/main.c | 8 +++++--- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 7 ++++--- drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 4 +--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/core.c | 8 +++++--- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 19 +++++++------------ drivers/net/wireless/st/cw1200/sta.c | 4 +--- drivers/net/wireless/st/cw1200/sta.h | 4 +--- drivers/net/wireless/ti/wlcore/main.c | 8 +++++--- 21 files changed, 89 insertions(+), 73 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 6146a293601a..368de5e5a04f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6366,12 +6366,13 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static int ath10k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", arvif->vdev_id, sta->addr, tid, action); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index fe1fd1a5ae15..639294a9e34d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1657,13 +1657,14 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_sta *ista; int ret = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c1b33fdcca08..cf58a304e9f0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1864,14 +1864,16 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static int ath9k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); bool flush = false; int ret = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; mutex_lock(&sc->mutex); diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 19d3d64416bf..4d1527a2e292 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1413,10 +1413,12 @@ static void carl9170_ampdu_work(struct work_struct *work) static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; struct carl9170_sta_tid *tid_info; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 7c169abdbafe..a27279c2c695 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -857,12 +857,14 @@ static int wcn36xx_resume(struct ieee80211_hw *hw) static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct wcn36xx *wcn = hw->priv; struct wcn36xx_sta *sta_priv = NULL; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index bec2dc1ca2e4..61ae2768132a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -818,13 +818,15 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int brcms_ops_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct brcms_info *wl = hw->priv; struct scb *scb = &wl->wlc->pri_scb; int status; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u8 buf_size = params->buf_size; if (WARN_ON(scb->magic != SCB_MAGIC)) return -EIDRM; diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index fd38aa0763e4..b75f4ef3cdc7 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -5982,12 +5982,14 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 * ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct il_priv *il = hw->priv; int ret = -EINVAL; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; D_HT("A-MPDU action on addr %pM tid %d\n", sta->addr, tid); diff --git a/drivers/net/wireless/intel/iwlegacy/4965.h b/drivers/net/wireless/intel/iwlegacy/4965.h index 8ab8706f9422..e432715e02d8 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965.h +++ b/drivers/net/wireless/intel/iwlegacy/4965.h @@ -182,9 +182,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 * ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 29ea1c6705b4..151721e4040c 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -732,12 +732,15 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret = -EINVAL; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 buf_size = params->buf_size; struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d70a1716f3e0..1bd3f0b700d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -837,13 +837,16 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif, static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, - u16 *ssn, u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; bool tx_agg_ref = false; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 buf_size = params->buf_size; IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", sta->addr, tid, action); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c32889a1e39c..e31a94fd6135 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1845,10 +1845,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + switch (action) { case IEEE80211_AMPDU_TX_START: ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 30e3aaae32e2..088429d0a634 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5421,11 +5421,13 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, static int mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { - + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 buf_size = params->buf_size; int i, rc = 0; struct mwl8k_priv *priv = hw->priv; struct mwl8k_ampdu_stream *stream; diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index f715eee39851..e70dd9523911 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -334,11 +334,13 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value) static int mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, - bool amsdu) + struct ieee80211_ampdu_params *params) { struct mt7601u_dev *dev = hw->priv; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; WARN_ON(msta->wcid.idx > GROUP_WCID(0)); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 9733b31a780d..69c1c09687a3 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -7935,10 +7935,11 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) EXPORT_SYMBOL_GPL(rt2800_get_tsf); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv; int ret = 0; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 440790b92b19..83f1a44fb9b4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -218,9 +218,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params); u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); int rt2800_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 6aed923a709a..7d820c395375 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5375,13 +5375,13 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static int rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, - bool amsdu) + struct ieee80211_ampdu_params *params) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; u8 ampdu_factor, ampdu_density; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; switch (action) { case IEEE80211_AMPDU_TX_START: diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 4ae421ef30d9..f2507610314b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1371,11 +1371,13 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw, static int rtl_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; switch (action) { case IEEE80211_AMPDU_TX_START: diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index b5bcc933a2a6..4df992de7d07 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -659,29 +659,24 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, * informs the f/w regarding this. * @hw: Pointer to the ieee80211_hw structure. * @vif: Pointer to the ieee80211_vif structure. - * @action: ieee80211_ampdu_mlme_action enum. - * @sta: Pointer to the ieee80211_sta structure. - * @tid: Traffic identifier. - * @ssn: Pointer to ssn value. - * @buf_size: Buffer size (for kernel version > 2.6.38). - * @amsdu: is AMSDU in AMPDU allowed + * @params: Pointer to A-MPDU action parameters * * Return: status: 0 on success, negative error code on failure. */ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - unsigned short tid, - unsigned short *ssn, - unsigned char buf_size, - bool amsdu) + struct ieee80211_ampdu_params *params) { int status = -EOPNOTSUPP; struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; u16 seq_no = 0; u8 ii = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 buf_size = params->buf_size; for (ii = 0; ii < RSI_MAX_VIFS; ii++) { if (vif == adapter->vifs[ii]) diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 06321c799c90..d0ddcde6c695 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -2129,9 +2129,7 @@ void cw1200_mcast_timeout(unsigned long arg) int cw1200_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { /* Aggregation is implemented fully in firmware, * including block ack negotiation. Do not allow diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h index bebb3379017f..a0bacaa39b31 100644 --- a/drivers/net/wireless/st/cw1200/sta.h +++ b/drivers/net/wireless/st/cw1200/sta.h @@ -109,9 +109,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, u32 changed); int cw1200_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu); + struct ieee80211_ampdu_params *params); void cw1200_suspend_resume(struct cw1200_common *priv, struct wsm_suspend_resume *arg); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d1109c4f0f0d..45662cf3169f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5187,14 +5187,16 @@ out: static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) + struct ieee80211_ampdu_params *params) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int ret; u8 hlid, *ba_bitmap; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, tid); -- cgit v1.2.3 From d742c969b3ad9c83ac57579dfd56c90dd437db37 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 13 Jan 2016 14:52:52 +0100 Subject: ath10k: prevent txrx running for too long On multicore systems it was possible for the txrx tasklet to keep on running for long periods of time on a single CPU due to tx completion processing. Another CPU could feed the running tasklet for an indefinite amount of time. The tasklet is now guaranteed to run a finite amount of time and is limited by HTT CE Rx ring depth. This improves behavior when RPS is used on target system and might improve TCP handling as well. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 91afa3ae414c..3079434b5d9b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2156,10 +2156,18 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) { struct ath10k_htt *htt = (struct ath10k_htt *)ptr; struct ath10k *ar = htt->ar; + struct sk_buff_head tx_q; struct htt_resp *resp; struct sk_buff *skb; + unsigned long flags; - while ((skb = skb_dequeue(&htt->tx_compl_q))) { + __skb_queue_head_init(&tx_q); + + spin_lock_irqsave(&htt->tx_compl_q.lock, flags); + skb_queue_splice_init(&htt->tx_compl_q, &tx_q); + spin_unlock_irqrestore(&htt->tx_compl_q.lock, flags); + + while ((skb = __skb_dequeue(&tx_q))) { ath10k_htt_rx_frm_tx_compl(htt->ar, skb); dev_kfree_skb_any(skb); } -- cgit v1.2.3 From de46c015c9b703bb8abb91856ed45e3639c7e7d2 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:28 +0530 Subject: ath10k: add support for parsing per STA rx_duration for 10.2.4 Add support for parsing 'peer_rx_duration' as part of 10.2.4 peer_stats. Also register PEER_STATS service for parsing 'rx_duration' (and for any new fields to be added as part of peer_stats). Have checks for backward compatibility with older 10.2.4 firmware incase PEER_STATS service is not enabled Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 22 ++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/wmi.h | 12 ++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 7840cf3ef7a6..d47a08568bdc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -159,6 +159,7 @@ struct ath10k_fw_stats_peer { u32 peer_rssi; u32 peer_tx_rate; u32 peer_rx_rate; /* 10x only */ + u32 rx_duration; }; struct ath10k_fw_stats_vdev { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a7c3d299639b..c610d1761940 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2862,11 +2862,20 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, /* fw doesn't implement vdev stats */ for (i = 0; i < num_peer_stats; i++) { - const struct wmi_10_2_4_peer_stats *src; + const struct wmi_10_2_4_ext_peer_stats *src; struct ath10k_fw_stats_peer *dst; + int stats_len; + bool ext_peer_stats_support; + + ext_peer_stats_support = test_bit(WMI_SERVICE_PEER_STATS, + ar->wmi.svc_map); + if (ext_peer_stats_support) + stats_len = sizeof(struct wmi_10_2_4_ext_peer_stats); + else + stats_len = sizeof(struct wmi_10_2_4_peer_stats); src = (void *)skb->data; - if (!skb_pull(skb, sizeof(*src))) + if (!skb_pull(skb, stats_len)) return -EPROTO; dst = kzalloc(sizeof(*dst), GFP_ATOMIC); @@ -2876,6 +2885,9 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, ath10k_wmi_pull_peer_stats(&src->common.old, dst); dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate); + + if (ext_peer_stats_support) + dst->rx_duration = __le32_to_cpu(src->rx_duration); /* FIXME: expose 10.2 specific values */ list_add_tail(&dst->list, &stats->peers); @@ -5517,6 +5529,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map)) features |= WMI_10_2_COEX_GPIO; + if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) + features |= WMI_10_2_PEER_STATS; + cmd->resource_config.feature_mask = __cpu_to_le32(features); memcpy(&cmd->resource_config.common, &config, sizeof(config)); @@ -7126,6 +7141,9 @@ ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer, "Peer TX rate", peer->peer_tx_rate); len += scnprintf(buf + len, buf_len - len, "%30s %u\n", "Peer RX rate", peer->peer_rx_rate); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "Peer RX duration", peer->rx_duration); + len += scnprintf(buf + len, buf_len - len, "\n"); *length = len; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index d85ad7855d20..e1bb02ba207d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -177,6 +177,7 @@ enum wmi_service { WMI_SERVICE_BSS_CHANNEL_INFO_64, WMI_SERVICE_EXT_RES_CFG_SUPPORT, WMI_SERVICE_MESH, + WMI_SERVICE_PEER_STATS, /* keep last */ WMI_SERVICE_MAX, @@ -213,6 +214,7 @@ enum wmi_10x_service { WMI_10X_SERVICE_BSS_CHANNEL_INFO_64, WMI_10X_SERVICE_MESH, WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT, + WMI_10X_SERVICE_PEER_STATS, }; enum wmi_main_service { @@ -386,6 +388,7 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64); SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT); SVCSTR(WMI_SERVICE_MESH); + SVCSTR(WMI_SERVICE_PEER_STATS); default: return NULL; } @@ -463,6 +466,8 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_MESH, len); SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT, WMI_SERVICE_EXT_RES_CFG_SUPPORT, len); + SVCMAP(WMI_10X_SERVICE_PEER_STATS, + WMI_SERVICE_PEER_STATS, len); } static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, @@ -2417,6 +2422,7 @@ enum wmi_10_2_feature_mask { WMI_10_2_RX_BATCH_MODE = BIT(0), WMI_10_2_ATF_CONFIG = BIT(1), WMI_10_2_COEX_GPIO = BIT(3), + WMI_10_2_PEER_STATS = BIT(7), }; struct wmi_resource_config_10_2 { @@ -4230,6 +4236,12 @@ struct wmi_10_2_4_peer_stats { __le32 unknown_value; /* FIXME: what is this word? */ } __packed; +struct wmi_10_2_4_ext_peer_stats { + struct wmi_10_2_peer_stats common; + __le32 peer_rssi_changed; + __le32 rx_duration; +} __packed; + struct wmi_10_4_peer_stats { struct wmi_mac_addr peer_macaddr; __le32 peer_rssi; -- cgit v1.2.3 From 774e656e94cdd8db27a8831abb3d35fbb95d2bc6 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:29 +0530 Subject: ath10k: fix naming Peer stats rssi_changed field in 10.2.4 Fix naming of peer stats rssi_changed field in 10.2.4 to make it more readable. As of now this field is not used, but necessary to pull in fw_stats with appropriate length. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e1bb02ba207d..187f495c1fbe 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4233,7 +4233,7 @@ struct wmi_10_2_peer_stats { struct wmi_10_2_4_peer_stats { struct wmi_10_2_peer_stats common; - __le32 unknown_value; /* FIXME: what is this word? */ + __le32 peer_rssi_changed; } __packed; struct wmi_10_2_4_ext_peer_stats { -- cgit v1.2.3 From 1fe374f5b07ed58e485fdbfa7410876e25ce1a78 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:30 +0530 Subject: ath10k: cleanup setting pdev paramaters Replace the local variable 'burst_enable' with 'param' for mapping and setting pdev paraemeters and with this patch pretty easy to extend support for new parameters adhering to linux kernel coding guidelines Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 6146a293601a..0d7671c778fd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3988,7 +3988,7 @@ static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; - u32 burst_enable; + u32 param; int ret = 0; /* @@ -4031,13 +4031,15 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err_power_down; } - ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); + param = ar->wmi.pdev_param->pmf_qos; + ret = ath10k_wmi_pdev_set_param(ar, param, 1); if (ret) { ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret); goto err_core_stop; } - ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); + param = ar->wmi.pdev_param->dynamic_bw; + ret = ath10k_wmi_pdev_set_param(ar, param, 1); if (ret) { ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret); goto err_core_stop; @@ -4053,8 +4055,8 @@ static int ath10k_start(struct ieee80211_hw *hw) } if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) { - burst_enable = ar->wmi.pdev_param->burst_enable; - ret = ath10k_wmi_pdev_set_param(ar, burst_enable, 0); + param = ar->wmi.pdev_param->burst_enable; + ret = ath10k_wmi_pdev_set_param(ar, param, 0); if (ret) { ath10k_warn(ar, "failed to disable burst: %d\n", ret); goto err_core_stop; @@ -4072,8 +4074,8 @@ static int ath10k_start(struct ieee80211_hw *hw) * this problem. */ - ret = ath10k_wmi_pdev_set_param(ar, - ar->wmi.pdev_param->arp_ac_override, 0); + param = ar->wmi.pdev_param->arp_ac_override; + ret = ath10k_wmi_pdev_set_param(ar, param, 0); if (ret) { ath10k_warn(ar, "failed to set arp ac override parameter: %d\n", ret); @@ -4092,8 +4094,8 @@ static int ath10k_start(struct ieee80211_hw *hw) } } - ret = ath10k_wmi_pdev_set_param(ar, - ar->wmi.pdev_param->ani_enable, 1); + param = ar->wmi.pdev_param->ani_enable; + ret = ath10k_wmi_pdev_set_param(ar, param, 1); if (ret) { ath10k_warn(ar, "failed to enable ani by default: %d\n", ret); -- cgit v1.2.3 From b4619ea2f72153df42d8ba2894b2af5e621d6df6 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:31 +0530 Subject: ath10k: rename few function names of firmware stats Prerequisite patch to address checkpatch errors for the next patch in this series, this function names are bit too long, make it short Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 2bdf5408b0d9..4fb1e0eb3408 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -276,7 +276,7 @@ static const struct file_operations fops_wmi_services = { .llseek = default_llseek, }; -static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) +static void ath10k_fw_stats_pdevs_free(struct list_head *head) { struct ath10k_fw_stats_pdev *i, *tmp; @@ -286,7 +286,7 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) } } -static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head) +static void ath10k_fw_stats_vdevs_free(struct list_head *head) { struct ath10k_fw_stats_vdev *i, *tmp; @@ -296,7 +296,7 @@ static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head) } } -static void ath10k_debug_fw_stats_peers_free(struct list_head *head) +static void ath10k_fw_stats_peers_free(struct list_head *head) { struct ath10k_fw_stats_peer *i, *tmp; @@ -310,9 +310,9 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar) { spin_lock_bh(&ar->data_lock); ar->debug.fw_stats_done = false; - ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); - ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); - ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers); + ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); + ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); + ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); spin_unlock_bh(&ar->data_lock); } @@ -391,9 +391,9 @@ free: /* In some cases lists have been spliced and cleared. Free up * resources if that is not the case. */ - ath10k_debug_fw_stats_pdevs_free(&stats.pdevs); - ath10k_debug_fw_stats_vdevs_free(&stats.vdevs); - ath10k_debug_fw_stats_peers_free(&stats.peers); + ath10k_fw_stats_pdevs_free(&stats.pdevs); + ath10k_fw_stats_vdevs_free(&stats.vdevs); + ath10k_fw_stats_peers_free(&stats.peers); spin_unlock_bh(&ar->data_lock); } -- cgit v1.2.3 From d57e7f2e7e042a7cef19702abe42f1e9b55d754c Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:32 +0530 Subject: ath10k: provision to support periodic peer stats update Enable support for periodic peer stats update when peer stats service is enabled. The host to update the peer stats received from the firmware periodically, since firmware will reset this to zero after sometime (due to memory constraints) While enabling periodic peer / vdev stats cleanup the existing list in debugfs if max limit is reached, so that the new stats is updated. Ideally speaking based on 'Michal Kazior's' suggestion we need to completely move to periodic update of all the stats making the 'ping - pong' method obselete. This requires a bit of re-work and some testing as well, also confirmation regarding backward comptability for various firmware and chipsets. Hence allow periodic update only for peer_stats. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 4fb1e0eb3408..3b8da817972b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -347,7 +347,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) * delivered which is treated as end-of-data and is itself discarded */ - if (ar->debug.fw_stats_done) { + if (ar->debug.fw_stats_done && + !test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { ath10k_warn(ar, "received unsolicited stats update event\n"); goto free; } @@ -372,11 +373,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) /* Although this is unlikely impose a sane limit to * prevent firmware from DoS-ing the host. */ + ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); ath10k_warn(ar, "dropping fw peer stats\n"); goto free; } if (num_vdevs >= BITS_PER_LONG) { + ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); ath10k_warn(ar, "dropping fw vdev stats\n"); goto free; } -- cgit v1.2.3 From 8351c052194b30f852db6225a568e48ee2a4947b Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:33 +0530 Subject: ath10k: enable periodic peer stats update Register for 500ms as periodic peer stats update period, and parameters like rx_duration that needs to be tracked in host can be achieved by this provision, also periodic stats update is the future of fw_stats and shall be extended for pdev / vdev stats irrespecitive PEER_STATS service is enabled or not Signed-off-by: Mohammed Shafi Shajakhan [kvalo@qca.qualcomm.com: fix a checkpatch warning] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0d7671c778fd..ef0438d2cc8f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4104,6 +4104,18 @@ static int ath10k_start(struct ieee80211_hw *hw) ar->ani_enabled = true; + if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { + param = ar->wmi.pdev_param->peer_stats_update_period; + ret = ath10k_wmi_pdev_set_param(ar, param, + PEER_DEFAULT_STATS_UPDATE_PERIOD); + if (ret) { + ath10k_warn(ar, + "failed to set peer stats period : %d\n", + ret); + goto err_core_stop; + } + } + ar->num_started_vdevs = 0; ath10k_regd_update(ar); -- cgit v1.2.3 From 856e7c3084399fb7e029628dbe43dcb9bb7d7b5b Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 13 Jan 2016 21:16:34 +0530 Subject: ath10k: add debugfs support for Per STA total rx duration Add debugfs support for per client total rx duration, track this via the report of Peer stats rx duration reported for every 500ms Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 9 ++++-- drivers/net/wireless/ath/ath10k/debug.h | 6 ++++ drivers/net/wireless/ath/ath10k/debugfs_sta.c | 41 +++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d47a08568bdc..921b86a4f257 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -316,6 +316,7 @@ struct ath10k_sta { #ifdef CONFIG_MAC80211_DEBUGFS /* protected by conf_mutex */ bool aggr_mode; + u64 rx_duration; #endif }; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3b8da817972b..8d4148a96af8 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -319,7 +319,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar) void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_fw_stats stats = {}; - bool is_start, is_started, is_end; + bool is_start, is_started, is_end, peer_stats_svc; size_t num_peers; size_t num_vdevs; int ret; @@ -347,8 +347,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) * delivered which is treated as end-of-data and is itself discarded */ - if (ar->debug.fw_stats_done && - !test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { + peer_stats_svc = test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map); + if (ar->debug.fw_stats_done && !peer_stats_svc) { ath10k_warn(ar, "received unsolicited stats update event\n"); goto free; } @@ -384,6 +384,9 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) goto free; } + if (peer_stats_svc) + ath10k_sta_update_rx_duration(ar, &stats.peers); + list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); } diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 814719cf4f22..f273478e2afb 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -153,6 +153,12 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) #ifdef CONFIG_MAC80211_DEBUGFS void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); +void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer); +#else +static inline void ath10k_sta_update_rx_duration(struct ath10k *ar, + struct list_head *peer) +{ +} #endif /* CONFIG_MAC80211_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 95b5c49374e0..67ef75b60567 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -18,6 +18,23 @@ #include "wmi-ops.h" #include "debug.h" +void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head) +{ struct ieee80211_sta *sta; + struct ath10k_fw_stats_peer *peer; + struct ath10k_sta *arsta; + + rcu_read_lock(); + list_for_each_entry(peer, head, list) { + sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, + NULL); + if (!sta) + continue; + arsta = (struct ath10k_sta *)sta->drv_priv; + arsta->rx_duration += (u64)peer->rx_duration; + } + rcu_read_unlock(); +} + static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -232,6 +249,28 @@ static const struct file_operations fops_delba = { .llseek = default_llseek, }; +static ssize_t ath10k_dbg_sta_read_rx_duration(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + char buf[100]; + int len = 0; + + len = scnprintf(buf, sizeof(buf), + "%llu usecs\n", arsta->rx_duration); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_rx_duration = { + .read = ath10k_dbg_sta_read_rx_duration, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { @@ -240,4 +279,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); + debugfs_create_file("rx_duration", S_IRUGO, dir, sta, + &fops_rx_duration); } -- cgit v1.2.3 From 8b019fb0d0e75e2f682f17742b99c0ca970ca024 Mon Sep 17 00:00:00 2001 From: Yanbo Li Date: Thu, 14 Jan 2016 15:39:19 -0800 Subject: ath10k: remove the p2p notice of absence info from 10.2.4 FW beacon info The p2p NOA never been supported at 10.2.4 FW, remove it to avoid SWBA event parse error for multi beacon interval case. Signed-off-by: Yanbo Li Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 46 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 10 ++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c610d1761940..0f01a8d99604 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3256,6 +3256,50 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_2_4_op_pull_swba_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_10_2_4_host_swba_event *ev = (void *)skb->data; + u32 map; + size_t i; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_map = ev->vdev_map; + + for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { + if (!(map & BIT(0))) + continue; + + /* If this happens there were some changes in firmware and + * ath10k should update the max size of tim_info array. + */ + if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) + break; + + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len; + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + i++; + } + + return 0; +} + static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_swba_ev_arg *arg) @@ -7584,7 +7628,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, - .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_swba = ath10k_wmi_10_2_4_op_pull_swba_ev, .pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr, .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 187f495c1fbe..806d4bb6e7d6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5454,6 +5454,16 @@ struct wmi_host_swba_event { struct wmi_bcn_info bcn_info[0]; } __packed; +struct wmi_10_2_4_bcn_info { + struct wmi_tim_info tim_info; + /* The 10.2.4 FW doesn't have p2p NOA info */ +} __packed; + +struct wmi_10_2_4_host_swba_event { + __le32 vdev_map; + struct wmi_10_2_4_bcn_info bcn_info[0]; +} __packed; + /* 16 words = 512 client + 1 word = for guard */ #define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17 -- cgit v1.2.3 From b9a9693fd9aea43f50b107dfc8cbaea317f95a79 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 27 Nov 2015 09:37:14 +0100 Subject: ath9k: request NOA update when chanctx active Request NOA update when chanctx active, also in case of STA. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/channel.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 50e614b915f1..0bcb82abd094 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1454,7 +1454,7 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) if (!sc->p2p_ps_timer) return; - if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) + if (vif->type != NL80211_IFTYPE_STATION) return; sc->p2p_ps_vif = avp; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c1b33fdcca08..4ae63fd4290e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -978,7 +978,7 @@ static void ath9k_update_bssid_mask(struct ath_softc *sc, if (ctx->nvifs_assigned != 1) continue; - if (!avp->vif->p2p || !iter_data->has_hw_macaddr) + if (!iter_data->has_hw_macaddr) continue; ether_addr_copy(common->curbssid, avp->bssid); @@ -1255,6 +1255,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); sc->cur_chan->nvifs++; + if (vif->type == NL80211_IFTYPE_STATION && ath9k_is_chanctx_enabled()) + vif->driver_flags |= IEEE80211_VIF_GET_NOA_UPDATE; + if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); -- cgit v1.2.3 From aea57edf80c6e96d6dc24757599396af99c02b19 Mon Sep 17 00:00:00 2001 From: Alexander Tsoy Date: Fri, 8 Jan 2016 01:26:03 +0300 Subject: ath9k_htc: add device ID for Toshiba WLM-20U2/GN-1080 This device is available under different marketing names: WLM-20U2 - Wireless USB Dongle for Toshiba TVs GN-1080 - Wireless LAN Module for Toshiba MFPs. Signed-off-by: Alexander Tsoy Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hif_usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 165dd202c365..8cbf4904db7b 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -55,6 +55,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { .driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */ { USB_DEVICE(0x04da, 0x3904), .driver_info = AR9280_USB }, + { USB_DEVICE(0x0930, 0x0a08), + .driver_info = AR9280_USB }, /* Toshiba WLM-20U2 and GN-1080 */ { USB_DEVICE(0x0cf3, 0x20ff), .driver_info = STORAGE_DEVICE }, -- cgit v1.2.3 From c5a157e4d7d7f1d39dbb382bc3ad7ea9f248ed7d Mon Sep 17 00:00:00 2001 From: Lior David Date: Sun, 17 Jan 2016 12:39:06 +0200 Subject: wil6210: fix privacy flag calculation in change_beacon Currently the privacy flag calculation in change_beacon checks for RSN IE inside proberesp_ies, but normally it is not found there. It works today because of code inside the function wil_fix_bcon, but wil_fix_bcon is not directly related to change_beacon, and it may be changed or removed in the future and break the calculation. To fix this issue, change the privacy flag calculation to check RSN IE inside the beacon itself. The new check is more reliable and will not be sensitive to changes in wil_fix_bcon. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 20d07ef679e8..182f071f722d 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -828,9 +828,9 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - if (bcon->proberesp_ies && - cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies, - bcon->proberesp_ies_len)) + if (bcon->tail && + cfg80211_find_ie(WLAN_EID_RSN, bcon->tail, + bcon->tail_len)) privacy = 1; /* in case privacy has changed, need to restart the AP */ -- cgit v1.2.3 From c100c883e785802ab333604237928a65ae62c6bc Mon Sep 17 00:00:00 2001 From: Lior David Date: Sun, 17 Jan 2016 12:39:07 +0200 Subject: wil6210: use extra IEs from probe response In the start_ap/change_beacon API, when we set up probe response offloading, we only use the IE list from the probe response template and not the IE list from the proberesp_ies argument. As a result, we miss important IEs and it causes problems with some scenarios such as P2P. With this change, we merge the list of IEs from the probe response template and proberesp_ies and send the merged list to the FW for offloading. It is still FW responsibility to filter out irrelevant IEs when sending probe response, based on the actual contents of the probe request. Also in case association response termplate is not provided, we will use the merged list of IEs from probe response in the association response as well. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 141 ++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 182f071f722d..774352f9e256 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -696,6 +696,79 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy, return rc; } +/** + * find a specific IE in a list of IEs + * return a pointer to the beginning of IE in the list + * or NULL if not found + */ +static const u8 *_wil_cfg80211_find_ie(const u8 *ies, u16 ies_len, const u8 *ie, + u16 ie_len) +{ + struct ieee80211_vendor_ie *vie; + u32 oui; + + /* IE tag at offset 0, length at offset 1 */ + if (ie_len < 2 || 2 + ie[1] > ie_len) + return NULL; + + if (ie[0] != WLAN_EID_VENDOR_SPECIFIC) + return cfg80211_find_ie(ie[0], ies, ies_len); + + /* make sure there is room for 3 bytes OUI + 1 byte OUI type */ + if (ie[1] < 4) + return NULL; + vie = (struct ieee80211_vendor_ie *)ie; + oui = vie->oui[0] << 16 | vie->oui[1] << 8 | vie->oui[2]; + return cfg80211_find_vendor_ie(oui, vie->oui_type, ies, + ies_len); +} + +/** + * merge the IEs in two lists into a single list. + * do not include IEs from the second list which exist in the first list. + * add only vendor specific IEs from second list to keep + * the merged list sorted (since vendor-specific IE has the + * highest tag number) + * caller must free the allocated memory for merged IEs + */ +static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len, + const u8 *ies2, u16 ies2_len, + u8 **merged_ies, u16 *merged_len) +{ + u8 *buf, *dpos; + const u8 *spos; + + if (ies1_len == 0 && ies2_len == 0) { + *merged_ies = NULL; + *merged_len = 0; + return 0; + } + + buf = kmalloc(ies1_len + ies2_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + memcpy(buf, ies1, ies1_len); + dpos = buf + ies1_len; + spos = ies2; + while (spos + 1 < ies2 + ies2_len) { + /* IE tag at offset 0, length at offset 1 */ + u16 ielen = 2 + spos[1]; + + if (spos + ielen > ies2 + ies2_len) + break; + if (spos[0] == WLAN_EID_VENDOR_SPECIFIC && + !_wil_cfg80211_find_ie(ies1, ies1_len, spos, ielen)) { + memcpy(dpos, spos, ielen); + dpos += ielen; + } + spos += ielen; + } + + *merged_ies = buf; + *merged_len = dpos - buf; + return 0; +} + static void wil_print_bcon_data(struct cfg80211_beacon_data *b) { print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET, @@ -712,49 +785,49 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) b->assocresp_ies, b->assocresp_ies_len); } -static int wil_fix_bcon(struct wil6210_priv *wil, - struct cfg80211_beacon_data *bcon) -{ - struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; - size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - - if (bcon->probe_resp_len <= hlen) - return 0; - -/* always use IE's from full probe frame, they has more info - * notable RSN - */ - bcon->proberesp_ies = f->u.probe_resp.variable; - bcon->proberesp_ies_len = bcon->probe_resp_len - hlen; - if (!bcon->assocresp_ies) { - bcon->assocresp_ies = bcon->proberesp_ies; - bcon->assocresp_ies_len = bcon->proberesp_ies_len; - } - - return 1; -} - /* internal functions for device reset and starting AP */ static int _wil_cfg80211_set_ies(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon) { int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + u16 len = 0, proberesp_len = 0; + u8 *ies = NULL, *proberesp = NULL; + + if (bcon->probe_resp) { + struct ieee80211_mgmt *f = + (struct ieee80211_mgmt *)bcon->probe_resp; + size_t hlen = offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + proberesp = f->u.probe_resp.variable; + proberesp_len = bcon->probe_resp_len - hlen; + } + rc = _wil_cfg80211_merge_extra_ies(proberesp, + proberesp_len, + bcon->proberesp_ies, + bcon->proberesp_ies_len, + &ies, &len); - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, - bcon->proberesp_ies); if (rc) - return rc; + goto out; - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, - bcon->assocresp_ies); + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, ies); + if (rc) + goto out; + + if (bcon->assocresp_ies) + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, + bcon->assocresp_ies_len, bcon->assocresp_ies); + else + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, len, ies); #if 0 /* to use beacon IE's, remove this #if 0 */ if (rc) - return rc; + goto out; rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail); #endif - +out: + kfree(ies); return rc; } @@ -823,11 +896,6 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); - if (wil_fix_bcon(wil, bcon)) { - wil_dbg_misc(wil, "Fixed bcon\n"); - wil_print_bcon_data(bcon); - } - if (bcon->tail && cfg80211_find_ie(WLAN_EID_RSN, bcon->tail, bcon->tail_len)) @@ -900,11 +968,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); - if (wil_fix_bcon(wil, bcon)) { - wil_dbg_misc(wil, "Fixed bcon\n"); - wil_print_bcon_data(bcon); - } - rc = _wil_cfg80211_start_ap(wiphy, ndev, info->ssid, info->ssid_len, info->privacy, info->beacon_interval, channel->hw_value, -- cgit v1.2.3 From 640751ac30b2ddfbe06ad712aa7d57a8d89a7eef Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 17 Jan 2016 12:39:08 +0200 Subject: wil6210: handle tx completions only if vring tx data is enabled wil_vring_fini_tx is called in disconnect in order to free the allocated vrings. wil_vring_fini_tx is disabling the vring_tx_data before napi_synchronize is called in order to avoid the tx handling of this vring, while wil_vring_free is called only after napi finished the current handling of the tx completed packets. Due to that, in case of disconnect, wil6210_netdev_poll_tx can be called when vring->va is not NULL but vring_tx_data[i]->enabled is already disabled. This patch checks vring_tx_data[i]->enabled in wil6210_netdev_poll_tx to prevent handling of disabled vrings. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 56aaa2d4fb0e..ecc3c1bdae4b 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -108,8 +108,9 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) /* always process ALL Tx complete, regardless budget - it is fast */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { struct vring *vring = &wil->vring_tx[i]; + struct vring_tx_data *txdata = &wil->vring_tx_data[i]; - if (!vring->va) + if (!vring->va || !txdata->enabled) continue; tx_done += wil_tx_complete(wil, i); -- cgit v1.2.3 From b729aaf066b013458e95cd6c69a5e371eb9ce355 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 17 Jan 2016 12:39:09 +0200 Subject: wil6210: find TX vring only if vring_tx_data is enabled In TX vring allocation, vring_tx->va is allocated before WMI command to configure the vring is sent to the device. As the WMI command can take time to complete, it can lead to scenarios where vring_tx->va is not NULL but vring is still not enabled. This patch adds a check that vring_tx_data is enabled before returning a valid TX vring. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 7887e6cfd817..c22ee8b3ed9b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -911,10 +911,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, continue; if (wil->vring2cid_tid[i][0] == cid) { struct vring *v = &wil->vring_tx[i]; + struct vring_tx_data *txdata = &wil->vring_tx_data[i]; wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n", __func__, eth->h_dest, i); - if (v->va) { + if (v->va && txdata->enabled) { return v; } else { wil_dbg_txrx(wil, "vring[%d] not valid\n", i); @@ -935,6 +936,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, struct vring *v; int i; u8 cid; + struct vring_tx_data *txdata; /* In the STA mode, it is expected to have only 1 VRING * for the AP we connected to. @@ -942,7 +944,8 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->vring_tx[i]; - if (!v->va) + txdata = &wil->vring_tx_data[i]; + if (!v->va || !txdata->enabled) continue; cid = wil->vring2cid_tid[i][0]; @@ -978,12 +981,14 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil, struct sk_buff *skb) { struct vring *v; + struct vring_tx_data *txdata; int i = wil->bcast_vring; if (i < 0) return NULL; v = &wil->vring_tx[i]; - if (!v->va) + txdata = &wil->vring_tx_data[i]; + if (!v->va || !txdata->enabled) return NULL; if (!wil->vring_tx_data[i].dot1x_open && (skb->protocol != cpu_to_be16(ETH_P_PAE))) @@ -1010,11 +1015,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil, u8 cid; struct ethhdr *eth = (void *)skb->data; char *src = eth->h_source; + struct vring_tx_data *txdata; /* find 1-st vring eligible for data */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->vring_tx[i]; - if (!v->va) + txdata = &wil->vring_tx_data[i]; + if (!v->va || !txdata->enabled) continue; cid = wil->vring2cid_tid[i][0]; -- cgit v1.2.3 From 0916d9f2b6bea53a830ae5061b63a515c04da62e Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 17 Jan 2016 12:39:10 +0200 Subject: wil6210: handle multiple connect/disconnect events In the current solution wil6210 configures the vring in a worker and holds only one pending CID. This implementation may lead to race conditions between connect and disconnect events of multiple stations or fast connect/disconnect events of the same station. In order to allow the removal of the connect worker and handling of WMI_VRING_CFG_DONE_EVENTID in the connect event, the WMI replies that provide the reply in a given buffer needs to be handled immediately in the WMI event interrupt thread. To prevent deadlocks, WMI replies that requires additional handling are still handled via the events list. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 81 +++++++-------- drivers/net/wireless/ath/wil6210/txrx.c | 3 + drivers/net/wireless/ath/wil6210/wil6210.h | 8 +- drivers/net/wireless/ath/wil6210/wmi.c | 157 +++++++++++++++++++++-------- 4 files changed, 156 insertions(+), 93 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index b39f0bfc591e..0652efed6b5d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -155,7 +155,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) if (sta->status != wil_sta_unused) { if (!from_event) - wmi_disconnect_sta(wil, sta->addr, reason_code); + wmi_disconnect_sta(wil, sta->addr, reason_code, true); switch (wdev->iftype) { case NL80211_IFTYPE_AP: @@ -195,8 +195,8 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, struct wireless_dev *wdev = wil->wdev; might_sleep(); - wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid, - reason_code, from_event ? "+" : "-"); + wil_info(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid, + reason_code, from_event ? "+" : "-"); /* Cases are: * - disconnect single STA, still connected @@ -258,13 +258,16 @@ static void wil_disconnect_worker(struct work_struct *work) static void wil_connect_timer_fn(ulong x) { struct wil6210_priv *wil = (void *)x; + bool q; - wil_dbg_misc(wil, "Connect timeout\n"); + wil_err(wil, "Connect timeout detected, disconnect station\n"); /* reschedule to thread context - disconnect won't - * run from atomic context + * run from atomic context. + * queue on wmi_wq to prevent race with connect event. */ - schedule_work(&wil->disconnect_worker); + q = queue_work(wil->wmi_wq, &wil->disconnect_worker); + wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q); } static void wil_scan_timer_fn(ulong x) @@ -369,6 +372,32 @@ static int wil_find_free_vring(struct wil6210_priv *wil) return -EINVAL; } +int wil_tx_init(struct wil6210_priv *wil, int cid) +{ + int rc = -EINVAL, ringid; + + if (cid < 0) { + wil_err(wil, "No connection pending\n"); + goto out; + } + ringid = wil_find_free_vring(wil); + if (ringid < 0) { + wil_err(wil, "No free vring found\n"); + goto out; + } + + wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n", + cid, ringid); + + rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0); + if (rc) + wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n", + cid, ringid); + +out: + return rc; +} + int wil_bcast_init(struct wil6210_priv *wil) { int ri = wil->bcast_vring, rc; @@ -399,41 +428,6 @@ void wil_bcast_fini(struct wil6210_priv *wil) wil_vring_fini_tx(wil, ri); } -static void wil_connect_worker(struct work_struct *work) -{ - int rc, cid, ringid; - struct wil6210_priv *wil = container_of(work, struct wil6210_priv, - connect_worker); - struct net_device *ndev = wil_to_ndev(wil); - - mutex_lock(&wil->mutex); - - cid = wil->pending_connect_cid; - if (cid < 0) { - wil_err(wil, "No connection pending\n"); - goto out; - } - ringid = wil_find_free_vring(wil); - if (ringid < 0) { - wil_err(wil, "No free vring found\n"); - goto out; - } - - wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n", - cid, ringid); - - rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0); - wil->pending_connect_cid = -1; - if (rc == 0) { - wil->sta[cid].status = wil_sta_connected; - netif_tx_wake_all_queues(ndev); - } else { - wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true); - } -out: - mutex_unlock(&wil->mutex); -} - int wil_priv_init(struct wil6210_priv *wil) { uint i; @@ -453,12 +447,10 @@ int wil_priv_init(struct wil6210_priv *wil) init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); - wil->pending_connect_cid = -1; wil->bcast_vring = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); - INIT_WORK(&wil->connect_worker, wil_connect_worker); INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); @@ -844,7 +836,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) } /* init after reset */ - wil->pending_connect_cid = -1; wil->ap_isolate = 0; reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index c22ee8b3ed9b..9680b970b863 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -794,6 +794,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, txdata->dot1x_open = false; txdata->enabled = 0; wil_vring_free(wil, vring, 1); + wil->vring2cid_tid[id][0] = WIL6210_MAX_CID; + wil->vring2cid_tid[id][1] = 0; + out: return rc; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 235e205ce2bc..1b8fa1d2bae9 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -581,12 +581,10 @@ struct wil6210_priv { struct workqueue_struct *wmi_wq; /* for deferred calls */ struct work_struct wmi_event_worker; struct workqueue_struct *wq_service; - struct work_struct connect_worker; struct work_struct disconnect_worker; struct work_struct fw_error_worker; /* for FW error recovery */ struct timer_list connect_timer; struct timer_list scan_timer; /* detect scan timeout */ - int pending_connect_cid; struct list_head pending_wmi_ev; /* * protect pending_wmi_ev @@ -756,7 +754,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); -int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason, + bool full_disconnect); int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout); int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason); int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason); @@ -807,6 +806,7 @@ void wil_rx_fini(struct wil6210_priv *wil); int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, int cid, int tid); void wil_vring_fini_tx(struct wil6210_priv *wil, int id); +int wil_tx_init(struct wil6210_priv *wil, int cid); int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size); int wil_bcast_init(struct wil6210_priv *wil); void wil_bcast_fini(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index e3ea74cdd4aa..e1a6cb8840ed 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -426,6 +426,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) const size_t assoc_req_ie_offset = sizeof(u16) * 2; /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */ const size_t assoc_resp_ie_offset = sizeof(u16) * 3; + int rc; if (len < sizeof(*evt)) { wil_err(wil, "Connect event too short : %d bytes\n", len); @@ -445,8 +446,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) } ch = evt->channel + 1; - wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", - evt->bssid, ch, evt->cid); + wil_info(wil, "Connect %pM channel [%d] cid %d\n", + evt->bssid, ch, evt->cid); wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, evt->assoc_info, len - sizeof(*evt), true); @@ -468,20 +469,67 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) assoc_resp_ielen = 0; } + mutex_lock(&wil->mutex); + if (test_bit(wil_status_resetting, wil->status) || + !test_bit(wil_status_fwready, wil->status)) { + wil_err(wil, "status_resetting, cancel connect event, CID %d\n", + evt->cid); + mutex_unlock(&wil->mutex); + /* no need for cleanup, wil_reset will do that */ + return; + } + if ((wdev->iftype == NL80211_IFTYPE_STATION) || (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { if (!test_bit(wil_status_fwconnecting, wil->status)) { wil_err(wil, "Not in connecting state\n"); + mutex_unlock(&wil->mutex); return; } del_timer_sync(&wil->connect_timer); - cfg80211_connect_result(ndev, evt->bssid, - assoc_req_ie, assoc_req_ielen, - assoc_resp_ie, assoc_resp_ielen, - WLAN_STATUS_SUCCESS, GFP_KERNEL); + } + + /* FIXME FW can transmit only ucast frames to peer */ + /* FIXME real ring_id instead of hard coded 0 */ + ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid); + wil->sta[evt->cid].status = wil_sta_conn_pending; + rc = wil_tx_init(wil, evt->cid); + if (rc) { + wil_err(wil, "%s: config tx vring failed for CID %d, rc (%d)\n", + __func__, evt->cid, rc); + wmi_disconnect_sta(wil, wil->sta[evt->cid].addr, + WLAN_REASON_UNSPECIFIED, false); + } else { + wil_info(wil, "%s: successful connection to CID %d\n", + __func__, evt->cid); + } + + if ((wdev->iftype == NL80211_IFTYPE_STATION) || + (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { + if (rc) { + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + wil_err(wil, + "%s: cfg80211_connect_result with failure\n", + __func__); + cfg80211_connect_result(ndev, evt->bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + goto out; + } else { + cfg80211_connect_result(ndev, evt->bssid, + assoc_req_ie, assoc_req_ielen, + assoc_resp_ie, assoc_resp_ielen, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + } } else if ((wdev->iftype == NL80211_IFTYPE_AP) || (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { + if (rc) + goto out; + memset(&sinfo, 0, sizeof(sinfo)); sinfo.generation = wil->sinfo_gen++; @@ -492,17 +540,21 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) } cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); + } else { + wil_err(wil, "%s: unhandled iftype %d for CID %d\n", + __func__, wdev->iftype, evt->cid); + goto out; } - clear_bit(wil_status_fwconnecting, wil->status); - set_bit(wil_status_fwconnected, wil->status); - /* FIXME FW can transmit only ucast frames to peer */ - /* FIXME real ring_id instead of hard coded 0 */ - ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid); - wil->sta[evt->cid].status = wil_sta_conn_pending; + wil->sta[evt->cid].status = wil_sta_connected; + set_bit(wil_status_fwconnected, wil->status); + netif_tx_wake_all_queues(ndev); - wil->pending_connect_cid = evt->cid; - queue_work(wil->wq_service, &wil->connect_worker); +out: + if (rc) + wil->sta[evt->cid].status = wil_sta_unused; + clear_bit(wil_status_fwconnecting, wil->status); + mutex_unlock(&wil->mutex); } static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, @@ -511,8 +563,8 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, struct wmi_disconnect_event *evt = d; u16 reason_code = le16_to_cpu(evt->protocol_reason_status); - wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", - evt->bssid, reason_code, evt->disconnect_reason); + wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n", + evt->bssid, reason_code, evt->disconnect_reason); wil->sinfo_gen++; @@ -727,6 +779,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) void __iomem *src; ulong flags; unsigned n; + unsigned int num_immed_reply = 0; if (!test_bit(wil_status_mbox_ready, wil->status)) { wil_err(wil, "Reset in progress. Cannot handle WMI event\n"); @@ -736,6 +789,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) for (n = 0;; n++) { u16 len; bool q; + bool immed_reply = false; r->head = wil_r(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, rx.head)); @@ -784,6 +838,13 @@ void wmi_recv_cmd(struct wil6210_priv *wil) struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->id); u32 tstamp = le32_to_cpu(wmi->timestamp); + if (wil->reply_id && wil->reply_id == id) { + if (wil->reply_buf) { + memcpy(wil->reply_buf, wmi, + min(len, wil->reply_size)); + immed_reply = true; + } + } wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n", id, wmi->mid, tstamp); @@ -799,15 +860,24 @@ void wmi_recv_cmd(struct wil6210_priv *wil) wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail); - /* add to the pending list */ - spin_lock_irqsave(&wil->wmi_ev_lock, flags); - list_add_tail(&evt->list, &wil->pending_wmi_ev); - spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); - q = queue_work(wil->wmi_wq, &wil->wmi_event_worker); - wil_dbg_wmi(wil, "queue_work -> %d\n", q); + if (immed_reply) { + wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n", + __func__, wil->reply_id); + kfree(evt); + num_immed_reply++; + complete(&wil->wmi_call); + } else { + /* add to the pending list */ + spin_lock_irqsave(&wil->wmi_ev_lock, flags); + list_add_tail(&evt->list, &wil->pending_wmi_ev); + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); + q = queue_work(wil->wmi_wq, &wil->wmi_event_worker); + wil_dbg_wmi(wil, "queue_work -> %d\n", q); + } } /* normally, 1 event per IRQ should be processed */ - wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n); + wil_dbg_wmi(wil, "%s -> %d events queued, %d completed\n", __func__, + n - num_immed_reply, num_immed_reply); } int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, @@ -1184,7 +1254,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) return 0; } -int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason, + bool full_disconnect) { int rc; u16 reason_code; @@ -1208,19 +1279,20 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) return rc; } - /* call event handler manually after processing wmi_call, - * to avoid deadlock - disconnect event handler acquires wil->mutex - * while it is already held here - */ - reason_code = le16_to_cpu(reply.evt.protocol_reason_status); - - wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", - reply.evt.bssid, reason_code, - reply.evt.disconnect_reason); + if (full_disconnect) { + /* call event handler manually after processing wmi_call, + * to avoid deadlock - disconnect event handler acquires + * wil->mutex while it is already held here + */ + reason_code = le16_to_cpu(reply.evt.protocol_reason_status); - wil->sinfo_gen++; - wil6210_disconnect(wil, reply.evt.bssid, reason_code, true); + wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", + reply.evt.bssid, reason_code, + reply.evt.disconnect_reason); + wil->sinfo_gen++; + wil6210_disconnect(wil, reply.evt.bssid, reason_code, true); + } return 0; } @@ -1348,14 +1420,11 @@ static void wmi_event_handle(struct wil6210_priv *wil, id, wil->reply_id); /* check if someone waits for this event */ if (wil->reply_id && wil->reply_id == id) { - if (wil->reply_buf) { - memcpy(wil->reply_buf, wmi, - min(len, wil->reply_size)); - } else { - wmi_evt_call_handler(wil, id, evt_data, - len - sizeof(*wmi)); - } - wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id); + WARN_ON(wil->reply_buf); + wmi_evt_call_handler(wil, id, evt_data, + len - sizeof(*wmi)); + wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n", + __func__, id); complete(&wil->wmi_call); return; } -- cgit v1.2.3 From 424aecaa797901708e7f260b642d27b077cdb491 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 14 Jan 2016 03:15:13 +0100 Subject: ath9k_hw: add low power tx gain table for AR953x Used in some newer TP-Link AR9533 devices. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 3 ++ drivers/net/wireless/ath/ath9k/ar953x_initvals.h | 65 ++++++++++++++++++++++++ 2 files changed, 68 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 8b238c15916d..2fe12b0de5b4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_low_ob_db_tx_gain_table_1p0); + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_no_xpa_low_power_tx_gain_table); else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_low_ob_db_tx_gain_1_1); diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 6fc0d07e5ec6..c0b90daa3e3d 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = { {0x00016448, 0x6c927a70}, }; +static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfff55592}, + {0x0000a2e0, 0xfff99924}, + {0x0000a2e4, 0xfffe1e00}, + {0x0000a2e8, 0xffffe000}, + {0x0000a410, 0x000050d6}, + {0x0000a500, 0x00000069}, + {0x0000a504, 0x0400006b}, + {0x0000a508, 0x0800006d}, + {0x0000a50c, 0x0c000269}, + {0x0000a510, 0x1000026b}, + {0x0000a514, 0x1400026d}, + {0x0000a518, 0x18000669}, + {0x0000a51c, 0x1c00066b}, + {0x0000a520, 0x1d000a68}, + {0x0000a524, 0x21000a6a}, + {0x0000a528, 0x25000a6c}, + {0x0000a52c, 0x29000a6e}, + {0x0000a530, 0x2d0012a9}, + {0x0000a534, 0x310012ab}, + {0x0000a538, 0x350012ad}, + {0x0000a53c, 0x39001b0a}, + {0x0000a540, 0x3d001b0c}, + {0x0000a544, 0x41001b0e}, + {0x0000a548, 0x43001bae}, + {0x0000a54c, 0x45001914}, + {0x0000a550, 0x47001916}, + {0x0000a554, 0x49001b96}, + {0x0000a558, 0x49001b96}, + {0x0000a55c, 0x49001b96}, + {0x0000a560, 0x49001b96}, + {0x0000a564, 0x49001b96}, + {0x0000a568, 0x49001b96}, + {0x0000a56c, 0x49001b96}, + {0x0000a570, 0x49001b96}, + {0x0000a574, 0x49001b96}, + {0x0000a578, 0x49001b96}, + {0x0000a57c, 0x49001b96}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00000000}, + {0x0000a610, 0x00000000}, + {0x0000a614, 0x00000000}, + {0x0000a618, 0x00804201}, + {0x0000a61c, 0x01408201}, + {0x0000a620, 0x01408502}, + {0x0000a624, 0x01408502}, + {0x0000a628, 0x01408502}, + {0x0000a62c, 0x01408502}, + {0x0000a630, 0x01408502}, + {0x0000a634, 0x01408502}, + {0x0000a638, 0x01408502}, + {0x0000a63c, 0x01408502}, + {0x0000b2dc, 0xfff55592}, + {0x0000b2e0, 0xfff99924}, + {0x0000b2e4, 0xfffe1e00}, + {0x0000b2e8, 0xffffe000}, + {0x00016044, 0x044922db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x044922db}, + {0x00016448, 0x6c927a70}, +}; + static const u32 qca953x_2p0_baseband_core[][2] = { /* Addr allmodes */ {0x00009800, 0xafe68e30}, -- cgit v1.2.3 From 344cd850b55e9dfd4f3ec1ba564f8edbc8136aca Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Jan 2016 14:41:30 +0100 Subject: ath9k: Drop useless const on chanctx_event_delta() return type drivers/net/wireless/ath/ath9k/channel.c:230: warning: type qualifiers ignored on function return type Signed-off-by: Geert Uytterhoeven Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 0bcb82abd094..319cb5f25f58 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -226,7 +226,7 @@ static const char *chanctx_state_string(enum ath_chanctx_state state) } } -static const u32 chanctx_event_delta(struct ath_softc *sc) +static u32 chanctx_event_delta(struct ath_softc *sc) { u64 ms; struct timespec ts, *old; -- cgit v1.2.3 From c1cab1df9b651d999922e0f04d01dc046121a237 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Mon, 18 Jan 2016 09:33:46 +0800 Subject: ath9k: avoid ANI restart if no trigger Fixes commit 54da20d83f0e ("ath9k_hw: improve ANI processing and rx desensitizing parameters") Call ath9k_ani_restart() only when the phy error rate reach the ANI immunity threshold. Sync the logic with internal code base. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ani.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 25e45e4d1a60..aa82e1326fff 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -450,7 +450,9 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) } else if (cckPhyErrRate > ah->config.cck_trig_high) { ath9k_hw_ani_cck_err_trigger(ah); aniState->ofdmsTurn = true; - } + } else + return; + ath9k_ani_restart(ah); } } -- cgit v1.2.3 From 66b533d5adb3eb0cd111b07e516ab13a47ed34f5 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Mon, 18 Jan 2016 09:33:47 +0800 Subject: ath9k: clean up ANI per-channel pointer checking commit c24bd3620c50 ("ath9k: Do not maintain ANI state per-channel") removed per-channel handling, the code to check 'curchan' also should be removed as never used. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ani.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index aa82e1326fff..815efe9fd208 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah, static void ath9k_ani_restart(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - if (!ah->curchan) - return; + struct ar5416AniState *aniState = &ah->ani; - aniState = &ah->ani; aniState->listenTime = 0; ENABLE_REGWRITE_BUFFER(ah); @@ -221,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - if (!ah->curchan) - return; - - aniState = &ah->ani; + struct ar5416AniState *aniState = &ah->ani; if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); @@ -281,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - if (!ah->curchan) - return; - - aniState = &ah->ani; + struct ar5416AniState *aniState = &ah->ani; if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, @@ -299,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) */ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - aniState = &ah->ani; + struct ar5416AniState *aniState = &ah->ani; /* lower OFDM noise immunity */ if (aniState->ofdmNoiseImmunityLevel > 0 && @@ -329,7 +313,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) struct ath_common *common = ath9k_hw_common(ah); int ofdm_nil, cck_nil; - if (!ah->curchan) + if (!chan) return; BUG_ON(aniState == NULL); @@ -416,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar5416AniState *aniState; + struct ar5416AniState *aniState = &ah->ani; struct ath_common *common = ath9k_hw_common(ah); u32 ofdmPhyErrRate, cckPhyErrRate; - if (!ah->curchan) - return; - - aniState = &ah->ani; if (!ath9k_hw_ani_read_counters(ah)) return; -- cgit v1.2.3 From 3f6cc4e57d304f552abc2bdba716519c5e18b442 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Mon, 18 Jan 2016 09:33:48 +0800 Subject: ath9k: do not reset while BB panic(0x4000409) on ar9561 BB panic(0x4000409) observed while AP enabling/disabling bursting. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 201425e7f9cb..abd964691d8c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -2071,7 +2071,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) * to be disabled. * * 0x04000409: Packet stuck on receive. - * Full chip reset is required for all chips except AR9340. + * Full chip reset is required for all chips except + * AR9340, AR9531 and AR9561. */ /* @@ -2100,7 +2101,7 @@ bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah) case 0x04000b09: return true; case 0x04000409: - if (AR_SREV_9340(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) return false; else return true; -- cgit v1.2.3 From 1542bc37842d5d51e4aa71286a08be9615eba884 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Mon, 18 Jan 2016 09:33:49 +0800 Subject: ath9k: fix inconsistent use of tab and space in indentation Minor changes for indenting. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 8b4561e8ce1a..54ed2f72d35e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah, AR9300_PAPRD_SCALE_1); else { if (chan->channel >= 5700) - return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20), - AR9300_PAPRD_SCALE_1); + return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20), + AR9300_PAPRD_SCALE_1); else if (chan->channel >= 5400) return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40), - AR9300_PAPRD_SCALE_2); + AR9300_PAPRD_SCALE_2); else return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40), AR9300_PAPRD_SCALE_1); -- cgit v1.2.3 From 466b0f0208508b08eb59907fac0958d6da7fa3e2 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Mon, 18 Jan 2016 09:33:50 +0800 Subject: ath9k: fix data bus error on ar9300 and ar9580 One crash issue be found on ar9300: RTC_RC reg read leads crash, leading the data bus error, due to RTC_RC reg write not happen properly. Warm Reset trigger in continuous beacon stuck for one of the customer for other chip, noticed the MAC was stuck in RTC reset. After analysis noticed DMA did not complete when RTC was put in reset. So, before resetting the MAC need to make sure there are no pending DMA transactions because this reset does not reset all parts of the chip. The 12th and 11th bit of MAC _DMA_CFG register used to do that. 12 cfg_halt_ack 0x0 0 DMA has not yet halted 1 DMA has halted 11 cfg_halt_req 0x0 0 DMA logic operates normally 1 Request DMA logic to stop so software can reset the MAC The Bit [12] of this register indicates when the halt has taken effect or not. the DMA halt IS NOT recoverable; once software sets bit [11] to request a DMA halt, software must wait for bit [12] to be set and reset the MAC. So, the same thing we implemented for ar9580 chip. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 10 ++++++++++ drivers/net/wireless/ath/ath9k/reg.h | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 257f46ed4a04..e7a31016f370 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_check_gpm_offset(ah); + /* DMA HALT added to resolve ar9300 and ar9580 bus error during + * RTC_RC reg read + */ + if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { + REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, + 20 * AH_WAIT_TIMEOUT); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + } + REG_WRITE(ah, AR_RTC_RC, rst_flags); REGWRITE_BUFFER_FLUSH(ah); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index caba54ddad25..c8d35febaf0f 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -34,8 +34,10 @@ #define AR_CFG_SWRG 0x00000010 #define AR_CFG_AP_ADHOC_INDICATION 0x00000020 #define AR_CFG_PHOK 0x00000100 -#define AR_CFG_CLK_GATE_DIS 0x00000400 #define AR_CFG_EEBS 0x00000200 +#define AR_CFG_CLK_GATE_DIS 0x00000400 +#define AR_CFG_HALT_REQ 0x00000800 +#define AR_CFG_HALT_ACK 0x00001000 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 -- cgit v1.2.3 From df94e702277e14889af5eef5fbfc3a33261c8b33 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 21 Jan 2016 14:13:23 +0100 Subject: ath10k: rename some HTT events New names make a bit more sense. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.c | 8 ++++---- drivers/net/wireless/ath/ath10k/htt.h | 8 ++++---- drivers/net/wireless/ath/ath10k/htt_rx.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 3e6ba63dfdff..7561f22f10f9 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -131,12 +131,12 @@ static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = { [HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF, [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] = HTT_T2H_MSG_TYPE_TX_FETCH_IND, - [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] = - HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM] = + HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM, [HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] = HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, - [HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] = - HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] = + HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND, }; int ath10k_htt_connect(struct ath10k_htt *htt) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 47ca048feaf0..edd3b9070de9 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -413,10 +413,10 @@ enum htt_10_4_t2h_msg_type { HTT_10_4_T2H_MSG_TYPE_EN_STATS = 0x14, HTT_10_4_T2H_MSG_TYPE_AGGR_CONF = 0x15, HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND = 0x16, - HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF = 0x17, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM = 0x17, HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18, /* 0x19 to 0x2f are reserved */ - HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND = 0x30, + HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND = 0x30, /* keep this last */ HTT_10_4_T2H_NUM_MSGS }; @@ -449,8 +449,8 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_TEST, HTT_T2H_MSG_TYPE_EN_STATS, HTT_T2H_MSG_TYPE_TX_FETCH_IND, - HTT_T2H_MSG_TYPE_TX_FETCH_CONF, - HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, + HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM, + HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND, /* keep this last */ HTT_T2H_NUM_MSGS }; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 3079434b5d9b..84abe4f25c73 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2125,8 +2125,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_EN_STATS: case HTT_T2H_MSG_TYPE_TX_FETCH_IND: - case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: - case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND: + case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM: + case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND: default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); -- cgit v1.2.3 From 22e6b3bc5d9668dc711665d255efad89c527b4d6 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 21 Jan 2016 14:13:24 +0100 Subject: ath10k: add new htt definitions These definitions are associated with some improvements upcomming for 10.4 and QCA99X0. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 153 +++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index edd3b9070de9..0c5628dafabf 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -52,6 +52,7 @@ enum htt_h2t_msg_type { /* host-to-target */ /* This command is used for sending management frames in HTT < 3.0. * HTT >= 3.0 uses TX_FRM for everything. */ HTT_H2T_MSG_TYPE_MGMT_TX = 7, + HTT_H2T_MSG_TYPE_TX_FETCH_RESP = 11, HTT_H2T_NUM_MSGS /* keep this last */ }; @@ -1306,9 +1307,43 @@ struct htt_frag_desc_bank_id { * so we use a conservatively safe value for now */ #define HTT_FRAG_DESC_BANK_MAX 4 -#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK 0x03 -#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_LSB 0 -#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP (1 << 2) +#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK 0x03 +#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_LSB 0 +#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP BIT(2) +#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID BIT(3) +#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE_MASK BIT(4) +#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE_LSB 4 + +enum htt_q_depth_type { + HTT_Q_DEPTH_TYPE_BYTES = 0, + HTT_Q_DEPTH_TYPE_MSDUS = 1, +}; + +#define HTT_TX_Q_STATE_NUM_PEERS (TARGET_10_4_NUM_QCACHE_PEERS_MAX + \ + TARGET_10_4_NUM_VDEVS) +#define HTT_TX_Q_STATE_NUM_TIDS 8 +#define HTT_TX_Q_STATE_ENTRY_SIZE 1 +#define HTT_TX_Q_STATE_ENTRY_MULTIPLIER 0 + +/** + * htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config + * + * Defines host q state format and behavior. See htt_q_state. + * + * @record_size: Defines the size of each host q entry in bytes. In practice + * however firmware (at least 10.4.3-00191) ignores this host + * configuration value and uses hardcoded value of 1. + * @record_multiplier: This is valid only when q depth type is MSDUs. It + * defines the exponent for the power of 2 multiplication. + */ +struct htt_q_state_conf { + __le32 paddr; + __le16 num_peers; + __le16 num_tids; + u8 record_size; + u8 record_multiplier; + u8 pad[2]; +} __packed; struct htt_frag_desc_bank_cfg { u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */ @@ -1316,6 +1351,114 @@ struct htt_frag_desc_bank_cfg { u8 desc_size; __le32 bank_base_addrs[HTT_FRAG_DESC_BANK_MAX]; struct htt_frag_desc_bank_id bank_id[HTT_FRAG_DESC_BANK_MAX]; + struct htt_q_state_conf q_state; +} __packed; + +#define HTT_TX_Q_STATE_ENTRY_COEFFICIENT 128 +#define HTT_TX_Q_STATE_ENTRY_FACTOR_MASK 0x3f +#define HTT_TX_Q_STATE_ENTRY_FACTOR_LSB 0 +#define HTT_TX_Q_STATE_ENTRY_EXP_MASK 0xc0 +#define HTT_TX_Q_STATE_ENTRY_EXP_LSB 6 + +/** + * htt_q_state - shared between host and firmware via DMA + * + * This structure is used for the host to expose it's software queue state to + * firmware so that its rate control can schedule fetch requests for optimized + * performance. This is most notably used for MU-MIMO aggregation when multiple + * MU clients are connected. + * + * @count: Each element defines the host queue depth. When q depth type was + * configured as HTT_Q_DEPTH_TYPE_BYTES then each entry is defined as: + * FACTOR * 128 * 8^EXP (see HTT_TX_Q_STATE_ENTRY_FACTOR_MASK and + * HTT_TX_Q_STATE_ENTRY_EXP_MASK). When q depth type was configured as + * HTT_Q_DEPTH_TYPE_MSDUS the number of packets is scaled by 2 ** + * record_multiplier (see htt_q_state_conf). + * @map: Used by firmware to quickly check which host queues are not empty. It + * is a bitmap simply saying. + * @seq: Used by firmware to quickly check if the host queues were updated + * since it last checked. + * + * FIXME: Is the q_state map[] size calculation really correct? + */ +struct htt_q_state { + u8 count[HTT_TX_Q_STATE_NUM_TIDS][HTT_TX_Q_STATE_NUM_PEERS]; + u32 map[HTT_TX_Q_STATE_NUM_TIDS][(HTT_TX_Q_STATE_NUM_PEERS + 31) / 32]; + __le32 seq; +} __packed; + +#define HTT_TX_FETCH_RECORD_INFO_PEER_ID_MASK 0x0fff +#define HTT_TX_FETCH_RECORD_INFO_PEER_ID_LSB 0 +#define HTT_TX_FETCH_RECORD_INFO_TID_MASK 0xf000 +#define HTT_TX_FETCH_RECORD_INFO_TID_LSB 12 + +struct htt_tx_fetch_record { + __le16 info; /* HTT_TX_FETCH_IND_RECORD_INFO_ */ + __le16 num_msdus; + __le32 num_bytes; +} __packed; + +struct htt_tx_fetch_ind { + u8 pad0; + __le16 fetch_seq_num; + __le32 token; + __le16 num_resp_ids; + __le16 num_records; + struct htt_tx_fetch_record records[0]; + __le32 resp_ids[0]; /* ath10k_htt_get_tx_fetch_ind_resp_ids() */ +} __packed; + +static inline void * +ath10k_htt_get_tx_fetch_ind_resp_ids(struct htt_tx_fetch_ind *ind) +{ + return (void *)&ind->records[le16_to_cpu(ind->num_records)]; +} + +struct htt_tx_fetch_resp { + u8 pad0; + __le16 resp_id; + __le16 fetch_seq_num; + __le16 num_records; + __le32 token; + struct htt_tx_fetch_record records[0]; +} __packed; + +struct htt_tx_fetch_confirm { + u8 pad0; + __le16 num_resp_ids; + __le32 resp_ids[0]; +} __packed; + +enum htt_tx_mode_switch_mode { + HTT_TX_MODE_SWITCH_PUSH = 0, + HTT_TX_MODE_SWITCH_PUSH_PULL = 1, +}; + +#define HTT_TX_MODE_SWITCH_IND_INFO0_ENABLE BIT(0) +#define HTT_TX_MODE_SWITCH_IND_INFO0_NUM_RECORDS_MASK 0xfffe +#define HTT_TX_MODE_SWITCH_IND_INFO0_NUM_RECORDS_LSB 1 + +#define HTT_TX_MODE_SWITCH_IND_INFO1_MODE_MASK 0x0003 +#define HTT_TX_MODE_SWITCH_IND_INFO1_MODE_LSB 0 +#define HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD_MASK 0xfffc +#define HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD_LSB 2 + +#define HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID_MASK 0x0fff +#define HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID_LSB 0 +#define HTT_TX_MODE_SWITCH_RECORD_INFO0_TID_MASK 0xf000 +#define HTT_TX_MODE_SWITCH_RECORD_INFO0_TID_LSB 12 + +struct htt_tx_mode_switch_record { + __le16 info0; /* HTT_TX_MODE_SWITCH_RECORD_INFO0_ */ + __le16 num_max_msdus; +} __packed; + +struct htt_tx_mode_switch_ind { + u8 pad0; + __le16 info0; /* HTT_TX_MODE_SWITCH_IND_INFO0_ */ + __le16 info1; /* HTT_TX_MODE_SWITCH_IND_INFO1_ */ + u8 pad1[2]; + struct htt_tx_mode_switch_record records[0]; } __packed; union htt_rx_pn_t { @@ -1340,6 +1483,7 @@ struct htt_cmd { struct htt_oob_sync_req oob_sync_req; struct htt_aggr_conf aggr_conf; struct htt_frag_desc_bank_cfg frag_desc_bank_cfg; + struct htt_tx_fetch_resp tx_fetch_resp; }; } __packed; @@ -1364,6 +1508,9 @@ struct htt_resp { struct htt_rx_pn_ind rx_pn_ind; struct htt_rx_offload_ind rx_offload_ind; struct htt_rx_in_ord_ind rx_in_ord_ind; + struct htt_tx_fetch_ind tx_fetch_ind; + struct htt_tx_fetch_confirm tx_fetch_confirm; + struct htt_tx_mode_switch_ind tx_mode_switch_ind; }; } __packed; -- cgit v1.2.3 From 9b783763aa9623dedeed77bec158f7377cb87750 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 21 Jan 2016 14:13:25 +0100 Subject: ath10k: add new FW_FEATURE_PEER_FLOW_CONTROL This feature flag will be used for firmware which supports pull-push model where host shares it's software queue state with firmware and firmware generates fetch requests telling host which queues to dequeue tx from. Primary function of this is improved MU-MIMO performance with multiple clients. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index b41eb3f4ee56..48a26206c5c1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -217,6 +217,7 @@ static const char *const ath10k_core_fw_feature_str[] = { [ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode", [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca", [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp", + [ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 921b86a4f257..5067a0ff4e89 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -512,6 +512,15 @@ enum ath10k_fw_features { /* Firmware supports management frame protection */ ATH10K_FW_FEATURE_MFP_SUPPORT = 12, + /* Firmware supports pull-push model where host shares it's software + * queue state with firmware and firmware generates fetch requests + * telling host which queues to dequeue tx from. + * + * Primary function of this is improved MU-MIMO performance with + * multiple clients. + */ + ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; -- cgit v1.2.3 From 575fc89500d37839eb24ecd258982b24edefed6f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 21 Jan 2016 14:13:26 +0100 Subject: ath10k: clean up cont frag desc init code This makes the code easier to extend and re-use. While at it fix _warn to _err. Other than that there are no functional changes. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 58 ++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index b3adadb5f824..28b8d7af8506 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -97,6 +97,41 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) idr_remove(&htt->pending_tx, msdu_id); } +static void ath10k_htt_tx_free_cont_frag_desc(struct ath10k_htt *htt) +{ + size_t size; + + if (!htt->frag_desc.vaddr) + return; + + size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); + + dma_free_coherent(htt->ar->dev, + size, + htt->frag_desc.vaddr, + htt->frag_desc.paddr); +} + +static int ath10k_htt_tx_alloc_cont_frag_desc(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + size_t size; + + if (!ar->hw_params.continuous_frag_desc) + return 0; + + size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); + htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, + &htt->frag_desc.paddr, + GFP_KERNEL); + if (!htt->frag_desc.vaddr) { + ath10k_err(ar, "failed to alloc fragment desc memory\n"); + return -ENOMEM; + } + + return 0; +} + int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; @@ -118,20 +153,12 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) goto free_idr_pending_tx; } - if (!ar->hw_params.continuous_frag_desc) - goto skip_frag_desc_alloc; - - size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); - htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, - &htt->frag_desc.paddr, - GFP_KERNEL); - if (!htt->frag_desc.vaddr) { - ath10k_warn(ar, "failed to alloc fragment desc memory\n"); - ret = -ENOMEM; + ret = ath10k_htt_tx_alloc_cont_frag_desc(htt); + if (ret) { + ath10k_err(ar, "failed to alloc cont frag desc: %d\n", ret); goto free_txbuf; } -skip_frag_desc_alloc: return 0; free_txbuf: @@ -139,8 +166,10 @@ free_txbuf: sizeof(struct ath10k_htt_txbuf); dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr, htt->txbuf.paddr); + free_idr_pending_tx: idr_destroy(&htt->pending_tx); + return ret; } @@ -174,12 +203,7 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt) htt->txbuf.paddr); } - if (htt->frag_desc.vaddr) { - size = htt->max_num_pending_tx * - sizeof(struct htt_msdu_ext_desc); - dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr, - htt->frag_desc.paddr); - } + ath10k_htt_tx_free_cont_frag_desc(htt); } void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) -- cgit v1.2.3 From 9b15873628050fe59ebbfae200be7d50ce5e1491 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 21 Jan 2016 14:13:27 +0100 Subject: ath10k: implement basic support for new tx path firmware This allows to use the new firmware which implements the new tx data path. Without this patch firmware supporting new tx path stops responding shortly after booting. This patch doesn't implement the entire pull-push logic available in the new firmware. This will be done in subsequent patches. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 8 +++ drivers/net/wireless/ath/ath10k/htt_rx.c | 4 +- drivers/net/wireless/ath/ath10k/htt_tx.c | 88 +++++++++++++++++++++++++++++--- 3 files changed, 91 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 0c5628dafabf..13391ea4422d 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1665,6 +1665,14 @@ struct ath10k_htt { dma_addr_t paddr; struct ath10k_htt_txbuf *vaddr; } txbuf; + + struct { + struct htt_q_state *vaddr; + dma_addr_t paddr; + u16 num_peers; + u16 num_tids; + enum htt_q_depth_type type; + } tx_q_state; }; #define RX_HTT_HDR_STATUS_LEN 64 diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 84abe4f25c73..cc957a625605 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2123,10 +2123,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_AGGR_CONF: break; - case HTT_T2H_MSG_TYPE_EN_STATS: case HTT_T2H_MSG_TYPE_TX_FETCH_IND: case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM: case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND: + /* TODO: Implement pull-push logic */ + break; + case HTT_T2H_MSG_TYPE_EN_STATS: default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 28b8d7af8506..95acb727c068 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -132,6 +132,50 @@ static int ath10k_htt_tx_alloc_cont_frag_desc(struct ath10k_htt *htt) return 0; } +static void ath10k_htt_tx_free_txq(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + size_t size; + + if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features)) + return; + + size = sizeof(*htt->tx_q_state.vaddr); + + dma_unmap_single(ar->dev, htt->tx_q_state.paddr, size, DMA_TO_DEVICE); + kfree(htt->tx_q_state.vaddr); +} + +static int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + size_t size; + int ret; + + if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features)) + return 0; + + htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS; + htt->tx_q_state.num_tids = HTT_TX_Q_STATE_NUM_TIDS; + htt->tx_q_state.type = HTT_Q_DEPTH_TYPE_BYTES; + + size = sizeof(*htt->tx_q_state.vaddr); + htt->tx_q_state.vaddr = kzalloc(size, GFP_KERNEL); + if (!htt->tx_q_state.vaddr) + return -ENOMEM; + + htt->tx_q_state.paddr = dma_map_single(ar->dev, htt->tx_q_state.vaddr, + size, DMA_TO_DEVICE); + ret = dma_mapping_error(ar->dev, htt->tx_q_state.paddr); + if (ret) { + ath10k_warn(ar, "failed to dma map tx_q_state: %d\n", ret); + kfree(htt->tx_q_state.vaddr); + return -EIO; + } + + return 0; +} + int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; @@ -159,8 +203,17 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) goto free_txbuf; } + ret = ath10k_htt_tx_alloc_txq(htt); + if (ret) { + ath10k_err(ar, "failed to alloc txq: %d\n", ret); + goto free_frag_desc; + } + return 0; +free_frag_desc: + ath10k_htt_tx_free_cont_frag_desc(htt); + free_txbuf: size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf); @@ -203,6 +256,7 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt) htt->txbuf.paddr); } + ath10k_htt_tx_free_txq(htt); ath10k_htt_tx_free_cont_frag_desc(htt); } @@ -292,7 +346,9 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) struct ath10k *ar = htt->ar; struct sk_buff *skb; struct htt_cmd *cmd; + struct htt_frag_desc_bank_cfg *cfg; int ret, size; + u8 info; if (!ar->hw_params.continuous_frag_desc) return 0; @@ -310,14 +366,30 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) skb_put(skb, size); cmd = (struct htt_cmd *)skb->data; cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; - cmd->frag_desc_bank_cfg.info = 0; - cmd->frag_desc_bank_cfg.num_banks = 1; - cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); - cmd->frag_desc_bank_cfg.bank_base_addrs[0] = - __cpu_to_le32(htt->frag_desc.paddr); - cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0; - cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = - __cpu_to_le16(htt->max_num_pending_tx - 1); + + info = 0; + info |= SM(htt->tx_q_state.type, + HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE); + + if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features)) + info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID; + + cfg = &cmd->frag_desc_bank_cfg; + cfg->info = info; + cfg->num_banks = 1; + cfg->desc_size = sizeof(struct htt_msdu_ext_desc); + cfg->bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr); + cfg->bank_id[0].bank_min_id = 0; + cfg->bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx - + 1); + + cfg->q_state.paddr = cpu_to_le32(htt->tx_q_state.paddr); + cfg->q_state.num_peers = cpu_to_le16(htt->tx_q_state.num_peers); + cfg->q_state.num_tids = cpu_to_le16(htt->tx_q_state.num_tids); + cfg->q_state.record_size = HTT_TX_Q_STATE_ENTRY_SIZE; + cfg->q_state.record_multiplier = HTT_TX_Q_STATE_ENTRY_MULTIPLIER; + + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt frag desc bank cmd\n"); ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); if (ret) { -- cgit v1.2.3 From f52f517189dea69614bbee9ec5ab2fe366905b16 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:22 +0530 Subject: ath10k: make some of ath10k_pci_* func reusable Some of static functions present in pci.c file are reusable in ahb (qca4019) case. Remove static word for those reusable functions and have those function prototype declaration in pci.h file. So that, pci.h header file can be included in ahb module and reused. There is no functionality changes done in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 63 +++++++++++++++++------------------ drivers/net/wireless/ath/ath10k/pci.h | 32 ++++++++++++++++++ 2 files changed, 63 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ee925c618535..956e548fd4a7 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -94,7 +94,6 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); static int ath10k_pci_safe_chip_reset(struct ath10k *ar); -static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); static int ath10k_pci_request_irq(struct ath10k *ar); @@ -687,7 +686,7 @@ void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val); } -static bool ath10k_pci_irq_pending(struct ath10k *ar) +bool ath10k_pci_irq_pending(struct ath10k *ar) { u32 cause; @@ -700,7 +699,7 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar) return false; } -static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) +void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) { /* IMPORTANT: INTR_CLR register has to be set after * INTR_ENABLE is set to 0, otherwise interrupt can not be @@ -716,7 +715,7 @@ static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) PCIE_INTR_ENABLE_ADDRESS); } -static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) +void ath10k_pci_enable_legacy_irq(struct ath10k *ar) { ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, @@ -809,7 +808,7 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) } } -static void ath10k_pci_rx_post(struct ath10k *ar) +void ath10k_pci_rx_post(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int i; @@ -818,7 +817,7 @@ static void ath10k_pci_rx_post(struct ath10k *ar) ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]); } -static void ath10k_pci_rx_replenish_retry(unsigned long ptr) +void ath10k_pci_rx_replenish_retry(unsigned long ptr) { struct ath10k *ar = (void *)ptr; @@ -1007,8 +1006,8 @@ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest, #define ath10k_pci_diag_read_hi(ar, dest, src, len) \ __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len) -static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, - const void *data, int nbytes) +int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, + const void *data, int nbytes) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret = 0; @@ -1263,8 +1262,8 @@ static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state) ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver); } -static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, - struct ath10k_hif_sg_item *items, int n_items) +int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id]; @@ -1332,13 +1331,13 @@ err: return err; } -static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf, - size_t buf_len) +int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len) { return ath10k_pci_diag_read_mem(ar, address, buf, buf_len); } -static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) +u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -1406,8 +1405,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) queue_work(ar->workqueue, &ar->restart_work); } -static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, - int force) +void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, + int force) { ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n"); @@ -1432,7 +1431,7 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, ath10k_ce_per_engine_service(ar, pipe); } -static void ath10k_pci_kill_tasklet(struct ath10k *ar) +void ath10k_pci_kill_tasklet(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int i; @@ -1446,8 +1445,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) del_timer_sync(&ar_pci->rx_post_retry); } -static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, - u8 *ul_pipe, u8 *dl_pipe) +int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) { const struct service_to_pipe *entry; bool ul_set = false, dl_set = false; @@ -1491,8 +1490,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, return 0; } -static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, - u8 *ul_pipe, u8 *dl_pipe) +void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) { ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n"); @@ -1668,7 +1667,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar) } } -static void ath10k_pci_ce_deinit(struct ath10k *ar) +void ath10k_pci_ce_deinit(struct ath10k *ar) { int i; @@ -1676,7 +1675,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) ath10k_ce_deinit_pipe(ar, i); } -static void ath10k_pci_flush(struct ath10k *ar) +void ath10k_pci_flush(struct ath10k *ar) { ath10k_pci_kill_tasklet(ar); ath10k_pci_buffer_cleanup(ar); @@ -1711,9 +1710,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) spin_unlock_irqrestore(&ar_pci->ps_lock, flags); } -static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, - void *req, u32 req_len, - void *resp, u32 *resp_len) +int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, + void *req, u32 req_len, + void *resp, u32 *resp_len) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; @@ -1907,7 +1906,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) return 1; } -static int ath10k_pci_init_config(struct ath10k *ar) +int ath10k_pci_init_config(struct ath10k *ar) { u32 interconnect_targ_addr; u32 pcie_state_targ_addr = 0; @@ -2071,7 +2070,7 @@ static void ath10k_pci_override_ce_config(struct ath10k *ar) target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1); } -static int ath10k_pci_alloc_pipes(struct ath10k *ar) +int ath10k_pci_alloc_pipes(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pipe; @@ -2102,7 +2101,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar) return 0; } -static void ath10k_pci_free_pipes(struct ath10k *ar) +void ath10k_pci_free_pipes(struct ath10k *ar) { int i; @@ -2110,7 +2109,7 @@ static void ath10k_pci_free_pipes(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } -static int ath10k_pci_init_pipes(struct ath10k *ar) +int ath10k_pci_init_pipes(struct ath10k *ar) { int i, ret; @@ -2453,7 +2452,7 @@ err_sleep: return ret; } -static void ath10k_pci_hif_power_down(struct ath10k *ar) +void ath10k_pci_hif_power_down(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); @@ -2722,7 +2721,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar) free_irq(ar_pci->pdev->irq + i, ar); } -static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) +void ath10k_pci_init_irq_tasklets(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int i; @@ -2808,7 +2807,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) return 0; } -static int ath10k_pci_wait_for_target_init(struct ath10k *ar) +int ath10k_pci_wait_for_target_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); unsigned long timeout; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index f91bf333cb75..ae76131aa081 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -253,6 +253,38 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset); u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr); u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr); +int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items); +int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len); +int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, + const void *data, int nbytes); +int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, void *req, u32 req_len, + void *resp, u32 *resp_len); +int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, + u8 *ul_pipe, u8 *dl_pipe); +void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, u8 *ul_pipe, + u8 *dl_pipe); +void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, + int force); +u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe); +void ath10k_pci_hif_power_down(struct ath10k *ar); +int ath10k_pci_alloc_pipes(struct ath10k *ar); +void ath10k_pci_free_pipes(struct ath10k *ar); +void ath10k_pci_free_pipes(struct ath10k *ar); +void ath10k_pci_rx_replenish_retry(unsigned long ptr); +void ath10k_pci_ce_deinit(struct ath10k *ar); +void ath10k_pci_init_irq_tasklets(struct ath10k *ar); +void ath10k_pci_kill_tasklet(struct ath10k *ar); +int ath10k_pci_init_pipes(struct ath10k *ar); +int ath10k_pci_init_config(struct ath10k *ar); +void ath10k_pci_rx_post(struct ath10k *ar); +void ath10k_pci_flush(struct ath10k *ar); +void ath10k_pci_enable_legacy_irq(struct ath10k *ar); +bool ath10k_pci_irq_pending(struct ath10k *ar); +void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar); +int ath10k_pci_wait_for_target_init(struct ath10k *ar); + /* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too * frequently. To avoid this put SoC to sleep after a very conservative grace * period. Adjust with great care. -- cgit v1.2.3 From 4ddb3299aa49ddeb40680d7427d3259d32aefa6d Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:23 +0530 Subject: ath10k: make ath10k_pci_read32/write32() ops more generic ath10k_pci_read32/write32() does work more specific to PCI by ensuring pci wake/sleep for every read and write. There is a plan to use most of stuff available in pci.c (irq stuff, copy engine, etc) for AHB case. Such kind of pci wake/sleep for every read/write is not required in AHB case (qca4019). All those reusable areas in pci.c and ce.c calls ath10k_pci_read32/write32() for low level read and write. In fact, ath10k_pci_read32/write32() should do what it does today for PCI case. But for AHB, it has to do differently. To make ath10k_pci_read32/write32() more generic, new function pointers are added in ar_pci for the function which does operation more close to the bus. Later, corresponding bus specific read and write function will be mapped to that. ath10k_pci_read32/write32() are changed to call directly those function pointers without worrying which bus underlying to it. Also, the function to get number of bank is changed in the same way. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 34 +++++++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/pci.h | 8 ++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 956e548fd4a7..c5f6604fa76d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -619,7 +619,7 @@ static void ath10k_pci_sleep_sync(struct ath10k *ar) spin_unlock_irqrestore(&ar_pci->ps_lock, flags); } -void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) +static void ath10k_bus_pci_write32(struct ath10k *ar, u32 offset, u32 value) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; @@ -641,7 +641,7 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) ath10k_pci_sleep(ar); } -u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) +static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); u32 val; @@ -666,6 +666,20 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) return val; } +inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + ar_pci->bus_ops->write32(ar, offset, value); +} + +inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + return ar_pci->bus_ops->read32(ar, offset); +} + u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr) { return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr); @@ -1906,6 +1920,13 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) return 1; } +static int ath10k_bus_get_num_banks(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + return ar_pci->bus_ops->get_num_banks(ar); +} + int ath10k_pci_init_config(struct ath10k *ar) { u32 interconnect_targ_addr; @@ -2017,7 +2038,7 @@ int ath10k_pci_init_config(struct ath10k *ar) /* first bank is switched to IRAM */ ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & HI_EARLY_ALLOC_MAGIC_MASK); - ealloc_value |= ((ath10k_pci_get_num_banks(ar) << + ealloc_value |= ((ath10k_bus_get_num_banks(ar) << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & HI_EARLY_ALLOC_IRAM_BANKS_MASK); @@ -2988,6 +3009,12 @@ static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) return false; } +static const struct ath10k_bus_ops ath10k_pci_bus_ops = { + .read32 = ath10k_bus_pci_read32, + .write32 = ath10k_bus_pci_write32, + .get_num_banks = ath10k_pci_get_num_banks, +}; + static int ath10k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { @@ -3038,6 +3065,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->ar = ar; ar->dev_id = pci_dev->device; ar_pci->pci_ps = pci_ps; + ar_pci->bus_ops = &ath10k_pci_bus_ops; ar->id.vendor = pdev->vendor; ar->id.device = pdev->device; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index ae76131aa081..41f3faced84c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -157,6 +157,12 @@ struct ath10k_pci_supp_chip { u32 rev_id; }; +struct ath10k_bus_ops { + u32 (*read32)(struct ath10k *ar, u32 offset); + void (*write32)(struct ath10k *ar, u32 offset, u32 value); + int (*get_num_banks)(struct ath10k *ar); +}; + struct ath10k_pci { struct pci_dev *pdev; struct device *dev; @@ -225,6 +231,8 @@ struct ath10k_pci { * on MMIO read/write. */ bool pci_ps; + + const struct ath10k_bus_ops *bus_ops; }; static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) -- cgit v1.2.3 From 90188f807f2a8bada8e165b932b56f7e03b0a9b9 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:24 +0530 Subject: ath10k: pull reusable code from pci probe and remove for ahb Some of the code present in ath10k_pci_{probe|remove} are reusable in ahb case too. To avoid code duplication, move reusable code to new functions. Later, those new functions can be called from ahb module's probe and exit functions. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 64 +++++++++++++++++++++++------------ drivers/net/wireless/ath/ath10k/pci.h | 2 ++ 2 files changed, 44 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c5f6604fa76d..6ef878c1eebc 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3009,6 +3009,37 @@ static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) return false; } +int ath10k_pci_setup_resource(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ret; + + spin_lock_init(&ar_pci->ce_lock); + spin_lock_init(&ar_pci->ps_lock); + + setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, + (unsigned long)ar); + + if (QCA_REV_6174(ar)) + ath10k_pci_override_ce_config(ar); + + ret = ath10k_pci_alloc_pipes(ar); + if (ret) { + ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", + ret); + return ret; + } + + return 0; +} + +void ath10k_pci_release_resource(struct ath10k *ar) +{ + ath10k_pci_kill_tasklet(ar); + ath10k_pci_ce_deinit(ar); + ath10k_pci_free_pipes(ar); +} + static const struct ath10k_bus_ops ath10k_pci_bus_ops = { .read32 = ath10k_bus_pci_read32, .write32 = ath10k_bus_pci_write32, @@ -3072,34 +3103,25 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar->id.subsystem_vendor = pdev->subsystem_vendor; ar->id.subsystem_device = pdev->subsystem_device; - spin_lock_init(&ar_pci->ce_lock); - spin_lock_init(&ar_pci->ps_lock); - - setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, - (unsigned long)ar); setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer, (unsigned long)ar); - ret = ath10k_pci_claim(ar); + ret = ath10k_pci_setup_resource(ar); if (ret) { - ath10k_err(ar, "failed to claim device: %d\n", ret); + ath10k_err(ar, "failed to setup resource: %d\n", ret); goto err_core_destroy; } - if (QCA_REV_6174(ar)) - ath10k_pci_override_ce_config(ar); - - ret = ath10k_pci_alloc_pipes(ar); + ret = ath10k_pci_claim(ar); if (ret) { - ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", - ret); - goto err_sleep; + ath10k_err(ar, "failed to claim device: %d\n", ret); + goto err_free_pipes; } ret = ath10k_pci_force_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake up device : %d\n", ret); - goto err_free_pipes; + goto err_sleep; } ath10k_pci_ce_deinit(ar); @@ -3108,7 +3130,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ret = ath10k_pci_init_irq(ar); if (ret) { ath10k_err(ar, "failed to init irqs: %d\n", ret); - goto err_free_pipes; + goto err_sleep; } ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n", @@ -3154,13 +3176,13 @@ err_free_irq: err_deinit_irq: ath10k_pci_deinit_irq(ar); -err_free_pipes: - ath10k_pci_free_pipes(ar); - err_sleep: ath10k_pci_sleep_sync(ar); ath10k_pci_release(ar); +err_free_pipes: + ath10k_pci_free_pipes(ar); + err_core_destroy: ath10k_core_destroy(ar); @@ -3184,10 +3206,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev) ath10k_core_unregister(ar); ath10k_pci_free_irq(ar); - ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); - ath10k_pci_ce_deinit(ar); - ath10k_pci_free_pipes(ar); + ath10k_pci_release_resource(ar); ath10k_pci_sleep_sync(ar); ath10k_pci_release(ar); ath10k_core_destroy(ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 41f3faced84c..fcfdbca8e55e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -292,6 +292,8 @@ void ath10k_pci_enable_legacy_irq(struct ath10k *ar); bool ath10k_pci_irq_pending(struct ath10k *ar); void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar); int ath10k_pci_wait_for_target_init(struct ath10k *ar); +int ath10k_pci_setup_resource(struct ath10k *ar); +void ath10k_pci_release_resource(struct ath10k *ar); /* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too * frequently. To avoid this put SoC to sleep after a very conservative grace -- cgit v1.2.3 From 0b523ced9a3cd05abf240e913b2d80e7d0fa3478 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:25 +0530 Subject: ath10k: add basic skeleton to support ahb qca4019 uses ahb instead of pci where it slightly differs in device enumeration, clock control, reset control, etc. Good thing is that ahb also uses copy engine for the data transaction. So, the most of the stuff implemented in pci.c/ce.c are reusable in ahb case too. Device enumeration in ahb case comes through platform driver/device model. All resource details like irq, memory map, clocks, etc for qca4019 can be fetched from of_node of platform device. Simply flow would look like, device tree => platform device (kernel) => platform driver (ath10k) Device tree entry will have all qca4019 resource details and the same info will be passed to kernel. Kernel will prepare new platform device for that entry and expose DT info to of_node in platform device. Later, ath10k would register platform driver with unique compatible name and then kernels binds to corresponding compatible entry & calls ath10k ahb probe functions. From there onwards, ath10k will take control of it and move forward. New bool flag CONFIG_ATH10K_AHB is added in Kconfig to conditionally enable ahb support in ath10k. On enabling this flag, ath10k_pci.ko will have ahb support. This patch adds only basic skeleton and few macros to support ahb in the context of qca4019. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 6 +++ drivers/net/wireless/ath/ath10k/Makefile | 2 + drivers/net/wireless/ath/ath10k/ahb.c | 67 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 41 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 3 ++ drivers/net/wireless/ath/ath10k/debug.h | 1 + drivers/net/wireless/ath/ath10k/hw.h | 2 + drivers/net/wireless/ath/ath10k/pci.c | 8 ++++ drivers/net/wireless/ath/ath10k/pci.h | 1 + 9 files changed, 131 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/ahb.c create mode 100644 drivers/net/wireless/ath/ath10k/ahb.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 03aa35f999a1..d7f207a6b0e0 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -15,6 +15,12 @@ config ATH10K_PCI ---help--- This module adds support for PCIE bus +config ATH10K_AHB + bool "Atheros ath10k AHB support" + depends on ATH10K_PCI && OF + ---help--- + This module adds support for AHB bus + config ATH10K_DEBUG bool "Atheros ath10k debugging" depends on ATH10K diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index c04fb00e7930..930fadd940d8 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -25,5 +25,7 @@ obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o ath10k_pci-y += pci.o \ ce.o +ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c new file mode 100644 index 000000000000..129f4f4491d0 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved. + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include "core.h" +#include "debug.h" +#include "ahb.h" + +static const struct of_device_id ath10k_ahb_of_match[] = { + /* TODO: enable this entry once everything in place. + * { .compatible = "qcom,ipq4019-wifi", + * .data = (void *)ATH10K_HW_QCA4019 }, + */ + { } +}; + +MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match); + +static int ath10k_ahb_probe(struct platform_device *pdev) +{ + return 0; +} + +static int ath10k_ahb_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver ath10k_ahb_driver = { + .driver = { + .name = "ath10k_ahb", + .of_match_table = ath10k_ahb_of_match, + }, + .probe = ath10k_ahb_probe, + .remove = ath10k_ahb_remove, +}; + +int ath10k_ahb_init(void) +{ + int ret; + + printk(KERN_ERR "AHB support is still work in progress\n"); + + ret = platform_driver_register(&ath10k_ahb_driver); + if (ret) + printk(KERN_ERR "failed to register ath10k ahb driver: %d\n", + ret); + return ret; +} + +void ath10k_ahb_exit(void) +{ + platform_driver_unregister(&ath10k_ahb_driver); +} diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h new file mode 100644 index 000000000000..d1afe93f9329 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved. + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _AHB_H_ +#define _AHB_H_ + +#include + +#ifdef CONFIG_ATH10K_AHB + +int ath10k_ahb_init(void); +void ath10k_ahb_exit(void); + +#else /* CONFIG_ATH10K_AHB */ + +static inline int ath10k_ahb_init(void) +{ + return 0; +} + +static inline void ath10k_ahb_exit(void) +{ +} + +#endif /* CONFIG_ATH10K_AHB */ + +#endif /* _AHB_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5067a0ff4e89..2e411b5258c2 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -69,6 +69,7 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, + ATH10K_BUS_AHB, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -76,6 +77,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) switch (bus) { case ATH10K_BUS_PCI: return "pci"; + case ATH10K_BUS_AHB: + return "ahb"; } return "unknown"; diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index f273478e2afb..6206edd7c49f 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -37,6 +37,7 @@ enum ath10k_debug_mask { ATH10K_DBG_TESTMODE = 0x00001000, ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_PCI_PS = 0x00004000, + ATH10K_DBG_AHB = 0x00008000, ATH10K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 0678831e8671..f8850155140a 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -200,6 +200,7 @@ enum ath10k_hw_rev { ATH10K_HW_QCA6174, ATH10K_HW_QCA99X0, ATH10K_HW_QCA9377, + ATH10K_HW_QCA4019, }; struct ath10k_hw_regs { @@ -253,6 +254,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) #define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377) +#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019) /* Known pecularities: * - raw appears in nwifi decap, raw and nwifi appear in ethernet decap diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 6ef878c1eebc..0e338b657210 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -851,6 +851,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) 0x7ff) << 21; break; case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA4019: val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); break; } @@ -1529,6 +1530,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) CORE_CTRL_ADDRESS, val); break; case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA4019: /* TODO: Find appropriate register configuration for QCA99X0 * to mask irq/MSI. */ @@ -1551,6 +1553,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) CORE_CTRL_ADDRESS, val); break; case ATH10K_HW_QCA99X0: + case ATH10K_HW_QCA4019: /* TODO: Find appropriate register configuration for QCA99X0 * to unmask irq/MSI. */ @@ -3231,6 +3234,10 @@ static int __init ath10k_pci_init(void) printk(KERN_ERR "failed to register ath10k pci driver: %d\n", ret); + ret = ath10k_ahb_init(); + if (ret) + printk(KERN_ERR "ahb init failed: %d\n", ret); + return ret; } module_init(ath10k_pci_init); @@ -3238,6 +3245,7 @@ module_init(ath10k_pci_init); static void __exit ath10k_pci_exit(void) { pci_unregister_driver(&ath10k_pci_driver); + ath10k_ahb_exit(); } module_exit(ath10k_pci_exit); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index fcfdbca8e55e..c2d4a79aa29a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -22,6 +22,7 @@ #include "hw.h" #include "ce.h" +#include "ahb.h" /* * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite -- cgit v1.2.3 From 37a219a556b01b3236156ecf58717c1e41b552d9 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:26 +0530 Subject: ath10k: include qca4019 register map table New register table is added for qca4019 to tell about it's register mapping details. Nothing much other than this. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++++ drivers/net/wireless/ath/ath10k/hw.c | 39 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 3 files changed, 45 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 48a26206c5c1..1f4a27881936 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1980,6 +1980,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->regs = &qca99x0_regs; ar->hw_values = &qca99x0_values; break; + case ATH10K_HW_QCA4019: + ar->regs = &qca4019_regs; + ar->hw_values = &qca4019_values; + break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 7b84d08a5154..f544d48518c3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -109,6 +109,38 @@ const struct ath10k_hw_regs qca99x0_regs = { .pcie_intr_clr_address = 0x00000010, }; +const struct ath10k_hw_regs qca4019_regs = { + .rtc_soc_base_address = 0x00080000, + .soc_core_base_address = 0x00082000, + .ce_wrapper_base_address = 0x0004d000, + .ce0_base_address = 0x0004a000, + .ce1_base_address = 0x0004a400, + .ce2_base_address = 0x0004a800, + .ce3_base_address = 0x0004ac00, + .ce4_base_address = 0x0004b000, + .ce5_base_address = 0x0004b400, + .ce6_base_address = 0x0004b800, + .ce7_base_address = 0x0004bc00, + /* qca4019 supports upto 12 copy engines. Since base address + * of ce8 to ce11 are not directly referred in the code, + * no need have them in separate members in this table. + * Copy Engine Address + * CE8 0x0004c000 + * CE9 0x0004c400 + * CE10 0x0004c800 + * CE11 0x0004cc00 + */ + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00000100, + .soc_chip_id_address = 0x000000ec, + .fw_indicator_address = 0x0004f00c, + .ce_wrap_intr_sum_host_msi_lsb = 0x0000000c, + .ce_wrap_intr_sum_host_msi_mask = 0x00fff000, + .pcie_intr_fw_mask = 0x00100000, + .pcie_intr_ce_mask_all = 0x000fff00, + .pcie_intr_clr_address = 0x00000010, +}; + const struct ath10k_hw_values qca988x_values = { .rtc_state_val_on = 3, .ce_count = 8, @@ -136,6 +168,13 @@ const struct ath10k_hw_values qca99x0_values = { .ce_desc_meta_data_lsb = 4, }; +const struct ath10k_hw_values qca4019_values = { + .ce_count = 12, + .num_target_ce_config_wlan = 10, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index f8850155140a..f57a37bfc9f6 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -233,6 +233,7 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; extern const struct ath10k_hw_regs qca99x0_regs; +extern const struct ath10k_hw_regs qca4019_regs; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -246,6 +247,7 @@ struct ath10k_hw_values { extern const struct ath10k_hw_values qca988x_values; extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca99x0_values; +extern const struct ath10k_hw_values qca4019_values; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); -- cgit v1.2.3 From 7f8e79cdc2534559e3e38f5aee0b9f78e57e8fb3 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:27 +0530 Subject: ath10k: add helper functions in ahb.c for reg rd/wr qca4019 deals with below register memory region to control the clock, reset, etc. - Memory to control wifi core - gcc (outside of wifi) - tcsr (outside of wifi) Add new helper functions to perform read/write in above registers spaces. Actual ioremap for above registers are done in later patch. Struct ath10k_ahb is introduced to maintain ahb specific info and memory this struct will be allocated in the continuation of struct ath10k_pci (again, memory ath10k_ahb is allocated in the later patch). Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 55 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 7 +++++ drivers/net/wireless/ath/ath10k/pci.h | 6 ++++ 3 files changed, 68 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 129f4f4491d0..eab4b47237e0 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -17,6 +17,7 @@ #include #include "core.h" #include "debug.h" +#include "pci.h" #include "ahb.h" static const struct of_device_id ath10k_ahb_of_match[] = { @@ -29,6 +30,60 @@ static const struct of_device_id ath10k_ahb_of_match[] = { MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match); +static inline struct ath10k_ahb *ath10k_ahb_priv(struct ath10k *ar) +{ + return &((struct ath10k_pci *)ar->drv_priv)->ahb[0]; +} + +static void ath10k_ahb_write32(struct ath10k *ar, u32 offset, u32 value) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + iowrite32(value, ar_ahb->mem + offset); +} + +static u32 ath10k_ahb_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + return ioread32(ar_ahb->mem + offset); +} + +static u32 ath10k_ahb_gcc_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + return ioread32(ar_ahb->gcc_mem + offset); +} + +static void ath10k_ahb_tcsr_write32(struct ath10k *ar, u32 offset, u32 value) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + iowrite32(value, ar_ahb->tcsr_mem + offset); +} + +static u32 ath10k_ahb_tcsr_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + return ioread32(ar_ahb->tcsr_mem + offset); +} + +static u32 ath10k_ahb_soc_read32(struct ath10k *ar, u32 addr) +{ + return ath10k_ahb_read32(ar, RTC_SOC_BASE_ADDRESS + addr); +} + +static int ath10k_ahb_get_num_banks(struct ath10k *ar) +{ + if (ar->hw_rev == ATH10K_HW_QCA4019) + return 1; + + ath10k_warn(ar, "unknown number of banks, assuming 1\n"); + return 1; +} + static int ath10k_ahb_probe(struct platform_device *pdev) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index d1afe93f9329..77d15af59c4a 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -20,6 +20,13 @@ #include +struct ath10k_ahb { + struct platform_device *pdev; + void __iomem *mem; + void __iomem *gcc_mem; + void __iomem *tcsr_mem; +}; + #ifdef CONFIG_ATH10K_AHB int ath10k_ahb_init(void); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index c2d4a79aa29a..249c73a69800 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -234,6 +234,12 @@ struct ath10k_pci { bool pci_ps; const struct ath10k_bus_ops *bus_ops; + + /* Keep this entry in the last, memory for struct ath10k_ahb is + * allocated (ahb support enabled case) in the continuation of + * this struct. + */ + struct ath10k_ahb ahb[0]; }; static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) -- cgit v1.2.3 From 8beff219c528d19c66e9d2c40fa868d7e7c2e36f Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:28 +0530 Subject: ath10k: add clock ctrl related functions in ahb pre qca4019 chipsets has/uses internal clock generator for the operation. But, qca4019 uses external clocks supplied from outside of target (ie, outside of wifi core). Three different clocks (cmd clock, ref clock, rtc clock) comes into picture in qca4019. All those clocks needs to configured with help of global clock controller (gcc) to make qca4019 functioning. Add functions for clock init/deinit, clock enable/disable in ahb. This is just a preparation, functions added in this patch will be used in later patches. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 123 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 4 ++ 2 files changed, 127 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index eab4b47237e0..11185c0dc6ad 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include +#include #include "core.h" #include "debug.h" #include "pci.h" @@ -84,6 +85,128 @@ static int ath10k_ahb_get_num_banks(struct ath10k *ar) return 1; } +static int ath10k_ahb_clock_init(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + struct device *dev; + int ret; + + dev = &ar_ahb->pdev->dev; + + ar_ahb->cmd_clk = clk_get(dev, "wifi_wcss_cmd"); + if (IS_ERR_OR_NULL(ar_ahb->cmd_clk)) { + ath10k_err(ar, "failed to get cmd clk: %ld\n", + PTR_ERR(ar_ahb->cmd_clk)); + ret = ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV; + goto out; + } + + ar_ahb->ref_clk = clk_get(dev, "wifi_wcss_ref"); + if (IS_ERR_OR_NULL(ar_ahb->ref_clk)) { + ath10k_err(ar, "failed to get ref clk: %ld\n", + PTR_ERR(ar_ahb->ref_clk)); + ret = ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV; + goto err_cmd_clk_put; + } + + ar_ahb->rtc_clk = clk_get(dev, "wifi_wcss_rtc"); + if (IS_ERR_OR_NULL(ar_ahb->rtc_clk)) { + ath10k_err(ar, "failed to get rtc clk: %ld\n", + PTR_ERR(ar_ahb->rtc_clk)); + ret = ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV; + goto err_ref_clk_put; + } + + return 0; + +err_ref_clk_put: + clk_put(ar_ahb->ref_clk); + +err_cmd_clk_put: + clk_put(ar_ahb->cmd_clk); + +out: + return ret; +} + +static void ath10k_ahb_clock_deinit(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk)) + clk_put(ar_ahb->cmd_clk); + + if (!IS_ERR_OR_NULL(ar_ahb->ref_clk)) + clk_put(ar_ahb->ref_clk); + + if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk)) + clk_put(ar_ahb->rtc_clk); + + ar_ahb->cmd_clk = NULL; + ar_ahb->ref_clk = NULL; + ar_ahb->rtc_clk = NULL; +} + +static int ath10k_ahb_clock_enable(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + struct device *dev; + int ret; + + dev = &ar_ahb->pdev->dev; + + if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) || + IS_ERR_OR_NULL(ar_ahb->ref_clk) || + IS_ERR_OR_NULL(ar_ahb->rtc_clk)) { + ath10k_err(ar, "clock(s) is/are not initialized\n"); + ret = -EIO; + goto out; + } + + ret = clk_prepare_enable(ar_ahb->cmd_clk); + if (ret) { + ath10k_err(ar, "failed to enable cmd clk: %d\n", ret); + goto out; + } + + ret = clk_prepare_enable(ar_ahb->ref_clk); + if (ret) { + ath10k_err(ar, "failed to enable ref clk: %d\n", ret); + goto err_cmd_clk_disable; + } + + ret = clk_prepare_enable(ar_ahb->rtc_clk); + if (ret) { + ath10k_err(ar, "failed to enable rtc clk: %d\n", ret); + goto err_ref_clk_disable; + } + + return 0; + +err_ref_clk_disable: + clk_disable_unprepare(ar_ahb->ref_clk); + +err_cmd_clk_disable: + clk_disable_unprepare(ar_ahb->cmd_clk); + +out: + return ret; +} + +static void ath10k_ahb_clock_disable(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk)) + clk_disable_unprepare(ar_ahb->cmd_clk); + + if (!IS_ERR_OR_NULL(ar_ahb->ref_clk)) + clk_disable_unprepare(ar_ahb->ref_clk); + + if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk)) + clk_disable_unprepare(ar_ahb->rtc_clk); +} + static int ath10k_ahb_probe(struct platform_device *pdev) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index 77d15af59c4a..753b4330075a 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -25,6 +25,10 @@ struct ath10k_ahb { void __iomem *mem; void __iomem *gcc_mem; void __iomem *tcsr_mem; + + struct clk *cmd_clk; + struct clk *ref_clk; + struct clk *rtc_clk; }; #ifdef CONFIG_ATH10K_AHB -- cgit v1.2.3 From 14854bfd9daaa20778db64f224a957c2abaab6fe Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:29 +0530 Subject: ath10k: add reset ctrl related functions in ahb To perform reset on qca4019 wifi, multiple reset lines needs to be toggled in a sequence with help of reset controller support in the kernel. This patch adds functions to reset control init/deinit and release reset. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 2 +- drivers/net/wireless/ath/ath10k/ahb.c | 138 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 6 ++ 3 files changed, 145 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index d7f207a6b0e0..db1ca629cbd6 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -17,7 +17,7 @@ config ATH10K_PCI config ATH10K_AHB bool "Atheros ath10k AHB support" - depends on ATH10K_PCI && OF + depends on ATH10K_PCI && OF && RESET_CONTROLLER ---help--- This module adds support for AHB bus diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 11185c0dc6ad..d1f197220e30 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -16,6 +16,7 @@ */ #include #include +#include #include "core.h" #include "debug.h" #include "pci.h" @@ -207,6 +208,143 @@ static void ath10k_ahb_clock_disable(struct ath10k *ar) clk_disable_unprepare(ar_ahb->rtc_clk); } +static int ath10k_ahb_rst_ctrl_init(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + struct device *dev; + int ret; + + dev = &ar_ahb->pdev->dev; + + ar_ahb->core_cold_rst = reset_control_get(dev, "wifi_core_cold"); + if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst)) { + ath10k_err(ar, "failed to get core cold rst ctrl: %ld\n", + PTR_ERR(ar_ahb->core_cold_rst)); + ret = ar_ahb->core_cold_rst ? + PTR_ERR(ar_ahb->core_cold_rst) : -ENODEV; + goto out; + } + + ar_ahb->radio_cold_rst = reset_control_get(dev, "wifi_radio_cold"); + if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst)) { + ath10k_err(ar, "failed to get radio cold rst ctrl: %ld\n", + PTR_ERR(ar_ahb->radio_cold_rst)); + ret = ar_ahb->radio_cold_rst ? + PTR_ERR(ar_ahb->radio_cold_rst) : -ENODEV; + goto err_core_cold_rst_put; + } + + ar_ahb->radio_warm_rst = reset_control_get(dev, "wifi_radio_warm"); + if (IS_ERR_OR_NULL(ar_ahb->radio_warm_rst)) { + ath10k_err(ar, "failed to get radio warm rst ctrl: %ld\n", + PTR_ERR(ar_ahb->radio_warm_rst)); + ret = ar_ahb->radio_warm_rst ? + PTR_ERR(ar_ahb->radio_warm_rst) : -ENODEV; + goto err_radio_cold_rst_put; + } + + ar_ahb->radio_srif_rst = reset_control_get(dev, "wifi_radio_srif"); + if (IS_ERR_OR_NULL(ar_ahb->radio_srif_rst)) { + ath10k_err(ar, "failed to get radio srif rst ctrl: %ld\n", + PTR_ERR(ar_ahb->radio_srif_rst)); + ret = ar_ahb->radio_srif_rst ? + PTR_ERR(ar_ahb->radio_srif_rst) : -ENODEV; + goto err_radio_warm_rst_put; + } + + ar_ahb->cpu_init_rst = reset_control_get(dev, "wifi_cpu_init"); + if (IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { + ath10k_err(ar, "failed to get cpu init rst ctrl: %ld\n", + PTR_ERR(ar_ahb->cpu_init_rst)); + ret = ar_ahb->cpu_init_rst ? + PTR_ERR(ar_ahb->cpu_init_rst) : -ENODEV; + goto err_radio_srif_rst_put; + } + + return 0; + +err_radio_srif_rst_put: + reset_control_put(ar_ahb->radio_srif_rst); + +err_radio_warm_rst_put: + reset_control_put(ar_ahb->radio_warm_rst); + +err_radio_cold_rst_put: + reset_control_put(ar_ahb->radio_cold_rst); + +err_core_cold_rst_put: + reset_control_put(ar_ahb->core_cold_rst); + +out: + return ret; +} + +static void ath10k_ahb_rst_ctrl_deinit(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + if (!IS_ERR_OR_NULL(ar_ahb->core_cold_rst)) + reset_control_put(ar_ahb->core_cold_rst); + + if (!IS_ERR_OR_NULL(ar_ahb->radio_cold_rst)) + reset_control_put(ar_ahb->radio_cold_rst); + + if (!IS_ERR_OR_NULL(ar_ahb->radio_warm_rst)) + reset_control_put(ar_ahb->radio_warm_rst); + + if (!IS_ERR_OR_NULL(ar_ahb->radio_srif_rst)) + reset_control_put(ar_ahb->radio_srif_rst); + + if (!IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) + reset_control_put(ar_ahb->cpu_init_rst); + + ar_ahb->core_cold_rst = NULL; + ar_ahb->radio_cold_rst = NULL; + ar_ahb->radio_warm_rst = NULL; + ar_ahb->radio_srif_rst = NULL; + ar_ahb->cpu_init_rst = NULL; +} + +static int ath10k_ahb_release_reset(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + int ret; + + if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) || + IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) || + IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) || + IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { + ath10k_err(ar, "rst ctrl(s) is/are not initialized\n"); + return -EINVAL; + } + + ret = reset_control_deassert(ar_ahb->radio_cold_rst); + if (ret) { + ath10k_err(ar, "failed to deassert radio cold rst: %d\n", ret); + return ret; + } + + ret = reset_control_deassert(ar_ahb->radio_warm_rst); + if (ret) { + ath10k_err(ar, "failed to deassert radio warm rst: %d\n", ret); + return ret; + } + + ret = reset_control_deassert(ar_ahb->radio_srif_rst); + if (ret) { + ath10k_err(ar, "failed to deassert radio srif rst: %d\n", ret); + return ret; + } + + ret = reset_control_deassert(ar_ahb->cpu_init_rst); + if (ret) { + ath10k_err(ar, "failed to deassert cpu init rst: %d\n", ret); + return ret; + } + + return 0; +} + static int ath10k_ahb_probe(struct platform_device *pdev) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index 753b4330075a..2904b7bc9459 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -29,6 +29,12 @@ struct ath10k_ahb { struct clk *cmd_clk; struct clk *ref_clk; struct clk *rtc_clk; + + struct reset_control *core_cold_rst; + struct reset_control *radio_cold_rst; + struct reset_control *radio_warm_rst; + struct reset_control *radio_srif_rst; + struct reset_control *cpu_init_rst; }; #ifdef CONFIG_ATH10K_AHB -- cgit v1.2.3 From 133df0f849bc7b5448c62272986af626f2bda6bd Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:30 +0530 Subject: ath10k: add chip and bus halt logic in ahb Add function to perform chip halt sequence and function to halt axi bus in ahb module. Mainly used in the scenario like driver unload. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 113 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 15 +++++ 2 files changed, 128 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index d1f197220e30..230507890fbf 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -345,6 +345,119 @@ static int ath10k_ahb_release_reset(struct ath10k *ar) return 0; } +static void ath10k_ahb_halt_axi_bus(struct ath10k *ar, u32 haltreq_reg, + u32 haltack_reg) +{ + unsigned long timeout; + u32 val; + + /* Issue halt axi bus request */ + val = ath10k_ahb_tcsr_read32(ar, haltreq_reg); + val |= AHB_AXI_BUS_HALT_REQ; + ath10k_ahb_tcsr_write32(ar, haltreq_reg, val); + + /* Wait for axi bus halted ack */ + timeout = jiffies + msecs_to_jiffies(ATH10K_AHB_AXI_BUS_HALT_TIMEOUT); + do { + val = ath10k_ahb_tcsr_read32(ar, haltack_reg); + if (val & AHB_AXI_BUS_HALT_ACK) + break; + + mdelay(1); + } while (time_before(jiffies, timeout)); + + if (!(val & AHB_AXI_BUS_HALT_ACK)) { + ath10k_err(ar, "failed to halt axi bus: %d\n", val); + return; + } + + ath10k_dbg(ar, ATH10K_DBG_AHB, "axi bus halted\n"); +} + +static void ath10k_ahb_halt_chip(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + u32 core_id, glb_cfg_reg, haltreq_reg, haltack_reg; + u32 val; + int ret; + + if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst) || + IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) || + IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) || + IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) || + IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { + ath10k_err(ar, "rst ctrl(s) is/are not initialized\n"); + return; + } + + core_id = ath10k_ahb_read32(ar, ATH10K_AHB_WLAN_CORE_ID_REG); + + switch (core_id) { + case 0: + glb_cfg_reg = ATH10K_AHB_TCSR_WIFI0_GLB_CFG; + haltreq_reg = ATH10K_AHB_TCSR_WCSS0_HALTREQ; + haltack_reg = ATH10K_AHB_TCSR_WCSS0_HALTACK; + break; + case 1: + glb_cfg_reg = ATH10K_AHB_TCSR_WIFI1_GLB_CFG; + haltreq_reg = ATH10K_AHB_TCSR_WCSS1_HALTREQ; + haltack_reg = ATH10K_AHB_TCSR_WCSS1_HALTACK; + break; + default: + ath10k_err(ar, "invalid core id %d found, skipping reset sequence\n", + core_id); + return; + } + + ath10k_ahb_halt_axi_bus(ar, haltreq_reg, haltack_reg); + + val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg); + val |= TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK; + ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val); + + ret = reset_control_assert(ar_ahb->core_cold_rst); + if (ret) + ath10k_err(ar, "failed to assert core cold rst: %d\n", ret); + msleep(1); + + ret = reset_control_assert(ar_ahb->radio_cold_rst); + if (ret) + ath10k_err(ar, "failed to assert radio cold rst: %d\n", ret); + msleep(1); + + ret = reset_control_assert(ar_ahb->radio_warm_rst); + if (ret) + ath10k_err(ar, "failed to assert radio warm rst: %d\n", ret); + msleep(1); + + ret = reset_control_assert(ar_ahb->radio_srif_rst); + if (ret) + ath10k_err(ar, "failed to assert radio srif rst: %d\n", ret); + msleep(1); + + ret = reset_control_assert(ar_ahb->cpu_init_rst); + if (ret) + ath10k_err(ar, "failed to assert cpu init rst: %d\n", ret); + msleep(10); + + /* Clear halt req and core clock disable req before + * deasserting wifi core reset. + */ + val = ath10k_ahb_tcsr_read32(ar, haltreq_reg); + val &= ~AHB_AXI_BUS_HALT_REQ; + ath10k_ahb_tcsr_write32(ar, haltreq_reg, val); + + val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg); + val &= ~TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK; + ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val); + + ret = reset_control_deassert(ar_ahb->core_cold_rst); + if (ret) + ath10k_err(ar, "failed to deassert core cold rst: %d\n", ret); + + ath10k_dbg(ar, ATH10K_DBG_AHB, "core %d reset done\n", core_id); +} + static int ath10k_ahb_probe(struct platform_device *pdev) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index 2904b7bc9459..4761eeb475d6 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -39,6 +39,21 @@ struct ath10k_ahb { #ifdef CONFIG_ATH10K_AHB +#define ATH10K_AHB_WLAN_CORE_ID_REG 0x82030 + +#define ATH10K_AHB_TCSR_WIFI0_GLB_CFG 0x49000 +#define ATH10K_AHB_TCSR_WIFI1_GLB_CFG 0x49004 +#define TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK BIT(25) + +#define ATH10K_AHB_TCSR_WCSS0_HALTREQ 0x52000 +#define ATH10K_AHB_TCSR_WCSS1_HALTREQ 0x52010 +#define ATH10K_AHB_TCSR_WCSS0_HALTACK 0x52004 +#define ATH10K_AHB_TCSR_WCSS1_HALTACK 0x52014 + +#define ATH10K_AHB_AXI_BUS_HALT_TIMEOUT 10 /* msec */ +#define AHB_AXI_BUS_HALT_REQ 1 +#define AHB_AXI_BUS_HALT_ACK 1 + int ath10k_ahb_init(void); void ath10k_ahb_exit(void); -- cgit v1.2.3 From 1c44fcb9234c80bbf9e4043deab8492e1c0dcf99 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:31 +0530 Subject: ath10k: include irq related functions in ahb Add irq related functions to register,handle,release,disable interrupt. qca4019 supports msi interrupt, but it has the problem. Until the issue gets sorted out, only legacy interrupt model is enabled and used. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 44 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 2 ++ 2 files changed, 46 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 230507890fbf..29d0b6c6b35c 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -458,6 +458,50 @@ static void ath10k_ahb_halt_chip(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_AHB, "core %d reset done\n", core_id); } +static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg) +{ + struct ath10k *ar = arg; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + if (!ath10k_pci_irq_pending(ar)) + return IRQ_NONE; + + ath10k_pci_disable_and_clear_legacy_irq(ar); + tasklet_schedule(&ar_pci->intr_tq); + + return IRQ_HANDLED; +} + +static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + int ret; + + ret = request_irq(ar_ahb->irq, + ath10k_ahb_interrupt_handler, + IRQF_SHARED, "ath10k_ahb", ar); + if (ret) { + ath10k_warn(ar, "failed to request legacy irq %d: %d\n", + ar_ahb->irq, ret); + return ret; + } + + return 0; +} + +static void ath10k_ahb_release_irq_legacy(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + free_irq(ar_ahb->irq, ar); +} + +static void ath10k_ahb_irq_disable(struct ath10k *ar) +{ + ath10k_ce_disable_interrupts(ar); + ath10k_pci_disable_and_clear_legacy_irq(ar); +} + static int ath10k_ahb_probe(struct platform_device *pdev) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index 4761eeb475d6..97c40e47dc02 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -26,6 +26,8 @@ struct ath10k_ahb { void __iomem *gcc_mem; void __iomem *tcsr_mem; + int irq; + struct clk *cmd_clk; struct clk *ref_clk; struct clk *rtc_clk; -- cgit v1.2.3 From 704dc4e36769218145d30c41e81a5fbfed3977c7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:32 +0530 Subject: ath10k: add resource init and deinit in ahb Add function to gather resources required for qca4019 to operate (memory, irq, dma setting, clock init , rest control init) and function release those resources when it's not needed. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 122 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 7 ++ 2 files changed, 129 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 29d0b6c6b35c..d83a864515a2 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include +#include +#include #include #include #include "core.h" @@ -502,6 +504,126 @@ static void ath10k_ahb_irq_disable(struct ath10k *ar) ath10k_pci_disable_and_clear_legacy_irq(ar); } +static int ath10k_ahb_resource_init(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + struct platform_device *pdev; + struct device *dev; + struct resource *res; + int ret; + + pdev = ar_ahb->pdev; + dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ath10k_err(ar, "failed to get memory resource\n"); + ret = -ENXIO; + goto out; + } + + ar_ahb->mem = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ar_ahb->mem)) { + ath10k_err(ar, "mem ioremap error\n"); + ret = PTR_ERR(ar_ahb->mem); + goto out; + } + + ar_ahb->mem_len = resource_size(res); + + ar_ahb->gcc_mem = ioremap_nocache(ATH10K_GCC_REG_BASE, + ATH10K_GCC_REG_SIZE); + if (!ar_ahb->gcc_mem) { + ath10k_err(ar, "gcc mem ioremap error\n"); + ret = -ENOMEM; + goto err_mem_unmap; + } + + ar_ahb->tcsr_mem = ioremap_nocache(ATH10K_TCSR_REG_BASE, + ATH10K_TCSR_REG_SIZE); + if (!ar_ahb->tcsr_mem) { + ath10k_err(ar, "tcsr mem ioremap error\n"); + ret = -ENOMEM; + goto err_gcc_mem_unmap; + } + + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + ath10k_err(ar, "failed to set 32-bit dma mask: %d\n", ret); + goto err_tcsr_mem_unmap; + } + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + ath10k_err(ar, "failed to set 32-bit consistent dma: %d\n", + ret); + goto err_tcsr_mem_unmap; + } + + ret = ath10k_ahb_clock_init(ar); + if (ret) + goto err_tcsr_mem_unmap; + + ret = ath10k_ahb_rst_ctrl_init(ar); + if (ret) + goto err_clock_deinit; + + ar_ahb->irq = platform_get_irq_byname(pdev, "legacy"); + if (ar_ahb->irq < 0) { + ath10k_err(ar, "failed to get irq number: %d\n", ar_ahb->irq); + goto err_clock_deinit; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "irq: %d\n", ar_ahb->irq); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "mem: 0x%p mem_len: %lu gcc mem: 0x%p tcsr_mem: 0x%p\n", + ar_ahb->mem, ar_ahb->mem_len, + ar_ahb->gcc_mem, ar_ahb->tcsr_mem); + return 0; + +err_clock_deinit: + ath10k_ahb_clock_deinit(ar); + +err_tcsr_mem_unmap: + iounmap(ar_ahb->tcsr_mem); + +err_gcc_mem_unmap: + ar_ahb->tcsr_mem = NULL; + iounmap(ar_ahb->gcc_mem); + +err_mem_unmap: + ar_ahb->gcc_mem = NULL; + devm_iounmap(&pdev->dev, ar_ahb->mem); + +out: + ar_ahb->mem = NULL; + return ret; +} + +static void ath10k_ahb_resource_deinit(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + struct device *dev; + + dev = &ar_ahb->pdev->dev; + + if (ar_ahb->mem) + devm_iounmap(dev, ar_ahb->mem); + + if (ar_ahb->gcc_mem) + iounmap(ar_ahb->gcc_mem); + + if (ar_ahb->tcsr_mem) + iounmap(ar_ahb->tcsr_mem); + + ar_ahb->mem = NULL; + ar_ahb->gcc_mem = NULL; + ar_ahb->tcsr_mem = NULL; + + ath10k_ahb_clock_deinit(ar); + ath10k_ahb_rst_ctrl_deinit(ar); +} + static int ath10k_ahb_probe(struct platform_device *pdev) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index 97c40e47dc02..5bd01b49132b 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -23,6 +23,7 @@ struct ath10k_ahb { struct platform_device *pdev; void __iomem *mem; + unsigned long mem_len; void __iomem *gcc_mem; void __iomem *tcsr_mem; @@ -41,6 +42,12 @@ struct ath10k_ahb { #ifdef CONFIG_ATH10K_AHB +#define ATH10K_GCC_REG_BASE 0x1800000 +#define ATH10K_GCC_REG_SIZE 0x60000 + +#define ATH10K_TCSR_REG_BASE 0x1900000 +#define ATH10K_TCSR_REG_SIZE 0x80000 + #define ATH10K_AHB_WLAN_CORE_ID_REG 0x82030 #define ATH10K_AHB_TCSR_WIFI0_GLB_CFG 0x49000 -- cgit v1.2.3 From 0d87c9208a17cb82fed66e29180078ab603086ea Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 27 Jan 2016 15:24:33 +0530 Subject: ath10k: expose hif ops for ahb Like how pci.c exposes hif ops for the bus specific operation, expose similar hif ops table for ahb with all required functions linked to it. Many ath10k_pci_* functions are reused here in hif ops table. If something is not sharable, new functions are added for ahb and linked to hif ops table. Finally, make ath10k_ahb_probe/remove() to perform what is expected out of it. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 271 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/ahb.h | 5 + drivers/net/wireless/ath/ath10k/hw.h | 1 + 3 files changed, 277 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index d83a864515a2..bd62bc19e758 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -624,13 +624,284 @@ static void ath10k_ahb_resource_deinit(struct ath10k *ar) ath10k_ahb_rst_ctrl_deinit(ar); } +static int ath10k_ahb_prepare_device(struct ath10k *ar) +{ + u32 val; + int ret; + + ret = ath10k_ahb_clock_enable(ar); + if (ret) { + ath10k_err(ar, "failed to enable clocks\n"); + return ret; + } + + /* Clock for the target is supplied from outside of target (ie, + * external clock module controlled by the host). Target needs + * to know what frequency target cpu is configured which is needed + * for target internal use. Read target cpu frequency info from + * gcc register and write into target's scratch register where + * target expects this information. + */ + val = ath10k_ahb_gcc_read32(ar, ATH10K_AHB_GCC_FEPLL_PLL_DIV); + ath10k_ahb_write32(ar, ATH10K_AHB_WIFI_SCRATCH_5_REG, val); + + ret = ath10k_ahb_release_reset(ar); + if (ret) + goto err_clk_disable; + + ath10k_ahb_irq_disable(ar); + + ath10k_ahb_write32(ar, FW_INDICATOR_ADDRESS, FW_IND_HOST_READY); + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) + goto err_halt_chip; + + return 0; + +err_halt_chip: + ath10k_ahb_halt_chip(ar); + +err_clk_disable: + ath10k_ahb_clock_disable(ar); + + return ret; +} + +static int ath10k_ahb_chip_reset(struct ath10k *ar) +{ + int ret; + + ath10k_ahb_halt_chip(ar); + ath10k_ahb_clock_disable(ar); + + ret = ath10k_ahb_prepare_device(ar); + if (ret) + return ret; + + return 0; +} + +static int ath10k_ahb_wake_target_cpu(struct ath10k *ar) +{ + u32 addr, val; + + addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS; + val = ath10k_ahb_read32(ar, addr); + val |= ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK; + ath10k_ahb_write32(ar, addr, val); + + return 0; +} + +static int ath10k_ahb_hif_start(struct ath10k *ar) +{ + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n"); + + ath10k_ce_enable_interrupts(ar); + ath10k_pci_enable_legacy_irq(ar); + + ath10k_pci_rx_post(ar); + + return 0; +} + +static void ath10k_ahb_hif_stop(struct ath10k *ar) +{ + struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif stop\n"); + + ath10k_ahb_irq_disable(ar); + synchronize_irq(ar_ahb->irq); + + ath10k_pci_flush(ar); +} + +static int ath10k_ahb_hif_power_up(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif power up\n"); + + ret = ath10k_ahb_chip_reset(ar); + if (ret) { + ath10k_err(ar, "failed to reset chip: %d\n", ret); + goto out; + } + + ret = ath10k_pci_init_pipes(ar); + if (ret) { + ath10k_err(ar, "failed to initialize CE: %d\n", ret); + goto out; + } + + ret = ath10k_pci_init_config(ar); + if (ret) { + ath10k_err(ar, "failed to setup init config: %d\n", ret); + goto err_ce_deinit; + } + + ret = ath10k_ahb_wake_target_cpu(ar); + if (ret) { + ath10k_err(ar, "could not wake up target CPU: %d\n", ret); + goto err_ce_deinit; + } + + return 0; + +err_ce_deinit: + ath10k_pci_ce_deinit(ar); +out: + return ret; +} + +static const struct ath10k_hif_ops ath10k_ahb_hif_ops = { + .tx_sg = ath10k_pci_hif_tx_sg, + .diag_read = ath10k_pci_hif_diag_read, + .diag_write = ath10k_pci_diag_write_mem, + .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, + .start = ath10k_ahb_hif_start, + .stop = ath10k_ahb_hif_stop, + .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, + .get_default_pipe = ath10k_pci_hif_get_default_pipe, + .send_complete_check = ath10k_pci_hif_send_complete_check, + .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, + .power_up = ath10k_ahb_hif_power_up, + .power_down = ath10k_pci_hif_power_down, + .read32 = ath10k_ahb_read32, + .write32 = ath10k_ahb_write32, +}; + +static const struct ath10k_bus_ops ath10k_ahb_bus_ops = { + .read32 = ath10k_ahb_read32, + .write32 = ath10k_ahb_write32, + .get_num_banks = ath10k_ahb_get_num_banks, +}; + static int ath10k_ahb_probe(struct platform_device *pdev) { + struct ath10k *ar; + struct ath10k_ahb *ar_ahb; + struct ath10k_pci *ar_pci; + const struct of_device_id *of_id; + enum ath10k_hw_rev hw_rev; + size_t size; + int ret; + u32 chip_id; + + of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev); + if (!of_id) { + dev_err(&pdev->dev, "failed to find matching device tree id\n"); + return -EINVAL; + } + + hw_rev = (enum ath10k_hw_rev)of_id->data; + + size = sizeof(*ar_pci) + sizeof(*ar_ahb); + ar = ath10k_core_create(size, &pdev->dev, ATH10K_BUS_AHB, + hw_rev, &ath10k_ahb_hif_ops); + if (!ar) { + dev_err(&pdev->dev, "failed to allocate core\n"); + return -ENOMEM; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "ahb probe\n"); + + ar_pci = ath10k_pci_priv(ar); + ar_ahb = ath10k_ahb_priv(ar); + + ar_ahb->pdev = pdev; + platform_set_drvdata(pdev, ar); + + ret = ath10k_ahb_resource_init(ar); + if (ret) + goto err_core_destroy; + + ar->dev_id = 0; + ar_pci->mem = ar_ahb->mem; + ar_pci->mem_len = ar_ahb->mem_len; + ar_pci->ar = ar; + ar_pci->bus_ops = &ath10k_ahb_bus_ops; + + ret = ath10k_pci_setup_resource(ar); + if (ret) { + ath10k_err(ar, "failed to setup resource: %d\n", ret); + goto err_resource_deinit; + } + + ath10k_pci_init_irq_tasklets(ar); + + ret = ath10k_ahb_request_irq_legacy(ar); + if (ret) + goto err_free_pipes; + + ret = ath10k_ahb_prepare_device(ar); + if (ret) + goto err_free_irq; + + ath10k_pci_ce_deinit(ar); + + chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (chip_id == 0xffffffff) { + ath10k_err(ar, "failed to get chip id\n"); + goto err_halt_device; + } + + ret = ath10k_core_register(ar, chip_id); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", ret); + goto err_halt_device; + } + return 0; + +err_halt_device: + ath10k_ahb_halt_chip(ar); + ath10k_ahb_clock_disable(ar); + +err_free_irq: + ath10k_ahb_release_irq_legacy(ar); + +err_free_pipes: + ath10k_pci_free_pipes(ar); + +err_resource_deinit: + ath10k_ahb_resource_deinit(ar); + +err_core_destroy: + ath10k_core_destroy(ar); + platform_set_drvdata(pdev, NULL); + + return ret; } static int ath10k_ahb_remove(struct platform_device *pdev) { + struct ath10k *ar = platform_get_drvdata(pdev); + struct ath10k_ahb *ar_ahb; + + if (!ar) + return -EINVAL; + + ar_ahb = ath10k_ahb_priv(ar); + + if (!ar_ahb) + return -EINVAL; + + ath10k_dbg(ar, ATH10K_DBG_AHB, "ahb remove\n"); + + ath10k_core_unregister(ar); + ath10k_ahb_irq_disable(ar); + ath10k_ahb_release_irq_legacy(ar); + ath10k_pci_release_resource(ar); + ath10k_ahb_halt_chip(ar); + ath10k_ahb_clock_disable(ar); + ath10k_ahb_resource_deinit(ar); + ath10k_core_destroy(ar); + + platform_set_drvdata(pdev, NULL); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h index 5bd01b49132b..d43e375215c8 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.h +++ b/drivers/net/wireless/ath/ath10k/ahb.h @@ -48,6 +48,9 @@ struct ath10k_ahb { #define ATH10K_TCSR_REG_BASE 0x1900000 #define ATH10K_TCSR_REG_SIZE 0x80000 +#define ATH10K_AHB_GCC_FEPLL_PLL_DIV 0x2f020 +#define ATH10K_AHB_WIFI_SCRATCH_5_REG 0x4f014 + #define ATH10K_AHB_WLAN_CORE_ID_REG 0x82030 #define ATH10K_AHB_TCSR_WIFI0_GLB_CFG 0x49000 @@ -63,6 +66,8 @@ struct ath10k_ahb { #define AHB_AXI_BUS_HALT_REQ 1 #define AHB_AXI_BUS_HALT_ACK 1 +#define ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK 1 + int ath10k_ahb_init(void); void ath10k_ahb_exit(void); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index f57a37bfc9f6..4217bdbe9f01 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -605,6 +605,7 @@ enum ath10k_hw_4addr_pad { #define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address #define FW_IND_EVENT_PENDING 1 #define FW_IND_INITIALIZED 2 +#define FW_IND_HOST_READY 0x80000000 /* HOST_REG interrupt from firmware */ #define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask -- cgit v1.2.3 From 1286558e45fd90fd0faf5d41df35f511c51f25e7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 22 Jan 2016 01:56:30 +0100 Subject: ath9k: do not limit the number of DFS channel interfaces to 1 I think this limit was added when CSA with multiple interfaces wasn't working yet. It should no longer be necessary Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index ab7a1ac37849..d4e0ac946c3a 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -751,14 +751,6 @@ static const struct ieee80211_iface_combination if_comb_multi[] = { #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ -static const struct ieee80211_iface_limit if_dfs_limits[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC) }, -}; - static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, @@ -766,6 +758,11 @@ static const struct ieee80211_iface_combination if_comb[] = { .max_interfaces = 2048, .num_different_channels = 1, .beacon_int_infra_match = true, +#ifdef CONFIG_ATH9K_DFS_CERTIFIED + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), +#endif }, { .limits = wds_limits, @@ -774,18 +771,6 @@ static const struct ieee80211_iface_combination if_comb[] = { .num_different_channels = 1, .beacon_int_infra_match = true, }, -#ifdef CONFIG_ATH9K_DFS_CERTIFIED - { - .limits = if_dfs_limits, - .n_limits = ARRAY_SIZE(if_dfs_limits), - .max_interfaces = 1, - .num_different_channels = 1, - .beacon_int_infra_match = true, - .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40), - } -#endif }; #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT -- cgit v1.2.3 From 4c1ce07bcf62536ed42a4ba43e5fb580be61ac48 Mon Sep 17 00:00:00 2001 From: Uri Mashiach Date: Wed, 30 Dec 2015 15:35:31 +0200 Subject: wlcore/wl12xx: spi: add power operation function The power function uses a consumer regulator access to update the WiFi enable GPIO value. Signed-off-by: Uri Mashiach Tested-By: Sebastian Reichel Reviewed-by: Grygorii Strashko Acked-by: Igor Grinberg Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/spi.c | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 44f059f7f34e..dec151247d0d 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "wlcore.h" #include "wl12xx_80211.h" @@ -81,6 +82,7 @@ struct wl12xx_spi_glue { struct device *dev; struct platform_device *core; + struct regulator *reg; /* Power regulator */ }; static void wl12xx_spi_reset(struct device *child) @@ -318,11 +320,40 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, return 0; } +/** + * wl12xx_spi_set_power - power on/off the wl12xx unit + * @child: wl12xx device handle. + * @enable: true/false to power on/off the unit. + * + * use the WiFi enable regulator to enable/disable the WiFi unit. + */ +static int wl12xx_spi_set_power(struct device *child, bool enable) +{ + int ret = 0; + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); + + WARN_ON(!glue->reg); + + /* Update regulator state */ + if (enable) { + ret = regulator_enable(glue->reg); + if (ret) + dev_err(child, "Power enable failure\n"); + } else { + ret = regulator_disable(glue->reg); + if (ret) + dev_err(child, "Power disable failure\n"); + } + + return ret; +} + static struct wl1271_if_operations spi_ops = { .read = wl12xx_spi_raw_read, .write = wl12xx_spi_raw_write, .reset = wl12xx_spi_reset, .init = wl12xx_spi_init, + .power = wl12xx_spi_set_power, .set_block_size = NULL, }; @@ -353,6 +384,14 @@ static int wl1271_probe(struct spi_device *spi) * comes from the board-peripherals file */ spi->bits_per_word = 32; + glue->reg = devm_regulator_get(&spi->dev, "vwlan"); + if (PTR_ERR(glue->reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (IS_ERR(glue->reg)) { + dev_err(glue->dev, "can't get regulator\n"); + return PTR_ERR(glue->reg); + } + ret = spi_setup(spi); if (ret < 0) { dev_err(glue->dev, "spi_setup failed\n"); -- cgit v1.2.3 From 04654c386145239c8bcb35878b0b0537ce916766 Mon Sep 17 00:00:00 2001 From: Uri Mashiach Date: Wed, 30 Dec 2015 15:35:32 +0200 Subject: wlcore/wl12xx: spi: add device tree support Add DT support for the wl1271 SPI WiFi. Add documentation file for the wl1271 SPI WiFi. Signed-off-by: Uri Mashiach Acked-by: Rob Herring Tested-By: Sebastian Reichel Reviewed-by: Grygorii Strashko Acked-by: Igor Grinberg Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/Kconfig | 2 +- drivers/net/wireless/ti/wlcore/spi.c | 47 +++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig index 969c9d79bfc8..8a8f1e711384 100644 --- a/drivers/net/wireless/ti/wlcore/Kconfig +++ b/drivers/net/wireless/ti/wlcore/Kconfig @@ -13,7 +13,7 @@ config WLCORE config WLCORE_SPI tristate "TI wlcore SPI support" - depends on WLCORE && SPI_MASTER + depends on WLCORE && SPI_MASTER && OF select CRC7 ---help--- This module adds support for the SPI interface of adapters using diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index dec151247d0d..020ac1a4b408 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "wlcore.h" @@ -357,6 +358,39 @@ static struct wl1271_if_operations spi_ops = { .set_block_size = NULL, }; +static const struct of_device_id wlcore_spi_of_match_table[] = { + { .compatible = "ti,wl1271" }, + { } +}; +MODULE_DEVICE_TABLE(of, wlcore_spi_of_match_table); + +/** + * wlcore_probe_of - DT node parsing. + * @spi: SPI slave device parameters. + * @res: resource parameters. + * @glue: wl12xx SPI bus to slave device glue parameters. + * @pdev_data: wlcore device parameters + */ +static int wlcore_probe_of(struct spi_device *spi, struct wl12xx_spi_glue *glue, + struct wlcore_platdev_data *pdev_data) +{ + struct device_node *dt_node = spi->dev.of_node; + int ret; + + if (of_find_property(dt_node, "clock-xtal", NULL)) + pdev_data->ref_clock_xtal = true; + + ret = of_property_read_u32(dt_node, "ref-clock-frequency", + &pdev_data->ref_clock_freq); + if (IS_ERR_VALUE(ret)) { + dev_err(glue->dev, + "can't get reference clock frequency (%d)\n", ret); + return ret; + } + + return 0; +} + static int wl1271_probe(struct spi_device *spi) { struct wl12xx_spi_glue *glue; @@ -366,8 +400,6 @@ static int wl1271_probe(struct spi_device *spi) memset(&pdev_data, 0x00, sizeof(pdev_data)); - /* TODO: add DT parsing when needed */ - pdev_data.if_ops = &spi_ops; glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL); @@ -392,6 +424,13 @@ static int wl1271_probe(struct spi_device *spi) return PTR_ERR(glue->reg); } + ret = wlcore_probe_of(spi, glue, &pdev_data); + if (IS_ERR_VALUE(ret)) { + dev_err(glue->dev, + "can't get device tree parameters (%d)\n", ret); + return ret; + } + ret = spi_setup(spi); if (ret < 0) { dev_err(glue->dev, "spi_setup failed\n"); @@ -409,7 +448,7 @@ static int wl1271_probe(struct spi_device *spi) memset(res, 0x00, sizeof(res)); res[0].start = spi->irq; - res[0].flags = IORESOURCE_IRQ; + res[0].flags = IORESOURCE_IRQ | irq_get_trigger_type(spi->irq); res[0].name = "irq"; ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); @@ -447,10 +486,10 @@ static int wl1271_remove(struct spi_device *spi) return 0; } - static struct spi_driver wl1271_spi_driver = { .driver = { .name = "wl1271_spi", + .of_match_table = of_match_ptr(wlcore_spi_of_match_table), }, .probe = wl1271_probe, -- cgit v1.2.3 From 2fd5c6ed0b4fbf3c2d9314a24c82862ce5254d42 Mon Sep 17 00:00:00 2001 From: chunfan chen Date: Wed, 6 Jan 2016 23:40:47 -0800 Subject: mwifiex: firmware download enhancements Same chip is being used by WLAN as well as bluetooth drivers. Each driver needs to check during initialisation if firmware is already active or it needs to be freshly downloaded. If one driver has started downloading the firmware, other finds the winner flag as false. mwifiex_check_fw_status() checks firmware status and also check if WLAN is the winner for firmware downloading. Once we detect that other interface is downloading the firmware, we call this routine again with max poll count to wait until firmware is ready. This patch splits the routine to avoid checking winner status unnecessarily multiple times and ensures that correct messages are displayed to user. Firmware status poll count is also increased to 150. Signed-off-by: Chunfan Chen Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/fw.h | 2 +- drivers/net/wireless/marvell/mwifiex/init.c | 16 +++++++++--- drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/pcie.c | 40 +++++++++++++++++------------ drivers/net/wireless/marvell/mwifiex/sdio.c | 33 ++++++++++++++---------- 5 files changed, 57 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index ced7af2be29a..426e76ade30c 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -96,7 +96,7 @@ enum KEY_TYPE_ID { #define WAPI_KEY_LEN (WLAN_KEY_LEN_SMS4 + PN_LEN + 2) #define MAX_POLL_TRIES 100 -#define MAX_FIRMWARE_POLL_TRIES 100 +#define MAX_FIRMWARE_POLL_TRIES 150 #define FIRMWARE_READY_SDIO 0xfedc #define FIRMWARE_READY_PCIE 0xfedcba00 diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 6f7876ec31b7..517653b3adab 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -741,8 +741,6 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, u32 poll_num = 1; if (adapter->if_ops.check_fw_status) { - adapter->winner = 0; - /* check if firmware is already running */ ret = adapter->if_ops.check_fw_status(adapter, poll_num); if (!ret) { @@ -750,13 +748,23 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, "WLAN FW already running! Skip FW dnld\n"); return 0; } + } + + /* check if we are the winner for downloading FW */ + if (adapter->if_ops.check_winner_status) { + adapter->winner = 0; + ret = adapter->if_ops.check_winner_status(adapter); poll_num = MAX_FIRMWARE_POLL_TRIES; + if (ret) { + mwifiex_dbg(adapter, MSG, + "WLAN read winner status failed!\n"); + return ret; + } - /* check if we are the winner for downloading FW */ if (!adapter->winner) { mwifiex_dbg(adapter, MSG, - "FW already running! Skip FW dnld\n"); + "WLAN is not the winner! Skip FW dnld\n"); goto poll_fw; } } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 2f7f478ce04b..c08be798905f 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -791,6 +791,7 @@ struct mwifiex_if_ops { int (*init_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *); int (*check_fw_status) (struct mwifiex_adapter *, u32); + int (*check_winner_status)(struct mwifiex_adapter *); int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); int (*register_dev) (struct mwifiex_adapter *); void (*unregister_dev) (struct mwifiex_adapter *); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 6d0dc40e20e5..f448d7ca4e7c 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2007,14 +2007,12 @@ done: /* * This function checks the firmware status in card. - * - * The winner interface is also determined by this function. */ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) { int ret = 0; - u32 firmware_stat, winner_status; + u32 firmware_stat; struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; u32 tries; @@ -2054,19 +2052,28 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) } } - if (ret) { - if (mwifiex_read_reg(adapter, reg->fw_status, - &winner_status)) - ret = -1; - else if (!winner_status) { - mwifiex_dbg(adapter, INFO, - "PCI-E is the winner\n"); - adapter->winner = 1; - } else { - mwifiex_dbg(adapter, ERROR, - "PCI-E is not the winner <%#x,%d>, exit dnld\n", - ret, adapter->winner); - } + return ret; +} + +/* This function checks if WLAN is the winner. + */ +static int +mwifiex_check_winner_status(struct mwifiex_adapter *adapter) +{ + u32 winner = 0; + int ret = 0; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + + if (mwifiex_read_reg(adapter, reg->fw_status, &winner)) { + ret = -1; + } else if (!winner) { + mwifiex_dbg(adapter, INFO, "PCI-E is the winner\n"); + adapter->winner = 1; + } else { + mwifiex_dbg(adapter, ERROR, + "PCI-E is not the winner <%#x,%d>, exit dnld\n", + ret, adapter->winner); } return ret; @@ -2675,6 +2682,7 @@ static struct mwifiex_if_ops pcie_ops = { .init_if = mwifiex_pcie_init, .cleanup_if = mwifiex_pcie_cleanup, .check_fw_status = mwifiex_check_fw_status, + .check_winner_status = mwifiex_check_winner_status, .prog_fw = mwifiex_prog_fw_w_helper, .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 4c8cae682c89..33771d3fd843 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1039,19 +1039,14 @@ done: /* * This function checks the firmware status in card. - * - * The winner interface is also determined by this function. */ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) { - struct sdio_mmc_card *card = adapter->card; int ret = 0; u16 firmware_stat; u32 tries; - u8 winner_status; - /* Wait for firmware initialization event */ for (tries = 0; tries < poll_num; tries++) { ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); if (ret) @@ -1065,16 +1060,25 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, } } - if (ret) { - if (mwifiex_read_reg - (adapter, card->reg->status_reg_0, &winner_status)) - winner_status = 0; + return ret; +} + +/* This function checks if WLAN is the winner. + */ +static int mwifiex_check_winner_status(struct mwifiex_adapter *adapter) +{ + int ret = 0; + u8 winner = 0; + struct sdio_mmc_card *card = adapter->card; + + if (mwifiex_read_reg(adapter, card->reg->status_reg_0, &winner)) + return -1; + + if (winner) + adapter->winner = 0; + else + adapter->winner = 1; - if (winner_status) - adapter->winner = 0; - else - adapter->winner = 1; - } return ret; } @@ -2620,6 +2624,7 @@ static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, .check_fw_status = mwifiex_check_fw_status, + .check_winner_status = mwifiex_check_winner_status, .prog_fw = mwifiex_prog_fw_w_helper, .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, -- cgit v1.2.3 From dc386ce76dedaeeaaf006fceb6ed8cf2e20ff026 Mon Sep 17 00:00:00 2001 From: chunfan chen Date: Wed, 6 Jan 2016 23:40:48 -0800 Subject: mwifiex: fix IBSS data path issue. The port_open flag is not applicable for IBSS mode. IBSS data path was broken when port_open flag was introduced. This patch fixes the problem by correcting the checks. Fixes: 5c8946330abfa4c ("mwifiex: enable traffic only when port is open") Signed-off-by: chunfan chen Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sta_event.c | 10 ++++++---- drivers/net/wireless/marvell/mwifiex/wmm.c | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index ff3ee9dfbbd5..23bae87d4d3d 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -607,11 +607,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PS_AWAKE: mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n"); - if (!adapter->pps_uapsd_mode && priv->port_open && + if (!adapter->pps_uapsd_mode && + (priv->port_open || + (priv->bss_mode == NL80211_IFTYPE_ADHOC)) && priv->media_connected && adapter->sleep_period.period) { - adapter->pps_uapsd_mode = true; - mwifiex_dbg(adapter, EVENT, - "event: PPS/UAPSD mode activated\n"); + adapter->pps_uapsd_mode = true; + mwifiex_dbg(adapter, EVENT, + "event: PPS/UAPSD mode activated\n"); } adapter->tx_lock_flag = false; if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index acccd6734e3b..499e5a741c62 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -475,7 +475,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) priv = adapter->priv[i]; if (!priv) continue; - if (!priv->port_open) + if (!priv->port_open && + (priv->bss_mode != NL80211_IFTYPE_ADHOC)) continue; if (adapter->if_ops.is_port_ready && !adapter->if_ops.is_port_ready(priv)) @@ -1099,7 +1100,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv; - if (!priv_tmp->port_open || + if (((priv_tmp->bss_mode != NL80211_IFTYPE_ADHOC) && + !priv_tmp->port_open) || (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)) continue; -- cgit v1.2.3 From 17934b6a32b2fdfcc0a9e83d17c780f15627aa30 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 6 Jan 2016 23:40:49 -0800 Subject: mwifiex: add debugfs file to read chip information This patch add 'verext' debugfs item, which can be used to get detailed chip specific information from our firmware. Examples: echo "1" > /sys/kernel/debug/mwifiex/mlan0/verext cat /sys/kernel/debug/mwifiex/mlan0/verext Signed-off-by: Shengzhen Li Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/README | 10 +++++ drivers/net/wireless/marvell/mwifiex/debugfs.c | 51 +++++++++++++++++++++++- drivers/net/wireless/marvell/mwifiex/main.h | 3 +- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 3 +- 4 files changed, 63 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/README b/drivers/net/wireless/marvell/mwifiex/README index 2f0f9b5609d0..24e649b1eb24 100644 --- a/drivers/net/wireless/marvell/mwifiex/README +++ b/drivers/net/wireless/marvell/mwifiex/README @@ -237,4 +237,14 @@ device_dump cat fw_dump +verext + This command is used to get extended firmware version string using + different configuration parameters. + + Usage: + echo "[version_str_sel]" > verext + cat verext + + [version_str_sel]: firmware support several extend version + string cases, include 0/1/10/20/21/99 =============================================================================== diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index 0b9c580af988..df28836a1d11 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -95,8 +95,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf, mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); - if (!priv->version_str[0]) - mwifiex_get_ver_ext(priv); + mwifiex_get_ver_ext(priv, 0); p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); p += sprintf(p, "driver_version = %s", fmt); @@ -583,6 +582,52 @@ done: return ret; } +/* debugfs verext file write handler. + * This function is called when the 'verext' file is opened for write + */ +static ssize_t +mwifiex_verext_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + int ret; + u32 versionstrsel; + struct mwifiex_private *priv = (void *)file->private_data; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = kstrtou32(buf, 10, &versionstrsel); + if (ret) + return ret; + + priv->versionstrsel = versionstrsel; + + return count; +} + +/* Proc verext file read handler. + * This function is called when the 'verext' file is opened for reading + * This function can be used read driver exteneed verion string. + */ +static ssize_t +mwifiex_verext_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *)file->private_data; + char buf[256]; + int ret; + + mwifiex_get_ver_ext(priv, priv->versionstrsel); + ret = snprintf(buf, sizeof(buf), "version string: %s\n", + priv->version_str); + + return simple_read_from_buffer(ubuf, count, ppos, buf, ret); +} + /* Proc memrw file write handler. * This function is called when the 'memrw' file is opened for writing * This function can be used to write to a memory location. @@ -940,6 +985,7 @@ MWIFIEX_DFS_FILE_OPS(histogram); MWIFIEX_DFS_FILE_OPS(debug_mask); MWIFIEX_DFS_FILE_OPS(timeshare_coex); MWIFIEX_DFS_FILE_WRITE_OPS(reset); +MWIFIEX_DFS_FILE_OPS(verext); /* * This function creates the debug FS directory structure and the files. @@ -968,6 +1014,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(debug_mask); MWIFIEX_DFS_ADD_FILE(timeshare_coex); MWIFIEX_DFS_ADD_FILE(reset); + MWIFIEX_DFS_ADD_FILE(verext); } /* diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index c08be798905f..35ab052c8a36 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -616,6 +616,7 @@ struct mwifiex_private { spinlock_t curr_bcn_buf_lock; struct wireless_dev wdev; struct mwifiex_chan_freq_power cfp; + u32 versionstrsel; char version_str[128]; #ifdef CONFIG_DEBUG_FS struct dentry *dfs_dev_dir; @@ -1418,7 +1419,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp, int mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len); -int mwifiex_get_ver_ext(struct mwifiex_private *priv); +int mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel); int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 6a4fc5d183cf..210b257aad6b 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -1114,11 +1114,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp, * with requisite parameters and calls the IOCTL handler. */ int -mwifiex_get_ver_ext(struct mwifiex_private *priv) +mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel) { struct mwifiex_ver_ext ver_ext; memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); + ver_ext.version_str_sel = version_str_sel; if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT, HostCmd_ACT_GEN_GET, 0, &ver_ext, true)) return -1; -- cgit v1.2.3 From 68f37e5d7a2e00306adab033fba6c3042b33e8e1 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 7 Jan 2016 14:28:50 +0100 Subject: wlcore: fix error handling in wlcore_event_fw_logger wlcore_read/wlcore_write can return negative values so it should be assigned to signed variable. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2120705 Fixes: 3719c17e1816 ("wlcore/wl18xx: fw logger over sdio") Signed-off-by: Andrzej Hajda Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index c96405498bf4..4b59f67724de 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -38,7 +38,7 @@ int wlcore_event_fw_logger(struct wl1271 *wl) { - u32 ret; + int ret; struct fw_logger_information fw_log; u8 *buffer; u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS; -- cgit v1.2.3 From 99074fc1e67b374b5c72406a23ac01fed806d634 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 11 Jan 2016 02:16:40 -0800 Subject: mwifiex: enable pcie MSIx interrupt mode support Newer pcie chipsets (8997 onwards) support MSIx. This patch enables it. Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 187 +++++++++++++++++++++++----- drivers/net/wireless/marvell/mwifiex/pcie.h | 17 +++ 2 files changed, 176 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index f448d7ca4e7c..5e154649c6a2 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2082,20 +2082,28 @@ mwifiex_check_winner_status(struct mwifiex_adapter *adapter) /* * This function reads the interrupt status from card. */ -static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) +static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter, + int msg_id) { u32 pcie_ireg; unsigned long flags; + struct pcie_service_card *card = adapter->card; if (!mwifiex_pcie_ok_to_access_hw(adapter)) return; - if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) { - mwifiex_dbg(adapter, ERROR, "Read register failed\n"); - return; - } + if (card->msix_enable && msg_id >= 0) { + pcie_ireg = BIT(msg_id); + } else { + if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, + &pcie_ireg)) { + mwifiex_dbg(adapter, ERROR, "Read register failed\n"); + return; + } + + if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg) + return; - if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) { mwifiex_pcie_disable_host_int(adapter); @@ -2106,20 +2114,23 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) "Write register failed\n"); return; } - spin_lock_irqsave(&adapter->int_lock, flags); - adapter->int_status |= pcie_ireg; - spin_unlock_irqrestore(&adapter->int_lock, flags); - - if (!adapter->pps_uapsd_mode && - adapter->ps_state == PS_STATE_SLEEP && - mwifiex_pcie_ok_to_access_hw(adapter)) { - /* Potentially for PCIe we could get other - * interrupts like shared. Don't change power - * state until cookie is set */ - adapter->ps_state = PS_STATE_AWAKE; - adapter->pm_wakeup_fw_try = false; - del_timer(&adapter->wakeup_timer); - } + } + + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= pcie_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg); + + if (!adapter->pps_uapsd_mode && + adapter->ps_state == PS_STATE_SLEEP && + mwifiex_pcie_ok_to_access_hw(adapter)) { + /* Potentially for PCIe we could get other + * interrupts like shared. Don't change power + * state until cookie is set + */ + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_fw_try = false; + del_timer(&adapter->wakeup_timer); } } @@ -2131,7 +2142,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) */ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) { - struct pci_dev *pdev = (struct pci_dev *)context; + struct mwifiex_msix_context *ctx = context; + struct pci_dev *pdev = ctx->dev; struct pcie_service_card *card; struct mwifiex_adapter *adapter; @@ -2151,7 +2163,11 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) if (adapter->surprise_removed) goto exit; - mwifiex_interrupt_status(adapter); + if (card->msix_enable) + mwifiex_interrupt_status(adapter, ctx->msg_id); + else + mwifiex_interrupt_status(adapter, -1); + mwifiex_queue_main_work(adapter); exit: @@ -2171,7 +2187,7 @@ exit: * In case of Rx packets received, the packets are uploaded from card to * host and processed accordingly. */ -static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) +static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) { int ret; u32 pcie_ireg; @@ -2251,6 +2267,69 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) return 0; } +static int mwifiex_process_msix_int(struct mwifiex_adapter *adapter) +{ + int ret; + u32 pcie_ireg; + unsigned long flags; + + spin_lock_irqsave(&adapter->int_lock, flags); + /* Clear out unused interrupts */ + pcie_ireg = adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + if (pcie_ireg & HOST_INTR_DNLD_DONE) { + mwifiex_dbg(adapter, INTR, + "info: TX DNLD Done\n"); + ret = mwifiex_pcie_send_data_complete(adapter); + if (ret) + return ret; + } + if (pcie_ireg & HOST_INTR_UPLD_RDY) { + mwifiex_dbg(adapter, INTR, + "info: Rx DATA\n"); + ret = mwifiex_pcie_process_recv_data(adapter); + if (ret) + return ret; + } + if (pcie_ireg & HOST_INTR_EVENT_RDY) { + mwifiex_dbg(adapter, INTR, + "info: Rx EVENT\n"); + ret = mwifiex_pcie_process_event_ready(adapter); + if (ret) + return ret; + } + + if (pcie_ireg & HOST_INTR_CMD_DONE) { + if (adapter->cmd_sent) { + mwifiex_dbg(adapter, INTR, + "info: CMD sent Interrupt\n"); + adapter->cmd_sent = false; + } + /* Handle command response */ + ret = mwifiex_pcie_process_cmd_complete(adapter); + if (ret) + return ret; + } + + mwifiex_dbg(adapter, INTR, + "info: cmd_sent=%d data_sent=%d\n", + adapter->cmd_sent, adapter->data_sent); + + return 0; +} + +static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + if (card->msix_enable) + return mwifiex_process_msix_int(adapter); + else + return mwifiex_process_pcie_int(adapter); +} + /* * This function downloads data from driver to card. * @@ -2602,10 +2681,43 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) { - int ret; + int ret, i, j; struct pcie_service_card *card = adapter->card; struct pci_dev *pdev = card->dev; + if (card->pcie.reg->msix_support) { + for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) + card->msix_entries[i].entry = i; + ret = pci_enable_msix_exact(pdev, card->msix_entries, + MWIFIEX_NUM_MSIX_VECTORS); + if (!ret) { + for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) { + card->msix_ctx[i].dev = pdev; + card->msix_ctx[i].msg_id = i; + + ret = request_irq(card->msix_entries[i].vector, + mwifiex_pcie_interrupt, 0, + "MWIFIEX_PCIE_MSIX", + &card->msix_ctx[i]); + if (ret) + break; + } + + if (ret) { + mwifiex_dbg(adapter, INFO, "request_irq fail: %d\n", + ret); + for (j = 0; j < i; j++) + free_irq(card->msix_entries[j].vector, + &card->msix_ctx[i]); + pci_disable_msix(pdev); + } else { + mwifiex_dbg(adapter, MSG, "MSIx enabled!"); + card->msix_enable = 1; + return 0; + } + } + } + if (pci_enable_msi(pdev) != 0) pci_disable_msi(pdev); else @@ -2613,8 +2725,10 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable); + card->share_irq_ctx.dev = pdev; + card->share_irq_ctx.msg_id = -1; ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED, - "MRVL_PCIE", pdev); + "MRVL_PCIE", &card->share_irq_ctx); if (ret) { pr_err("request_irq failed: ret=%d\n", ret); adapter->card = NULL; @@ -2660,11 +2774,28 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg; + struct pci_dev *pdev = card->dev; + int i; if (card) { - mwifiex_dbg(adapter, INFO, - "%s(): calling free_irq()\n", __func__); - free_irq(card->dev->irq, card->dev); + if (card->msix_enable) { + for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) + synchronize_irq(card->msix_entries[i].vector); + + for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) + free_irq(card->msix_entries[i].vector, + &card->msix_ctx[i]); + + card->msix_enable = 0; + pci_disable_msix(pdev); + } else { + mwifiex_dbg(adapter, INFO, + "%s(): calling free_irq()\n", __func__); + free_irq(card->dev->irq, &card->share_irq_ctx); + + if (card->msi_enable) + pci_disable_msi(pdev); + } reg = card->pcie.reg; if (reg->sleep_cookie) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 6fc28737b576..9700ac355e55 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -135,6 +135,7 @@ struct mwifiex_pcie_card_reg { u16 fw_dump_ctrl; u16 fw_dump_start; u16 fw_dump_end; + u8 msix_support; }; static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { @@ -166,6 +167,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { .ring_tx_start_ptr = 0, .pfu_enabled = 0, .sleep_cookie = 1, + .msix_support = 0, }; static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { @@ -200,6 +202,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { .fw_dump_ctrl = 0xcf4, .fw_dump_start = 0xcf8, .fw_dump_end = 0xcff, + .msix_support = 0, }; static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { @@ -231,6 +234,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, + .msix_support = 1, }; struct mwifiex_pcie_device { @@ -290,6 +294,13 @@ struct mwifiex_pfu_buf_desc { u32 reserved; } __packed; +#define MWIFIEX_NUM_MSIX_VECTORS 4 + +struct mwifiex_msix_context { + struct pci_dev *dev; + u16 msg_id; +}; + struct pcie_service_card { struct pci_dev *dev; struct mwifiex_adapter *adapter; @@ -327,6 +338,12 @@ struct pcie_service_card { void __iomem *pci_mmap; void __iomem *pci_mmap1; int msi_enable; + int msix_enable; +#ifdef CONFIG_PCI + struct msix_entry msix_entries[MWIFIEX_NUM_MSIX_VECTORS]; +#endif + struct mwifiex_msix_context msix_ctx[MWIFIEX_NUM_MSIX_VECTORS]; + struct mwifiex_msix_context share_irq_ctx; }; static inline int -- cgit v1.2.3 From dc896b15fe94345912ff13fa8eb581b5c6acccde Mon Sep 17 00:00:00 2001 From: Shengzhen Li Date: Tue, 12 Jan 2016 05:43:16 -0800 Subject: mwifiex: fix power state out of sync problem It's been observed that driver's power state goes out of sync with firmware in some corner cases. When this happens, driver tries to download the data to firmware assuming it's awake which causes Tx data timeout. Main thread will process interrupt as soon as interrupt handler fills 'int_status' variable. This patch fixes the race issue by updating 'int_status' at the end of mwifiex_interrupt_status(). Signed-off-by: Shengzhen Li Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 5e154649c6a2..918e04954afe 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2116,11 +2116,6 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter, } } - spin_lock_irqsave(&adapter->int_lock, flags); - adapter->int_status |= pcie_ireg; - spin_unlock_irqrestore(&adapter->int_lock, flags); - mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg); - if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP && mwifiex_pcie_ok_to_access_hw(adapter)) { @@ -2132,6 +2127,11 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter, adapter->pm_wakeup_fw_try = false; del_timer(&adapter->wakeup_timer); } + + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= pcie_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg); } /* -- cgit v1.2.3 From 0c9b7f22e8e1f3aa5b88d7530db8b3a7d647adb6 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 13 Jan 2016 01:26:52 -0800 Subject: mwifiex: add schedule scan support This patch add sched scan support for mwifiex, include cfg80211 sched_scan_start/sched_scan_stop handler, corresponding bgscan command path and event handler. Signed-off-by: Xinming Hu Signed-off-by: chunfan chen Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 134 +++++++++++ drivers/net/wireless/marvell/mwifiex/fw.h | 59 +++++ drivers/net/wireless/marvell/mwifiex/ioctl.h | 1 + drivers/net/wireless/marvell/mwifiex/main.c | 7 + drivers/net/wireless/marvell/mwifiex/main.h | 10 + drivers/net/wireless/marvell/mwifiex/scan.c | 261 +++++++++++++++++++++ drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 4 + drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c | 3 + drivers/net/wireless/marvell/mwifiex/sta_event.c | 7 + drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 7 + 10 files changed, 493 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index e7adef72c05f..c27c6cc5f93e 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + if (!mwifiex_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); + if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; @@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, "info: Trying to associate to %s and bssid %pM\n", (char *)sme->ssid, sme->bssid); + if (!mwifiex_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); + ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, priv->bss_mode, sme->channel, sme, 0); if (!ret) { @@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, return -EBUSY; } + if (!mwifiex_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); + user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); if (!user_scan_cfg) return -ENOMEM; @@ -2487,6 +2496,121 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, return 0; } +/* CFG802.11 operation handler for sched_scan_start. + * + * This function issues a bgscan config request to the firmware based upon + * the user specified sched_scan configuration. On successful completion, + * firmware will generate BGSCAN_REPORT event, driver should issue bgscan + * query command to get sched_scan results from firmware. + */ +static int +mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int i, offset; + struct ieee80211_channel *chan; + struct mwifiex_bg_scan_cfg *bgscan_cfg; + struct ieee_types_header *ie; + + if (!request || (!request->n_ssids && !request->n_match_sets)) { + wiphy_err(wiphy, "%s : Invalid Sched_scan parameters", + __func__); + return -EINVAL; + } + + wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ", + request->n_ssids, request->n_match_sets); + wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n", + request->n_channels, request->scan_plans->interval, + (int)request->ie_len); + + bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL); + if (!bgscan_cfg) + return -ENOMEM; + + if (priv->scan_request || priv->scan_aborting) + bgscan_cfg->start_later = true; + + bgscan_cfg->num_ssids = request->n_match_sets; + bgscan_cfg->ssid_list = request->match_sets; + + if (request->ie && request->ie_len) { + offset = 0; + for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { + if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR) + continue; + priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_BGSCAN; + ie = (struct ieee_types_header *)(request->ie + offset); + memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len); + offset += sizeof(*ie) + ie->len; + + if (offset >= request->ie_len) + break; + } + } + + for (i = 0; i < min_t(u32, request->n_channels, + MWIFIEX_BG_SCAN_CHAN_MAX); i++) { + chan = request->channels[i]; + bgscan_cfg->chan_list[i].chan_number = chan->hw_value; + bgscan_cfg->chan_list[i].radio_type = chan->band; + + if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) + bgscan_cfg->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_PASSIVE; + else + bgscan_cfg->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_ACTIVE; + + bgscan_cfg->chan_list[i].scan_time = 0; + } + + bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels, + MWIFIEX_BG_SCAN_CHAN_MAX); + + /* Use at least 15 second for per scan cycle */ + bgscan_cfg->scan_interval = (request->scan_plans->interval > + MWIFIEX_BGSCAN_INTERVAL) ? + request->scan_plans->interval : + MWIFIEX_BGSCAN_INTERVAL; + + bgscan_cfg->repeat_count = MWIFIEX_BGSCAN_REPEAT_COUNT; + bgscan_cfg->report_condition = MWIFIEX_BGSCAN_SSID_MATCH | + MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE; + bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA; + bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET; + bgscan_cfg->enable = true; + + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG, + HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) { + kfree(bgscan_cfg); + return -EFAULT; + } + + priv->sched_scanning = true; + + kfree(bgscan_cfg); + return 0; +} + +/* CFG802.11 operation handler for sched_scan_stop. + * + * This function issues a bgscan config command to disable + * previous bgscan configuration in the firmware + */ +static int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + wiphy_info(wiphy, "sched scan stop!"); + mwifiex_stop_bg_scan(priv); + + return 0; +} + static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info, struct mwifiex_private *priv) { @@ -2848,6 +2972,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) mwifiex_dev_debugfs_remove(priv); #endif + if (priv->sched_scanning) + priv->sched_scanning = false; + mwifiex_stop_net_dev_queue(priv->netdev, adapter); skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) @@ -3701,6 +3828,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, .set_antenna = mwifiex_cfg80211_set_antenna, .del_station = mwifiex_cfg80211_del_station, + .sched_scan_start = mwifiex_cfg80211_sched_scan_start, + .sched_scan_stop = mwifiex_cfg80211_sched_scan_stop, #ifdef CONFIG_PM .suspend = mwifiex_cfg80211_suspend, .resume = mwifiex_cfg80211_resume, @@ -3829,6 +3958,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_SUPPORTS_SCHED_SCAN | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -3847,6 +3977,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; + wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; + wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH; + wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 426e76ade30c..07bdc2a96b8a 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) +#define TLV_TYPE_BGSCAN_START_LATER (PROPRIETARY_TLV_BASE_ID + 30) #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) #define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32) #define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35) @@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 176) #define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183) #define TLV_TYPE_MC_GROUP_INFO (PROPRIETARY_TLV_BASE_ID + 184) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) @@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D #define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b #define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e +#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b #define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c #define HostCmd_CMD_WMM_GET_STATUS 0x0071 #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 @@ -523,6 +526,7 @@ enum P2P_MODES { #define EVENT_CHANNEL_REPORT_RDY 0x00000054 #define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 +#define EVENT_BG_SCAN_STOPPED 0x00000065 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_MULTI_CHAN_INFO 0x0000006a #define EVENT_TX_STATUS_REPORT 0x00000074 @@ -733,6 +737,16 @@ struct mwifiex_ie_types_num_probes { __le16 num_probes; } __packed; +struct mwifiex_ie_types_repeat_count { + struct mwifiex_ie_types_header header; + __le16 repeat_count; +} __packed; + +struct mwifiex_ie_types_bgscan_start_later { + struct mwifiex_ie_types_header header; + __le16 start_later; +} __packed; + struct mwifiex_ie_types_scan_chan_gap { struct mwifiex_ie_types_header header; /* time gap in TUs to be used between two consecutive channels scan */ @@ -1425,6 +1439,36 @@ struct mwifiex_user_scan_cfg { u16 scan_chan_gap; } __packed; +#define MWIFIEX_BG_SCAN_CHAN_MAX 38 +#define MWIFIEX_BSS_MODE_INFRA 1 +#define MWIFIEX_BGSCAN_ACT_GET 0x0000 +#define MWIFIEX_BGSCAN_ACT_SET 0x0001 +#define MWIFIEX_BGSCAN_ACT_SET_ALL 0xff01 +/** ssid match */ +#define MWIFIEX_BGSCAN_SSID_MATCH 0x0001 +/** ssid match and RSSI exceeded */ +#define MWIFIEX_BGSCAN_SSID_RSSI_MATCH 0x0004 +/**wait for all channel scan to complete to report scan result*/ +#define MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE 0x80000000 + +struct mwifiex_bg_scan_cfg { + u16 action; + u8 enable; + u8 bss_type; + u8 chan_per_scan; + u32 scan_interval; + u32 report_condition; + u8 num_probes; + u8 rssi_threshold; + u8 snr_threshold; + u16 repeat_count; + u16 start_later; + struct cfg80211_match_set *ssid_list; + u8 num_ssids; + struct mwifiex_user_scan_chan chan_list[MWIFIEX_BG_SCAN_CHAN_MAX]; + u16 scan_chan_gap; +} __packed; + struct ie_body { u8 grp_key_oui[4]; u8 ptk_cnt[2]; @@ -1470,6 +1514,20 @@ struct mwifiex_ie_types_bss_scan_info { __le64 tsf; } __packed; +struct host_cmd_ds_802_11_bg_scan_config { + __le16 action; + u8 enable; + u8 bss_type; + u8 chan_per_scan; + u8 reserved; + __le16 reserved1; + __le32 scan_interval; + __le32 reserved2; + __le32 report_condition; + __le16 reserved3; + u8 tlv[0]; +} __packed; + struct host_cmd_ds_802_11_bg_scan_query { u8 flush; } __packed; @@ -2124,6 +2182,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_802_11_scan scan; struct host_cmd_ds_802_11_scan_ext ext_scan; struct host_cmd_ds_802_11_scan_rsp scan_resp; + struct host_cmd_ds_802_11_bg_scan_config bg_scan_config; struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; struct host_cmd_ds_802_11_associate associate; diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 4f0174c64946..6333b163acef 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -414,6 +414,7 @@ struct mwifiex_ds_mef_cfg { #define MWIFIEX_VSIE_MASK_SCAN 0x01 #define MWIFIEX_VSIE_MASK_ASSOC 0x02 #define MWIFIEX_VSIE_MASK_ADHOC 0x04 +#define MWIFIEX_VSIE_MASK_BGSCAN 0x08 enum { MWIFIEX_FUNC_INIT = 1, diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 79c16de8743e..a99b72bbde51 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -746,6 +746,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) mwifiex_queue_main_work(priv->adapter); + if (priv->sched_scanning) { + mwifiex_dbg(priv->adapter, INFO, + "aborting bgscan on ndo_stop\n"); + mwifiex_stop_bg_scan(priv); + cfg80211_sched_scan_stopped(priv->wdev.wiphy); + } + return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 35ab052c8a36..5f5bcf8b9fc9 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -198,6 +198,11 @@ do { \ buf, len, false); \ } while (0) +/** Min BGSCAN interval 15 second */ +#define MWIFIEX_BGSCAN_INTERVAL 15000 +/** default repeat count */ +#define MWIFIEX_BGSCAN_REPEAT_COUNT 6 + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -641,6 +646,7 @@ struct mwifiex_private { u32 mgmt_frame_mask; struct mwifiex_roc_cfg roc_cfg; bool scan_aborting; + u8 sched_scanning; u8 csa_chan; unsigned long csa_expire_time; u8 del_list_idx; @@ -1198,6 +1204,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv, void *buf); +int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_stop_bg_scan(struct mwifiex_private *priv); /* * This function checks if the queuing is RA based or not. diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index c20017ced566..d4e214385f54 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -547,6 +547,61 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, return chan_idx; } +/* This function creates a channel list tlv for bgscan config, based + * on region/band information. + */ +static int +mwifiex_bgscan_create_channel_list(struct mwifiex_private *priv, + const struct mwifiex_bg_scan_cfg + *bgscan_cfg_in, + struct mwifiex_chan_scan_param_set + *scan_chan_list) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_adapter *adapter = priv->adapter; + int chan_idx = 0, i; + + for (band = 0; (band < IEEE80211_NUM_BANDS); band++) { + if (!priv->wdev.wiphy->bands[band]) + continue; + + sband = priv->wdev.wiphy->bands[band]; + + for (i = 0; (i < sband->n_channels) ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + scan_chan_list[chan_idx].radio_type = band; + + if (bgscan_cfg_in->chan_list[0].scan_time) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16((u16)bgscan_cfg_in-> + chan_list[0].scan_time); + else if (ch->flags & IEEE80211_CHAN_NO_IR) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->passive_scan_time); + else + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter-> + specific_scan_time); + + if (ch->flags & IEEE80211_CHAN_NO_IR) + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + scan_chan_list[chan_idx].chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + + scan_chan_list[chan_idx].chan_number = + (u32)ch->hw_value; + chan_idx++; + } + } + return chan_idx; +} + /* This function appends rate TLV to scan config command. */ static int mwifiex_append_rate_tlv(struct mwifiex_private *priv, @@ -2155,6 +2210,212 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, return 0; } +/* This function prepares an background scan config command to be sent + * to the firmware + */ +int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_bg_scan_config *bgscan_config = + &cmd->params.bg_scan_config; + struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf; + u8 *tlv_pos = bgscan_config->tlv; + u8 num_probes; + u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num; + int i; + struct mwifiex_ie_types_num_probes *num_probes_tlv; + struct mwifiex_ie_types_repeat_count *repeat_count_tlv; + struct mwifiex_ie_types_bgscan_start_later *start_later_tlv; + struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; + struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv; + struct mwifiex_chan_scan_param_set *temp_chan; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG); + cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN); + + bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action); + bgscan_config->enable = bgscan_cfg_in->enable; + bgscan_config->bss_type = bgscan_cfg_in->bss_type; + bgscan_config->scan_interval = + cpu_to_le32(bgscan_cfg_in->scan_interval); + bgscan_config->report_condition = + cpu_to_le32(bgscan_cfg_in->report_condition); + + /* stop sched scan */ + if (!bgscan_config->enable) + return 0; + + bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan; + + num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in-> + num_probes : priv->adapter->scan_probes); + + if (num_probes) { + num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos; + num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); + num_probes_tlv->header.len = + cpu_to_le16(sizeof(num_probes_tlv->num_probes)); + num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes); + + tlv_pos += sizeof(num_probes_tlv->header) + + le16_to_cpu(num_probes_tlv->header.len); + } + + if (bgscan_cfg_in->repeat_count) { + repeat_count_tlv = + (struct mwifiex_ie_types_repeat_count *)tlv_pos; + repeat_count_tlv->header.type = + cpu_to_le16(TLV_TYPE_REPEAT_COUNT); + repeat_count_tlv->header.len = + cpu_to_le16(sizeof(repeat_count_tlv->repeat_count)); + repeat_count_tlv->repeat_count = + cpu_to_le16(bgscan_cfg_in->repeat_count); + + tlv_pos += sizeof(repeat_count_tlv->header) + + le16_to_cpu(repeat_count_tlv->header.len); + } + + for (i = 0; i < bgscan_cfg_in->num_ssids; i++) { + ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len; + + wildcard_ssid_tlv = + (struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos; + wildcard_ssid_tlv->header.type = + cpu_to_le16(TLV_TYPE_WILDCARDSSID); + wildcard_ssid_tlv->header.len = cpu_to_le16( + (u16)(ssid_len + sizeof(wildcard_ssid_tlv-> + max_ssid_length))); + + /* max_ssid_length = 0 tells firmware to perform + * specific scan for the SSID filled, whereas + * max_ssid_length = IEEE80211_MAX_SSID_LEN is for + * wildcard scan. + */ + if (ssid_len) + wildcard_ssid_tlv->max_ssid_length = 0; + else + wildcard_ssid_tlv->max_ssid_length = + IEEE80211_MAX_SSID_LEN; + + memcpy(wildcard_ssid_tlv->ssid, + bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len); + + tlv_pos += (sizeof(wildcard_ssid_tlv->header) + + le16_to_cpu(wildcard_ssid_tlv->header.len)); + } + + chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos; + + if (bgscan_cfg_in->chan_list[0].chan_number) { + dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n"); + + chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + for (chan_idx = 0; + chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX && + bgscan_cfg_in->chan_list[chan_idx].chan_number; + chan_idx++) { + temp_chan = chan_list_tlv->chan_scan_param + chan_idx; + + /* Increment the TLV header length by size appended */ + le16_add_cpu(&chan_list_tlv->header.len, + sizeof(chan_list_tlv->chan_scan_param)); + + temp_chan->chan_number = + bgscan_cfg_in->chan_list[chan_idx].chan_number; + temp_chan->radio_type = + bgscan_cfg_in->chan_list[chan_idx].radio_type; + + scan_type = + bgscan_cfg_in->chan_list[chan_idx].scan_type; + + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + temp_chan->chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + temp_chan->chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + + if (bgscan_cfg_in->chan_list[chan_idx].scan_time) { + scan_dur = (u16)bgscan_cfg_in-> + chan_list[chan_idx].scan_time; + } else { + scan_dur = (scan_type == + MWIFIEX_SCAN_TYPE_PASSIVE) ? + priv->adapter->passive_scan_time : + priv->adapter->specific_scan_time; + } + + temp_chan->min_scan_time = cpu_to_le16(scan_dur); + temp_chan->max_scan_time = cpu_to_le16(scan_dur); + } + } else { + dev_dbg(priv->adapter->dev, + "info: bgscan: Creating full region channel list\n"); + chan_num = + mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in, + chan_list_tlv-> + chan_scan_param); + le16_add_cpu(&chan_list_tlv->header.len, + chan_num * + sizeof(chan_list_tlv->chan_scan_param[0])); + } + + tlv_pos += (sizeof(chan_list_tlv->header) + + le16_to_cpu(chan_list_tlv->header.len)); + + if (bgscan_cfg_in->start_later) { + start_later_tlv = + (struct mwifiex_ie_types_bgscan_start_later *)tlv_pos; + start_later_tlv->header.type = + cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER); + start_later_tlv->header.len = + cpu_to_le16(sizeof(start_later_tlv->start_later)); + start_later_tlv->start_later = + cpu_to_le16(bgscan_cfg_in->start_later); + + tlv_pos += sizeof(start_later_tlv->header) + + le16_to_cpu(start_later_tlv->header.len); + } + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos); + + le16_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv); + + return 0; +} + +int mwifiex_stop_bg_scan(struct mwifiex_private *priv) +{ + struct mwifiex_bg_scan_cfg *bgscan_cfg; + + if (!priv->sched_scanning) { + dev_dbg(priv->adapter->dev, "bgscan already stopped!\n"); + return 0; + } + + bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL); + if (!bgscan_cfg) + return -ENOMEM; + + bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA; + bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET; + bgscan_cfg->enable = false; + + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG, + HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) { + kfree(bgscan_cfg); + return -EFAULT; + } + + kfree(bgscan_cfg); + priv->sched_scanning = false; + + return 0; +} + static void mwifiex_update_chan_statistics(struct mwifiex_private *priv, struct mwifiex_ietypes_chanstats *tlv_stat) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index e486867a4c67..60f3ded747c9 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1873,6 +1873,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_802_11_SCAN: ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); break; + case HostCmd_CMD_802_11_BG_SCAN_CONFIG: + ret = mwifiex_cmd_802_11_bg_scan_config(priv, cmd_ptr, + data_buf); + break; case HostCmd_CMD_802_11_BG_SCAN_QUERY: ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); break; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 9ac7aa2431b4..4b23d3b95a20 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1076,9 +1076,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_802_11_BG_SCAN_QUERY: ret = mwifiex_ret_802_11_scan(priv, resp); + cfg80211_sched_scan_results(priv->wdev.wiphy); mwifiex_dbg(adapter, CMD, "info: CMD_RESP: BG_SCAN result is ready!\n"); break; + case HostCmd_CMD_802_11_BG_SCAN_CONFIG: + break; case HostCmd_CMD_TXPWR_CFG: ret = mwifiex_ret_tx_power_cfg(priv, resp); break; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 23bae87d4d3d..fd8061c73091 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -688,6 +688,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) HostCmd_ACT_GEN_GET, 0, NULL, false); break; + case EVENT_BG_SCAN_STOPPED: + dev_dbg(adapter->dev, "event: BGS_STOPPED\n"); + cfg80211_sched_scan_stopped(priv->wdev.wiphy); + if (priv->sched_scanning) + priv->sched_scanning = false; + break; + case EVENT_PORT_RELEASE: mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n"); priv->port_open = true; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 210b257aad6b..2cc1a32691bd 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -504,6 +504,13 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) } } + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + if (priv && priv->sched_scanning) { + dev_dbg(adapter->dev, "aborting bgscan!\n"); + mwifiex_stop_bg_scan(priv); + cfg80211_sched_scan_stopped(priv->wdev.wiphy); + } + if (adapter->hs_activated) { mwifiex_dbg(adapter, CMD, "cmd: HS Already activated\n"); -- cgit v1.2.3 From 5323b53d80fc17604b2c60b725af116827330b2c Mon Sep 17 00:00:00 2001 From: chunfan chen Date: Wed, 13 Jan 2016 01:26:53 -0800 Subject: mwifiex: add wowlan info messages This patch adds informative messages in wake up on magic packet, disconnect, pattern configuration paths. Signed-off-by: chunfan chen Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index c27c6cc5f93e..6d36d081e953 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3171,10 +3171,12 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, sizeof(byte_seq)); mef_entry->filter[filt_num].filt_type = TYPE_EQ; - if (first_pat) + if (first_pat) { first_pat = false; - else + mwifiex_dbg(priv->adapter, INFO, "Wake on patterns\n"); + } else { mef_entry->filter[filt_num].filt_action = TYPE_AND; + } filt_num++; } @@ -3200,6 +3202,7 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, mef_entry->filter[filt_num].offset = 56; mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_action = TYPE_OR; + mwifiex_dbg(priv->adapter, INFO, "Wake on magic packet\n"); } return ret; } @@ -3295,6 +3298,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, "Failed to set HS params\n"); return ret; } + mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n"); } return ret; -- cgit v1.2.3 From 7d7f07d8c5d35ebfb207650b0dbcf437dad76bab Mon Sep 17 00:00:00 2001 From: chunfan chen Date: Wed, 13 Jan 2016 01:26:54 -0800 Subject: mwifiex: add wowlan net-detect support This patch adds support for wakeup when configured network is detected. Signed-off-by: chunfan chen Signed-off-by: Amitkumar Karwar Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 40 +++++++++++++++--------- drivers/net/wireless/marvell/mwifiex/fw.h | 2 ++ drivers/net/wireless/marvell/mwifiex/main.c | 7 +++++ drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/scan.c | 34 ++++++++++++++++++++ drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 13 ++++++-- 6 files changed, 80 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 6d36d081e953..a1b8d89d399f 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3273,7 +3273,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); - if (!priv->media_connected) { + if (!priv->media_connected && !wowlan->nd_config) { mwifiex_dbg(adapter, ERROR, "Can not configure WOWLAN in disconnected state\n"); return 0; @@ -3285,22 +3285,32 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, return ret; } + memset(&hs_cfg, 0, sizeof(hs_cfg)); + hs_cfg.conditions = le32_to_cpu(adapter->hs_cfg.conditions); + + if (wowlan->nd_config) { + mwifiex_dbg(adapter, INFO, "Wake on net detect\n"); + hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; + mwifiex_cfg80211_sched_scan_start(wiphy, priv->netdev, + wowlan->nd_config); + } + if (wowlan->disconnect) { - memset(&hs_cfg, 0, sizeof(hs_cfg)); - hs_cfg.is_invoke_hostcmd = false; - hs_cfg.conditions = HS_CFG_COND_MAC_EVENT; - hs_cfg.gpio = adapter->hs_cfg.gpio; - hs_cfg.gap = adapter->hs_cfg.gap; - ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, - MWIFIEX_SYNC_CMD, &hs_cfg); - if (ret) { - mwifiex_dbg(adapter, ERROR, - "Failed to set HS params\n"); - return ret; - } + hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n"); } + hs_cfg.is_invoke_hostcmd = false; + hs_cfg.gpio = adapter->hs_cfg.gpio; + hs_cfg.gap = adapter->hs_cfg.gap; + ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + MWIFIEX_SYNC_CMD, &hs_cfg); + if (ret) { + mwifiex_dbg(adapter, ERROR, + "Failed to set HS params\n"); + return ret; + } + return ret; } @@ -3853,11 +3863,13 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { #ifdef CONFIG_PM static const struct wiphy_wowlan_support mwifiex_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_NET_DETECT, .n_patterns = MWIFIEX_MEF_MAX_FILTERS, .pattern_min_len = 1, .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, + .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS, }; #endif diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 07bdc2a96b8a..81b491aac343 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -543,6 +543,8 @@ enum P2P_MODES { #define MWIFIEX_MAX_PATTERN_LEN 40 #define MWIFIEX_MAX_OFFSET_LEN 100 +#define MWIFIEX_MAX_ND_MATCH_SETS 10 + #define STACK_NBYTES 100 #define TYPE_DNUM 1 #define TYPE_BYTESEQ 2 diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index a99b72bbde51..3cfa94677a8e 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -132,6 +132,13 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) } } + if (adapter->nd_info) { + for (i = 0 ; i < adapter->nd_info->n_matches ; i++) + kfree(adapter->nd_info->matches[i]); + kfree(adapter->nd_info); + adapter->nd_info = NULL; + } + vfree(adapter->chan_stats); kfree(adapter); return 0; diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 5f5bcf8b9fc9..bf9b24ae46fc 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1002,6 +1002,7 @@ struct mwifiex_adapter { u8 active_scan_triggered; bool usb_mc_status; bool usb_mc_setup; + struct cfg80211_wowlan_nd_info *nd_info; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index d4e214385f54..2702bd93f74d 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2092,6 +2092,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, u8 is_bgscan_resp; __le64 fw_tsf = 0; u8 *radio_type; + struct cfg80211_wowlan_nd_match *pmatch; + struct cfg80211_sched_scan_request *nd_config = NULL; is_bgscan_resp = (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_BG_SCAN_QUERY); @@ -2154,6 +2156,21 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, (struct mwifiex_ie_types_data **) &chan_band_tlv); +#ifdef CONFIG_PM + if (priv->wdev.wiphy->wowlan_config) + nd_config = priv->wdev.wiphy->wowlan_config->nd_config; +#endif + + if (nd_config) { + adapter->nd_info = + kzalloc(sizeof(struct cfg80211_wowlan_nd_match) + + sizeof(struct cfg80211_wowlan_nd_match *) * + scan_rsp->number_of_sets, GFP_ATOMIC); + + if (adapter->nd_info) + adapter->nd_info->n_matches = scan_rsp->number_of_sets; + } + for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { /* * If the TSF TLV was appended to the scan results, save this @@ -2172,6 +2189,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, radio_type = NULL; } + if (chan_band_tlv && adapter->nd_info) { + adapter->nd_info->matches[idx] = + kzalloc(sizeof(*pmatch) + + sizeof(u32), GFP_ATOMIC); + + pmatch = adapter->nd_info->matches[idx]; + + if (!pmatch) { + memset(pmatch, 0, sizeof(*pmatch)); + if (chan_band_tlv) { + pmatch->n_channels = 1; + pmatch->channels[0] = + chan_band->chan_number; + } + } + } + ret = mwifiex_parse_single_response_buf(priv, &bss_info, &bytes_left, le64_to_cpu(fw_tsf), diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 2cc1a32691bd..7277c24ee9aa 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -505,10 +505,17 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) } priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + if (priv && priv->sched_scanning) { - dev_dbg(adapter->dev, "aborting bgscan!\n"); - mwifiex_stop_bg_scan(priv); - cfg80211_sched_scan_stopped(priv->wdev.wiphy); +#ifdef CONFIG_PM + if (!priv->wdev.wiphy->wowlan_config->nd_config) { +#endif + mwifiex_dbg(adapter, CMD, "aborting bgscan!\n"); + mwifiex_stop_bg_scan(priv); + cfg80211_sched_scan_stopped(priv->wdev.wiphy); +#ifdef CONFIG_PM + } +#endif } if (adapter->hs_activated) { -- cgit v1.2.3 From 8de00f1b1c7f37e523430efba8e4257b2761df7c Mon Sep 17 00:00:00 2001 From: chunfan chen Date: Wed, 13 Jan 2016 01:26:55 -0800 Subject: mwifiex: report wakeup reason to cfg80211 This patch adds code to report wakeup reason to cfg80211 when system is resumed. Signed-off-by: chunfan chen Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 58 ++++++++++++++++++++++ drivers/net/wireless/marvell/mwifiex/cmdevt.c | 13 +++++ drivers/net/wireless/marvell/mwifiex/fw.h | 20 ++++++++ drivers/net/wireless/marvell/mwifiex/ioctl.h | 4 ++ drivers/net/wireless/marvell/mwifiex/main.h | 6 +++ drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 19 +++++++ drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c | 3 ++ drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 16 ++++++ 8 files changed, 139 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index a1b8d89d399f..c80d9e2daa16 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3316,6 +3316,64 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, static int mwifiex_cfg80211_resume(struct wiphy *wiphy) { + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + struct mwifiex_ds_wakeup_reason wakeup_reason; + struct cfg80211_wowlan_wakeup wakeup_report; + int i; + + mwifiex_get_wakeup_reason(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD, + &wakeup_reason); + memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup)); + + wakeup_report.pattern_idx = -1; + + switch (wakeup_reason.hs_wakeup_reason) { + case NO_HSWAKEUP_REASON: + break; + case BCAST_DATA_MATCHED: + break; + case MCAST_DATA_MATCHED: + break; + case UCAST_DATA_MATCHED: + break; + case MASKTABLE_EVENT_MATCHED: + break; + case NON_MASKABLE_EVENT_MATCHED: + if (wiphy->wowlan_config->disconnect) + wakeup_report.disconnect = true; + if (wiphy->wowlan_config->nd_config) + wakeup_report.net_detect = adapter->nd_info; + break; + case NON_MASKABLE_CONDITION_MATCHED: + break; + case MAGIC_PATTERN_MATCHED: + if (wiphy->wowlan_config->magic_pkt) + wakeup_report.magic_pkt = true; + if (wiphy->wowlan_config->n_patterns) + wakeup_report.pattern_idx = 1; + break; + case CONTROL_FRAME_MATCHED: + break; + case MANAGEMENT_FRAME_MATCHED: + break; + default: + break; + } + + if ((wakeup_reason.hs_wakeup_reason > 0) && + (wakeup_reason.hs_wakeup_reason <= 7)) + cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report, + GFP_KERNEL); + + if (adapter->nd_info) { + for (i = 0 ; i < adapter->nd_info->n_matches ; i++) + kfree(adapter->nd_info->matches[i]); + kfree(adapter->nd_info); + adapter->nd_info = NULL; + } + return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index cb25aa7e90db..a12adee776c6 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1657,3 +1657,16 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, return 0; } + +/* This function handles the command response of hs wakeup reason + * command. + */ +int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + struct host_cmd_ds_wakeup_reason *wakeup_reason) +{ + wakeup_reason->wakeup_reason = + resp->params.hs_wakeup_reason.wakeup_reason; + + return 0; +} diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 81b491aac343..d293e485189b 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -373,6 +373,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_MGMT_FRAME_REG 0x010c #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 +#define HostCmd_CMD_HS_WAKEUP_REASON 0x0116 #define HostCmd_CMD_TDLS_CONFIG 0x0100 #define HostCmd_CMD_MC_POLICY 0x0121 #define HostCmd_CMD_TDLS_OPER 0x0122 @@ -607,6 +608,20 @@ struct mwifiex_ie_types_data { #define MWIFIEX_RXPD_FLAGS_TDLS_PACKET 0x01 #define MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS 0x20 +enum HS_WAKEUP_REASON { + NO_HSWAKEUP_REASON = 0, + BCAST_DATA_MATCHED, + MCAST_DATA_MATCHED, + UCAST_DATA_MATCHED, + MASKTABLE_EVENT_MATCHED, + NON_MASKABLE_EVENT_MATCHED, + NON_MASKABLE_CONDITION_MATCHED, + MAGIC_PATTERN_MATCHED, + CONTROL_FRAME_MATCHED, + MANAGEMENT_FRAME_MATCHED, + RESERVED +}; + struct txpd { u8 bss_type; u8 bss_num; @@ -2159,6 +2174,10 @@ struct host_cmd_ds_robust_coex { __le16 reserved; } __packed; +struct host_cmd_ds_wakeup_reason { + u16 wakeup_reason; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2231,6 +2250,7 @@ struct host_cmd_ds_command { struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; struct host_cmd_ds_multi_chan_policy mc_policy; struct host_cmd_ds_robust_coex coex; + struct host_cmd_ds_wakeup_reason hs_wakeup_reason; } params; } __packed; diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 6333b163acef..14cfa37deb00 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -271,6 +271,10 @@ struct mwifiex_ds_hs_cfg { u32 gap; }; +struct mwifiex_ds_wakeup_reason { + u16 hs_wakeup_reason; +}; + #define DEEP_SLEEP_ON 1 #define DEEP_SLEEP_OFF 0 #define DEEP_SLEEP_IDLE_TIME 100 diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index bf9b24ae46fc..c755be54cc83 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1599,6 +1599,12 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter); void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter); void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); +int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action, + int cmd_type, + struct mwifiex_ds_wakeup_reason *wakeup_reason); +int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + struct host_cmd_ds_wakeup_reason *wakeup_reason); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 60f3ded747c9..30f152601c57 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1813,6 +1813,22 @@ static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd, return 0; } +/* This function prepares command to get HS wakeup reason. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_HS_WAKEUP_REASON); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_wakeup_reason) + + S_DS_GEN); + + return 0; +} + /* * This function prepares the commands before sending them to the firmware. * @@ -2067,6 +2083,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_HS_WAKEUP_REASON: + ret = mwifiex_cmd_get_wakeup_reason(priv, cmd_ptr); + break; case HostCmd_CMD_MC_POLICY: ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action, data_buf); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 4b23d3b95a20..d96523e10eb4 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1236,6 +1236,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); break; + case HostCmd_CMD_HS_WAKEUP_REASON: + ret = mwifiex_ret_wakeup_reason(priv, resp, data_buf); + break; case HostCmd_CMD_TDLS_CONFIG: break; case HostCmd_CMD_ROBUST_COEX: diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 7277c24ee9aa..5cbee58f8781 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -1465,3 +1465,19 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len) return 0; } + +/* This function get Host Sleep wake up reason. + * + */ +int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action, + int cmd_type, + struct mwifiex_ds_wakeup_reason *wakeup_reason) +{ + int status = 0; + + status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON, + HostCmd_ACT_GEN_GET, 0, wakeup_reason, + cmd_type == MWIFIEX_SYNC_CMD); + + return status; +} -- cgit v1.2.3 From fdcab083055d759325c8e0f8999d9e192417fc20 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Wed, 13 Jan 2016 01:26:56 -0800 Subject: mwifiex: add RSSI support for net-detect This patch adds support for waking up the device on finding better RSSI. Threshold RSSI value will be configured by application. Signed-off-by: Ganapathi Bhat Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 ++++ drivers/net/wireless/marvell/mwifiex/fw.h | 5 +++++ drivers/net/wireless/marvell/mwifiex/scan.c | 15 +++++++++++++++ 3 files changed, 24 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index c80d9e2daa16..84615533986c 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -2582,6 +2582,10 @@ mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy, bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA; bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET; bgscan_cfg->enable = true; + if (request->min_rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { + bgscan_cfg->report_condition |= MWIFIEX_BGSCAN_SSID_RSSI_MATCH; + bgscan_cfg->rssi_threshold = request->min_rssi_thold; + } if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG, HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) { diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index d293e485189b..4af916817bcd 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -759,6 +759,11 @@ struct mwifiex_ie_types_repeat_count { __le16 repeat_count; } __packed; +struct mwifiex_ie_types_min_rssi_threshold { + struct mwifiex_ie_types_header header; + __le16 rssi_threshold; +} __packed; + struct mwifiex_ie_types_bgscan_start_later { struct mwifiex_ie_types_header header; __le16 start_later; diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 2702bd93f74d..fc8d8ca67453 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2260,6 +2260,7 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, int i; struct mwifiex_ie_types_num_probes *num_probes_tlv; struct mwifiex_ie_types_repeat_count *repeat_count_tlv; + struct mwifiex_ie_types_min_rssi_threshold *rssi_threshold_tlv; struct mwifiex_ie_types_bgscan_start_later *start_later_tlv; struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv; @@ -2310,6 +2311,20 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, le16_to_cpu(repeat_count_tlv->header.len); } + if (bgscan_cfg_in->rssi_threshold) { + rssi_threshold_tlv = + (struct mwifiex_ie_types_min_rssi_threshold *)tlv_pos; + rssi_threshold_tlv->header.type = + cpu_to_le16(TLV_TYPE_RSSI_LOW); + rssi_threshold_tlv->header.len = + cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold)); + rssi_threshold_tlv->rssi_threshold = + cpu_to_le16(bgscan_cfg_in->rssi_threshold); + + tlv_pos += sizeof(rssi_threshold_tlv->header) + + le16_to_cpu(rssi_threshold_tlv->header.len); + } + for (i = 0; i < bgscan_cfg_in->num_ssids; i++) { ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len; -- cgit v1.2.3 From a92277bc3bfe7c41cac13ca4a7d5070033543732 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 13 Jan 2016 01:26:57 -0800 Subject: mwifiex: use SYNC flag for canceling host sleep Host sleep is cancelled in sdio resume() handler. Cfg80211's resume handler is immediately called after this. SYNC flag here ensures that host sleep handshake gets completed and we have valid "adapter->nd_config" before we report host wakeup reason in cfg80211's resume handler. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 33771d3fd843..abf15dbdfe08 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -181,7 +181,7 @@ static int mwifiex_sdio_resume(struct device *dev) /* Disable Host Sleep */ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), - MWIFIEX_ASYNC_CMD); + MWIFIEX_SYNC_CMD); return 0; } -- cgit v1.2.3 From 3955525d5d17118ed8900e9e79753057120eb02a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 14 Jan 2016 09:39:21 +0200 Subject: iwlwifi: pcie: buffer packets to avoid overflowing Tx queues When the Tx queues are full above a threshold, we immediately stop the mac80211's queue to stop getting new packets. This worked until TSO was enabled. With TSO, one single packet from mac80211 can use many descriptors since a large send needs to be split into several segments. This means that stopping mac80211's queues is not enough and we also need to ensure that we don't overflow the Tx queues with one single packet from mac80211. Add code to transport layer to do just that. Stop mac80211's queue as soon as the queue is full above the same threshold as before, and keep pushing the current packet along with its segments on the queue, but check that we don't overflow. If that would happen, buffer the segments, and send them when there is room in the Tx queue again. Of course, we first need to send the buffered segments and only then, wake up mac80211's queues. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 69 +++++++++++++++++++--- 2 files changed, 62 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cc3888e2700d..2d8b415fa55e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -280,6 +280,7 @@ struct iwl_txq { bool ampdu; bool block; unsigned long wd_timeout; + struct sk_buff_head overflow_q; }; static inline dma_addr_t diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 5262028b5505..b0b0fd9e2eff 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -571,6 +571,7 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, return ret; spin_lock_init(&txq->lock); + __skb_queue_head_init(&txq->overflow_q); /* * Tell nic where to find circular buffer of Tx Frame Descriptors for @@ -621,6 +622,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr); } txq->active = false; + + while (!skb_queue_empty(&txq->overflow_q)) { + struct sk_buff *skb = __skb_dequeue(&txq->overflow_q); + + iwl_op_mode_free_skb(trans->op_mode, skb); + } + spin_unlock_bh(&txq->lock); /* just in case - this queue may have been stopped */ @@ -1052,8 +1060,41 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, iwl_pcie_txq_progress(txq); - if (iwl_queue_space(&txq->q) > txq->q.low_mark) - iwl_wake_queue(trans, txq); + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + test_bit(txq_id, trans_pcie->queue_stopped)) { + struct sk_buff_head skbs; + + __skb_queue_head_init(&skbs); + skb_queue_splice_init(&txq->overflow_q, &skbs); + + /* + * This is tricky: we are in reclaim path which is non + * re-entrant, so noone will try to take the access the + * txq data from that path. We stopped tx, so we can't + * have tx as well. Bottom line, we can unlock and re-lock + * later. + */ + spin_unlock_bh(&txq->lock); + + while (!skb_queue_empty(&skbs)) { + struct sk_buff *skb = __skb_dequeue(&skbs); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 dev_cmd_idx = IWL_TRANS_FIRST_DRIVER_DATA + 1; + struct iwl_device_cmd *dev_cmd = + info->driver_data[dev_cmd_idx]; + + /* + * Note that we can very well be overflowing again. + * In that case, iwl_queue_space will be small again + * and we won't wake mac80211's queue. + */ + iwl_trans_pcie_tx(trans, skb, dev_cmd, txq_id); + } + spin_lock_bh(&txq->lock); + + if (iwl_queue_space(&txq->q) > txq->q.low_mark) + iwl_wake_queue(trans, txq); + } if (q->read_ptr == q->write_ptr) { IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id); @@ -2161,6 +2202,8 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, csum = skb_checksum(skb, offs, skb->len - offs, 0); *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum); + + skb->ip_summed = CHECKSUM_UNNECESSARY; } if (skb_is_nonlinear(skb) && @@ -2177,6 +2220,22 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, spin_lock(&txq->lock); + if (iwl_queue_space(q) < q->high_mark) { + iwl_stop_queue(trans, txq); + + /* don't put the packet on the ring, if there is no room */ + if (unlikely(iwl_queue_space(q) < 3)) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA + 1] = + dev_cmd; + __skb_queue_tail(&txq->overflow_q, skb); + + spin_unlock(&txq->lock); + return 0; + } + } + /* In AGG mode, the index in the ring must correspond to the WiFi * sequence number. This is a HW requirements to help the SCD to parse * the BA. @@ -2281,12 +2340,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, * At this point the frame is "transmitted" successfully * and we will get a TX status notification eventually. */ - if (iwl_queue_space(q) < q->high_mark) { - if (wait_write_ptr) - iwl_pcie_txq_inc_wr_ptr(trans, txq); - else - iwl_stop_queue(trans, txq); - } spin_unlock(&txq->lock); return 0; out_err: -- cgit v1.2.3 From 7848505416be4e96af14c3387775622d26a13146 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 14 Dec 2015 17:44:11 +0200 Subject: iwlwifi: pcie: add infrastructure for multi-queue rx The 9000 series devices will support multi rx queues. Current code has one static rx queue - change it to allocate a number of queues per the device capability (pre-9000 devices have the number of rx queues set to one). Subsequent generalizations are: Change the code to access an explicit numbered rx queue only when the queue number is known - when handling interrupt, when accessing the default queue and when iterating the queues. The rest of the functions will receive the rx queue as a pointer. Generalize the warning in allocation failure to consider the allocator status instead of a single rx queue status. Move the rx initial pool of memory buffers to be shared among all the queues and allocated to the default queue on init. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 8 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 264 +++++++++++---------- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 73 ++++-- 3 files changed, 191 insertions(+), 154 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 2d8b415fa55e..11ad87fca67a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -57,7 +57,7 @@ #define RX_POST_REQ_ALLOC 2 #define RX_CLAIM_REQ_ALLOC 8 #define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES) -#define RX_LOW_WATERMARK 8 +#define RX_PENDING_WATERMARK 16 struct iwl_host_cmd; @@ -103,7 +103,6 @@ struct isr_statistics { * @rb_stts: driver's pointer to receive buffer status * @rb_stts_dma: bus address of receive buffer status * @lock: - * @pool: initial pool of iwl_rx_mem_buffer for the queue * @queue: actual rx queue * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers @@ -122,7 +121,6 @@ struct iwl_rxq { struct iwl_rb_status *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; - struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE]; struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; }; @@ -298,6 +296,7 @@ struct iwl_tso_hdr_page { /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data + * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues * @rba: allocator for RX replenishing * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area @@ -324,7 +323,8 @@ struct iwl_tso_hdr_page { * @fw_mon_size: size of the buffer for the firmware monitor */ struct iwl_trans_pcie { - struct iwl_rxq rxq; + struct iwl_rxq *rxq; + struct iwl_rx_mem_buffer rx_pool[RX_QUEUE_SIZE]; struct iwl_rb_allocator rba; struct iwl_trans *trans; struct iwl_drv *drv; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index ccafbd8cf4b3..f557f3dc4db8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -173,10 +173,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans) /* * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue */ -static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans) +static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, + struct iwl_rxq *rxq) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; u32 reg; lockdep_assert_held(&rxq->lock); @@ -207,18 +206,18 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans) static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; - - spin_lock(&rxq->lock); - - if (!rxq->need_update) - goto exit_unlock; + int i; - iwl_pcie_rxq_inc_wr_ptr(trans); - rxq->need_update = false; + for (i = 0; i < trans->num_rx_queues; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; - exit_unlock: - spin_unlock(&rxq->lock); + if (!rxq->need_update) + continue; + spin_lock(&rxq->lock); + iwl_pcie_rxq_inc_wr_ptr(trans, rxq); + rxq->need_update = false; + spin_unlock(&rxq->lock); + } } /* @@ -232,10 +231,8 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) * also updates the memory address in the firmware to reference the new * target buffer. */ -static void iwl_pcie_rxq_restock(struct iwl_trans *trans) +static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; /* @@ -272,7 +269,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) * Increment device's write pointer in multiples of 8. */ if (rxq->write_actual != (rxq->write & ~0x7)) { spin_lock(&rxq->lock); - iwl_pcie_rxq_inc_wr_ptr(trans); + iwl_pcie_rxq_inc_wr_ptr(trans, rxq); spin_unlock(&rxq->lock); } } @@ -285,13 +282,9 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans, gfp_t priority) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; struct page *page; gfp_t gfp_mask = priority; - if (rxq->free_count > RX_LOW_WATERMARK) - gfp_mask |= __GFP_NOWARN; - if (trans_pcie->rx_page_order > 0) gfp_mask |= __GFP_COMP; @@ -301,16 +294,13 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans, if (net_ratelimit()) IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n", trans_pcie->rx_page_order); - /* Issue an error if the hardware has consumed more than half - * of its free buffer list and we don't have enough - * pre-allocated buffers. + /* + * Issue an error if we don't have enough pre-allocated + * buffers. ` */ - if (rxq->free_count <= RX_LOW_WATERMARK && - iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) && - net_ratelimit()) + if (!(gfp_mask & __GFP_NOWARN) && net_ratelimit()) IWL_CRIT(trans, - "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n", - rxq->free_count); + "Failed to alloc_pages\n"); return NULL; } return page; @@ -325,10 +315,10 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans, * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly * allocated buffers. */ -static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) +static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority, + struct iwl_rxq *rxq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; @@ -386,40 +376,23 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) } } -static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) +static void iwl_pcie_free_rbs_pool(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; int i; - lockdep_assert_held(&rxq->lock); - for (i = 0; i < RX_QUEUE_SIZE; i++) { - if (!rxq->pool[i].page) + if (!trans_pcie->rx_pool[i].page) continue; - dma_unmap_page(trans->dev, rxq->pool[i].page_dma, + dma_unmap_page(trans->dev, trans_pcie->rx_pool[i].page_dma, PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); - __free_pages(rxq->pool[i].page, trans_pcie->rx_page_order); - rxq->pool[i].page = NULL; + __free_pages(trans_pcie->rx_pool[i].page, + trans_pcie->rx_page_order); + trans_pcie->rx_pool[i].page = NULL; } } -/* - * iwl_pcie_rx_replenish - Move all used buffers from rx_used to rx_free - * - * When moving to rx_free an page is allocated for the slot. - * - * Also restock the Rx queue via iwl_pcie_rxq_restock. - * This is called only during initialization - */ -static void iwl_pcie_rx_replenish(struct iwl_trans *trans) -{ - iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL); - - iwl_pcie_rxq_restock(trans); -} - /* * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues * @@ -444,6 +417,11 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) while (pending) { int i; struct list_head local_allocated; + gfp_t gfp_mask = GFP_KERNEL; + + /* Do not post a warning if there are only a few requests */ + if (pending < RX_PENDING_WATERMARK) + gfp_mask |= __GFP_NOWARN; INIT_LIST_HEAD(&local_allocated); @@ -463,7 +441,7 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) BUG_ON(rxb->page); /* Alloc a new receive buffer */ - page = iwl_pcie_rx_alloc_page(trans, GFP_KERNEL); + page = iwl_pcie_rx_alloc_page(trans, gfp_mask); if (!page) continue; rxb->page = page; @@ -561,38 +539,60 @@ static void iwl_pcie_rx_allocator_work(struct work_struct *data) static int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rb_allocator *rba = &trans_pcie->rba; struct device *dev = trans->dev; + int i; + + if (WARN_ON(trans_pcie->rxq)) + return -EINVAL; - memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); + trans_pcie->rxq = kcalloc(trans->num_rx_queues, sizeof(struct iwl_rxq), + GFP_KERNEL); + if (!trans_pcie->rxq) + return -EINVAL; - spin_lock_init(&rxq->lock); spin_lock_init(&rba->lock); - if (WARN_ON(rxq->bd || rxq->rb_stts)) - return -EINVAL; + for (i = 0; i < trans->num_rx_queues; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; - /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + spin_lock_init(&rxq->lock); + /* + * Allocate the circular buffer of Read Buffer Descriptors + * (RBDs) + */ + rxq->bd = dma_zalloc_coherent(dev, + sizeof(__le32) * RX_QUEUE_SIZE, &rxq->bd_dma, GFP_KERNEL); - if (!rxq->bd) - goto err_bd; + if (!rxq->bd) + goto err; - /*Allocate the driver's pointer to receive buffer status */ - rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts), - &rxq->rb_stts_dma, GFP_KERNEL); - if (!rxq->rb_stts) - goto err_rb_stts; + /*Allocate the driver's pointer to receive buffer status */ + rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts), + &rxq->rb_stts_dma, + GFP_KERNEL); + if (!rxq->rb_stts) + goto err; + } return 0; -err_rb_stts: - dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - rxq->bd_dma = 0; - rxq->bd = NULL; -err_bd: +err: + for (i = 0; i < trans->num_rx_queues; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; + + if (rxq->bd) + dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + rxq->bd_dma = 0; + rxq->bd = NULL; + + if (rxq->rb_stts) + dma_free_coherent(trans->dev, + sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); + } + kfree(trans_pcie->rxq); return -ENOMEM; } @@ -661,17 +661,12 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) { - int i; - lockdep_assert_held(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); rxq->free_count = 0; rxq->used_count = 0; - - for (i = 0; i < RX_QUEUE_SIZE; i++) - list_add(&rxq->pool[i].list, &rxq->rx_used); } static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba) @@ -709,15 +704,16 @@ static void iwl_pcie_rx_free_rba(struct iwl_trans *trans) int iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rxq *def_rxq; struct iwl_rb_allocator *rba = &trans_pcie->rba; int i, err; - if (!rxq->bd) { + if (!trans_pcie->rxq) { err = iwl_pcie_rx_alloc(trans); if (err) return err; } + def_rxq = trans_pcie->rxq; if (!rba->alloc_wq) rba->alloc_wq = alloc_workqueue("rb_allocator", WQ_HIGHPRI | WQ_UNBOUND, 1); @@ -731,29 +727,42 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) iwl_pcie_rx_init_rba(rba); spin_unlock(&rba->lock); - spin_lock(&rxq->lock); - /* free all first - we might be reconfigured for a different size */ - iwl_pcie_rxq_free_rbs(trans); - iwl_pcie_rx_init_rxb_lists(rxq); + iwl_pcie_free_rbs_pool(trans); for (i = 0; i < RX_QUEUE_SIZE; i++) - rxq->queue[i] = NULL; + def_rxq->queue[i] = NULL; - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->write_actual = 0; - memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); - spin_unlock(&rxq->lock); + for (i = 0; i < trans->num_rx_queues; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; - iwl_pcie_rx_replenish(trans); + spin_lock(&rxq->lock); + /* + * Set read write pointer to reflect that we have processed + * and used all buffers, but have not restocked the Rx queue + * with fresh buffers + */ + rxq->read = 0; + rxq->write = 0; + rxq->write_actual = 0; + memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); - iwl_pcie_rx_hw_init(trans, rxq); + iwl_pcie_rx_init_rxb_lists(rxq); - spin_lock(&rxq->lock); - iwl_pcie_rxq_inc_wr_ptr(trans); - spin_unlock(&rxq->lock); + spin_unlock(&rxq->lock); + } + + /* move the entire pool to the default queue ownership */ + for (i = 0; i < RX_QUEUE_SIZE; i++) + list_add(&trans_pcie->rx_pool[i].list, &def_rxq->rx_used); + + iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq); + iwl_pcie_rxq_restock(trans, def_rxq); + iwl_pcie_rx_hw_init(trans, def_rxq); + + spin_lock(&def_rxq->lock); + iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq); + spin_unlock(&def_rxq->lock); return 0; } @@ -761,12 +770,14 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rb_allocator *rba = &trans_pcie->rba; + int i; - /*if rxq->bd is NULL, it means that nothing has been allocated, - * exit now */ - if (!rxq->bd) { + /* + * if rxq is NULL, it means that nothing has been allocated, + * exit now + */ + if (!trans_pcie->rxq) { IWL_DEBUG_INFO(trans, "Free NULL rx context\n"); return; } @@ -781,23 +792,28 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) iwl_pcie_rx_free_rba(trans); spin_unlock(&rba->lock); - spin_lock(&rxq->lock); - iwl_pcie_rxq_free_rbs(trans); - spin_unlock(&rxq->lock); - - dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - rxq->bd_dma = 0; - rxq->bd = NULL; + iwl_pcie_free_rbs_pool(trans); + + for (i = 0; i < trans->num_rx_queues; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; + + if (rxq->bd) + dma_free_coherent(trans->dev, + sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + rxq->bd_dma = 0; + rxq->bd = NULL; + + if (rxq->rb_stts) + dma_free_coherent(trans->dev, + sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); + else + IWL_DEBUG_INFO(trans, + "Free rxq->rb_stts which is NULL\n"); + } - if (rxq->rb_stts) - dma_free_coherent(trans->dev, - sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); - else - IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); - rxq->rb_stts_dma = 0; - rxq->rb_stts = NULL; + kfree(trans_pcie->rxq); } /* @@ -841,11 +857,11 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans, } static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, + struct iwl_rxq *rxq, struct iwl_rx_mem_buffer *rxb, bool emergency) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; bool page_stolen = false; int max_len = PAGE_SIZE << trans_pcie->rx_page_order; @@ -975,7 +991,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, static void iwl_pcie_rx_handle(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rxq *rxq = &trans_pcie->rxq[0]; u32 r, i, j, count = 0; bool emergency = false; @@ -1000,7 +1016,7 @@ restart: rxq->queue[i] = NULL; IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d\n", r, i); - iwl_pcie_rx_handle_rb(trans, rxb, emergency); + iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency); i = (i + 1) & RX_QUEUE_MASK; @@ -1043,7 +1059,7 @@ restart: if (rxq->used_count < RX_QUEUE_SIZE / 3) emergency = false; spin_unlock(&rxq->lock); - iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); spin_lock(&rxq->lock); } } @@ -1055,7 +1071,7 @@ restart: if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) { rxq->read = i; spin_unlock(&rxq->lock); - iwl_pcie_rxq_restock(trans); + iwl_pcie_rxq_restock(trans, rxq); goto restart; } } @@ -1077,7 +1093,7 @@ restart: * will be restocked by the next call of iwl_pcie_rxq_restock. */ if (unlikely(emergency && count)) - iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); if (trans_pcie->napi.poll) napi_gro_flush(&trans_pcie->napi, false); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d60a467a983c..0302aede4fdf 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2001,29 +2001,48 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, { struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; - char buf[256]; - int pos = 0; - const size_t bufsz = sizeof(buf); - - pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", - rxq->read); - pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", - rxq->write); - pos += scnprintf(buf + pos, bufsz - pos, "write_actual: %u\n", - rxq->write_actual); - pos += scnprintf(buf + pos, bufsz - pos, "need_update: %d\n", - rxq->need_update); - pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", - rxq->free_count); - if (rxq->rb_stts) { - pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", - le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); - } else { - pos += scnprintf(buf + pos, bufsz - pos, - "closed_rb_num: Not Allocated\n"); + char *buf; + int pos = 0, i, ret; + size_t bufsz = sizeof(buf); + + bufsz = sizeof(char) * 121 * trans->num_rx_queues; + + if (!trans_pcie->rxq) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < trans->num_rx_queues && pos < bufsz; i++) { + struct iwl_rxq *rxq = &trans_pcie->rxq[i]; + + pos += scnprintf(buf + pos, bufsz - pos, "queue#: %2d\n", + i); + pos += scnprintf(buf + pos, bufsz - pos, "\tread: %u\n", + rxq->read); + pos += scnprintf(buf + pos, bufsz - pos, "\twrite: %u\n", + rxq->write); + pos += scnprintf(buf + pos, bufsz - pos, "\twrite_actual: %u\n", + rxq->write_actual); + pos += scnprintf(buf + pos, bufsz - pos, "\tneed_update: %2d\n", + rxq->need_update); + pos += scnprintf(buf + pos, bufsz - pos, "\tfree_count: %u\n", + rxq->free_count); + if (rxq->rb_stts) { + pos += scnprintf(buf + pos, bufsz - pos, + "\tclosed_rb_num: %u\n", + le16_to_cpu(rxq->rb_stts->closed_rb_num) & + 0x0FFF); + } else { + pos += scnprintf(buf + pos, bufsz - pos, + "\tclosed_rb_num: Not Allocated\n"); + } } - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + + return ret; } static ssize_t iwl_dbgfs_interrupt_read(struct file *file, @@ -2188,7 +2207,8 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int max_len = PAGE_SIZE << trans_pcie->rx_page_order; - struct iwl_rxq *rxq = &trans_pcie->rxq; + /* Dump RBs is supported only for pre-9000 devices (1 queue) */ + struct iwl_rxq *rxq = &trans_pcie->rxq[0]; u32 i, r, j, rb_len = 0; spin_lock(&rxq->lock); @@ -2438,11 +2458,12 @@ static struct iwl_trans_dump_data len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); if (dump_rbs) { + /* Dump RBs is supported only for pre-9000 devices (1 queue) */ + struct iwl_rxq *rxq = &trans_pcie->rxq[0]; /* RBs */ - num_rbs = le16_to_cpu(ACCESS_ONCE( - trans_pcie->rxq.rb_stts->closed_rb_num)) + num_rbs = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF; - num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; + num_rbs = (num_rbs - rxq->read) & RX_QUEUE_MASK; len += num_rbs * (sizeof(*data) + sizeof(struct iwl_fw_error_dump_rb) + (PAGE_SIZE << trans_pcie->rx_page_order)); -- cgit v1.2.3 From 96a6497bc3ed1c19d877e5f4f95f2cfa27448abe Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 23 Dec 2015 15:10:03 +0200 Subject: iwlwifi: pcie: add 9000 series multi queue rx DMA support The 9000 series introduces several changes in the device DMA operation. As the device now supports multi-queue rx, several DMA channels should be configured. The flows of providing the device with the allocated RBDs now changes as well - the device maintains a separate table of used and free table. The hardware may use the free table to feed RBDs to any queue. This requires maintaing a shared table to map returned RBDs to the original RXB - for that purpose the VID is introduced - an internal identifier of the RB placed in the lower 12 bits and returned by HW in the used data. Another change is the support of 64 bit DMA address. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 + drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 77 ++++++ drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 28 ++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 277 ++++++++++++++++----- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 15 +- 6 files changed, 322 insertions(+), 80 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index ecbf4822cd69..4b93404f46a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -138,7 +138,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { .smem_offset = IWL9000_SMEM_OFFSET, \ .smem_len = IWL9000_SMEM_LEN, \ .thermal_params = &iwl9000_tt_params, \ - .apmg_not_supported = true + .apmg_not_supported = true, \ + .mq_rx_supported = true const struct iwl_cfg iwl9260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9260", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index f99048135fb9..dad5570d6cc8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -311,6 +311,7 @@ struct iwl_pwr_tx_backoff { * @dccm2_len: length of the second DCCM * @smem_offset: offset from which the SMEM begins * @smem_len: the length of SMEM + * @mq_rx_supported: multi-queue rx support * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -362,6 +363,7 @@ struct iwl_cfg { const u32 smem_len; const struct iwl_tt_params *thermal_params; bool apmg_not_supported; + bool mq_rx_supported; }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 5cc6be927eab..4ab6682ea53e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -312,6 +314,77 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 #define FH_MEM_TB_MAX_LENGTH (0x00020000) +/* 9000 rx series registers */ + +#define RFH_Q0_FRBDCB_BA_LSB 0xA08000 /* 64 bit address */ +#define RFH_Q_FRBDCB_BA_LSB(q) (RFH_Q0_FRBDCB_BA_LSB + (q) * 8) +/* Write index table */ +#define RFH_Q0_FRBDCB_WIDX 0xA08080 +#define RFH_Q_FRBDCB_WIDX(q) (RFH_Q0_FRBDCB_WIDX + (q) * 4) +/* Read index table */ +#define RFH_Q0_FRBDCB_RIDX 0xA080C0 +#define RFH_Q_FRBDCB_RIDX(q) (RFH_Q0_FRBDCB_RIDX + (q) * 4) +/* Used list table */ +#define RFH_Q0_URBDCB_BA_LSB 0xA08100 /* 64 bit address */ +#define RFH_Q_URBDCB_BA_LSB(q) (RFH_Q0_URBDCB_BA_LSB + (q) * 8) +/* Write index table */ +#define RFH_Q0_URBDCB_WIDX 0xA08180 +#define RFH_Q_URBDCB_WIDX(q) (RFH_Q0_URBDCB_WIDX + (q) * 4) +#define RFH_Q0_URBDCB_VAID 0xA081C0 +#define RFH_Q_URBDCB_VAID(q) (RFH_Q0_URBDCB_VAID + (q) * 4) +/* stts */ +#define RFH_Q0_URBD_STTS_WPTR_LSB 0xA08200 /*64 bits address */ +#define RFH_Q_URBD_STTS_WPTR_LSB(q) (RFH_Q0_URBD_STTS_WPTR_LSB + (q) * 8) + +#define RFH_Q0_ORB_WPTR_LSB 0xA08280 +#define RFH_Q_ORB_WPTR_LSB(q) (RFH_Q0_ORB_WPTR_LSB + (q) * 8) +#define RFH_RBDBUF_RBD0_LSB 0xA08300 +#define RFH_RBDBUF_RBD_LSB(q) (RFH_RBDBUF_RBD0_LSB + (q) * 8) + +/* DMA configuration */ +#define RFH_RXF_DMA_CFG 0xA09820 +/* RB size */ +#define RFH_RXF_DMA_RB_SIZE_MASK (0x000F0000) /* bits 16-19 */ +#define RFH_RXF_DMA_RB_SIZE_POS 16 +#define RFH_RXF_DMA_RB_SIZE_1K (0x1 << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_2K (0x2 << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_4K (0x4 << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_8K (0x8 << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_12K (0x9 << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_16K (0xA << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_20K (0xB << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_24K (0xC << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_28K (0xD << RFH_RXF_DMA_RB_SIZE_POS) +#define RFH_RXF_DMA_RB_SIZE_32K (0xE << RFH_RXF_DMA_RB_SIZE_POS) +/* RB Circular Buffer size:defines the table sizes in RBD units */ +#define RFH_RXF_DMA_RBDCB_SIZE_MASK (0x00F00000) /* bits 20-23 */ +#define RFH_RXF_DMA_RBDCB_SIZE_POS 20 +#define RFH_RXF_DMA_RBDCB_SIZE_8 (0x3 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_16 (0x4 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_32 (0x5 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_64 (0x7 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_128 (0x7 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_256 (0x8 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_512 (0x9 << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_1024 (0xA << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_RBDCB_SIZE_2048 (0xB << RFH_RXF_DMA_RBDCB_SIZE_POS) +#define RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */ +#define RFH_RXF_DMA_MIN_RB_SIZE_POS 24 +#define RFH_RXF_DMA_MIN_RB_4_8 (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS) +#define RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */ +#define RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/ +#define RFH_DMA_EN_ENABLE_VAL BIT(31) + +#define RFH_RXF_RXQ_ACTIVE 0xA0980C + +#define RFH_GEN_CFG 0xA09800 +#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00 +#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0) +#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1) +#define DEFAULT_RXQ_NUM 8 + +/* end of 9000 rx series registers */ + /* TFDB Area - TFDs buffer table */ #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) #define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900) @@ -434,6 +507,10 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) */ #define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) +#define MQ_RX_TABLE_SIZE 512 +#define MQ_RX_TABLE_MASK (MQ_RX_TABLE_SIZE - 1) +#define MQ_RX_POOL_SIZE MQ_RX_TABLE_MASK + #define RX_QUEUE_SIZE 256 #define RX_QUEUE_MASK 255 #define RX_QUEUE_SIZE_LOG 8 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 11ad87fca67a..bdda7028c393 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -56,7 +56,6 @@ #define RX_NUM_QUEUES 1 #define RX_POST_REQ_ALLOC 2 #define RX_CLAIM_REQ_ALLOC 8 -#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES) #define RX_PENDING_WATERMARK 16 struct iwl_host_cmd; @@ -64,9 +63,16 @@ struct iwl_host_cmd; /*This file includes the declaration that are internal to the * trans_pcie layer */ +/** + * struct iwl_rx_mem_buffer + * @page_dma: bus address of rxb page + * @page: driver's pointer to the rxb page + * @vid: index of this rxb in the global table + */ struct iwl_rx_mem_buffer { dma_addr_t page_dma; struct page *page; + u16 vid; struct list_head list; }; @@ -90,8 +96,12 @@ struct isr_statistics { /** * struct iwl_rxq - Rx queue - * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) + * @id: queue index + * @bd: driver's pointer to buffer of receive buffer descriptors (rbd). + * Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices. * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) + * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd) + * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd) * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free @@ -103,18 +113,22 @@ struct isr_statistics { * @rb_stts: driver's pointer to receive buffer status * @rb_stts_dma: bus address of receive buffer status * @lock: - * @queue: actual rx queue + * @queue: actual rx queue. Not used for multi-rx queue. * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ struct iwl_rxq { - __le32 *bd; + int id; + void *bd; dma_addr_t bd_dma; + __le32 *used_bd; + dma_addr_t used_bd_dma; u32 read; u32 write; u32 free_count; u32 used_count; u32 write_actual; + u32 queue_size; struct list_head rx_free; struct list_head rx_used; bool need_update; @@ -126,7 +140,6 @@ struct iwl_rxq { /** * struct iwl_rb_allocator - Rx allocator - * @pool: initial pool of allocator * @req_pending: number of requests the allcator had not processed yet * @req_ready: number of requests honored and ready for claiming * @rbd_allocated: RBDs with pages allocated and ready to be handled to @@ -138,7 +151,6 @@ struct iwl_rxq { * @rx_alloc: work struct for background calls */ struct iwl_rb_allocator { - struct iwl_rx_mem_buffer pool[RX_POOL_SIZE]; atomic_t req_pending; atomic_t req_ready; struct list_head rbd_allocated; @@ -297,6 +309,7 @@ struct iwl_tso_hdr_page { * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues + * @global_table: table mapping received VID from hw to rxb * @rba: allocator for RX replenishing * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area @@ -324,7 +337,8 @@ struct iwl_tso_hdr_page { */ struct iwl_trans_pcie { struct iwl_rxq *rxq; - struct iwl_rx_mem_buffer rx_pool[RX_QUEUE_SIZE]; + struct iwl_rx_mem_buffer rx_pool[MQ_RX_POOL_SIZE]; + struct iwl_rx_mem_buffer *global_table[MQ_RX_TABLE_SIZE]; struct iwl_rb_allocator rba; struct iwl_trans *trans; struct iwl_drv *drv; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index f557f3dc4db8..a385f3cddb5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -140,8 +140,8 @@ */ static int iwl_rxq_space(const struct iwl_rxq *rxq) { - /* Make sure RX_QUEUE_SIZE is a power of 2 */ - BUILD_BUG_ON(RX_QUEUE_SIZE & (RX_QUEUE_SIZE - 1)); + /* Make sure rx queue size is a power of 2 */ + WARN_ON(rxq->queue_size & (rxq->queue_size - 1)); /* * There can be up to (RX_QUEUE_SIZE - 1) free slots, to avoid ambiguity @@ -149,7 +149,7 @@ static int iwl_rxq_space(const struct iwl_rxq *rxq) * The following is equivalent to modulo by RX_QUEUE_SIZE and is well * defined for negative dividends. */ - return (rxq->read - rxq->write - 1) & (RX_QUEUE_SIZE - 1); + return (rxq->read - rxq->write - 1) & (rxq->queue_size - 1); } /* @@ -160,6 +160,12 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr) return cpu_to_le32((u32)(dma_addr >> 8)); } +static void iwl_pcie_write_prph_64(struct iwl_trans *trans, u64 ofs, u64 val) +{ + iwl_write_prph(trans, ofs, val & 0xffffffff); + iwl_write_prph(trans, ofs + 4, val >> 32); +} + /* * iwl_pcie_rx_stop - stops the Rx DMA */ @@ -200,7 +206,11 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, } rxq->write_actual = round_down(rxq->write, 8); - iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); + if (trans->cfg->mq_rx_supported) + iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(rxq->id), + rxq->write_actual); + else + iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); } static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) @@ -220,6 +230,51 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) } } +static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, + struct iwl_rxq *rxq) +{ + struct iwl_rx_mem_buffer *rxb; + + /* + * If the device isn't enabled - no need to try to add buffers... + * This can happen when we stop the device and still have an interrupt + * pending. We stop the APM before we sync the interrupts because we + * have to (see comment there). On the other hand, since the APM is + * stopped, we cannot access the HW (in particular not prph). + * So don't try to restock if the APM has been already stopped. + */ + if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + return; + + spin_lock(&rxq->lock); + while (rxq->free_count) { + __le64 *bd = (__le64 *)rxq->bd; + + /* Get next free Rx buffer, remove from free list */ + rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer, + list); + list_del(&rxb->list); + + /* 12 first bits are expected to be empty */ + WARN_ON(rxb->page_dma & DMA_BIT_MASK(12)); + /* Point to Rx buffer via next RBD in circular buffer */ + bd[rxq->write] = cpu_to_le64(rxb->page_dma | rxb->vid); + rxq->write = (rxq->write + 1) & MQ_RX_TABLE_MASK; + rxq->free_count--; + } + spin_unlock(&rxq->lock); + + /* + * If we've added more space for the firmware to place data, tell it. + * Increment device's write pointer in multiples of 8. + */ + if (rxq->write_actual != (rxq->write & ~0x7)) { + spin_lock(&rxq->lock); + iwl_pcie_rxq_inc_wr_ptr(trans, rxq); + spin_unlock(&rxq->lock); + } +} + /* * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool * @@ -248,6 +303,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) spin_lock(&rxq->lock); while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) { + __le32 *bd = (__le32 *)rxq->bd; /* The overwritten rxb must be a used one */ rxb = rxq->queue[rxq->write]; BUG_ON(rxb && rxb->page); @@ -258,7 +314,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) list_del(&rxb->list); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma); + bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -362,10 +418,6 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority, __free_pages(page, trans_pcie->rx_page_order); return; } - /* dma address must be no more than 36 bits */ - BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); - /* and also 256 byte aligned! */ - BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); spin_lock(&rxq->lock); @@ -381,7 +433,7 @@ static void iwl_pcie_free_rbs_pool(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; - for (i = 0; i < RX_QUEUE_SIZE; i++) { + for (i = 0; i < MQ_RX_POOL_SIZE; i++) { if (!trans_pcie->rx_pool[i].page) continue; dma_unmap_page(trans->dev, trans_pcie->rx_pool[i].page_dma, @@ -455,10 +507,6 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) __free_pages(page, trans_pcie->rx_page_order); continue; } - /* dma address must be no more than 36 bits */ - BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); - /* and also 256 byte aligned! */ - BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); /* move the allocated entry to the out list */ list_move(&rxb->list, &local_allocated); @@ -542,6 +590,8 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans) struct iwl_rb_allocator *rba = &trans_pcie->rba; struct device *dev = trans->dev; int i; + int free_size = trans->cfg->mq_rx_supported ? sizeof(__le64) : + sizeof(__le32); if (WARN_ON(trans_pcie->rxq)) return -EINVAL; @@ -557,16 +607,30 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans) struct iwl_rxq *rxq = &trans_pcie->rxq[i]; spin_lock_init(&rxq->lock); + if (trans->cfg->mq_rx_supported) + rxq->queue_size = MQ_RX_TABLE_SIZE; + else + rxq->queue_size = RX_QUEUE_SIZE; + /* * Allocate the circular buffer of Read Buffer Descriptors * (RBDs) */ rxq->bd = dma_zalloc_coherent(dev, - sizeof(__le32) * RX_QUEUE_SIZE, - &rxq->bd_dma, GFP_KERNEL); + free_size * rxq->queue_size, + &rxq->bd_dma, GFP_KERNEL); if (!rxq->bd) goto err; + if (trans->cfg->mq_rx_supported) { + rxq->used_bd = dma_zalloc_coherent(dev, + sizeof(__le32) * + rxq->queue_size, + &rxq->used_bd_dma, + GFP_KERNEL); + if (!rxq->used_bd) + goto err; + } /*Allocate the driver's pointer to receive buffer status */ rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts), @@ -582,7 +646,7 @@ err: struct iwl_rxq *rxq = &trans_pcie->rxq[i]; if (rxq->bd) - dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + dma_free_coherent(dev, free_size * rxq->queue_size, rxq->bd, rxq->bd_dma); rxq->bd_dma = 0; rxq->bd = NULL; @@ -591,8 +655,15 @@ err: dma_free_coherent(trans->dev, sizeof(struct iwl_rb_status), rxq->rb_stts, rxq->rb_stts_dma); + + if (rxq->used_bd) + dma_free_coherent(dev, sizeof(__le32) * rxq->queue_size, + rxq->used_bd, rxq->used_bd_dma); + rxq->used_bd_dma = 0; + rxq->used_bd = NULL; } kfree(trans_pcie->rxq); + return -ENOMEM; } @@ -659,46 +730,82 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE); } -static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) +static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) { - lockdep_assert_held(&rxq->lock); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 rb_size, enabled = 0; + int i; - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - rxq->free_count = 0; - rxq->used_count = 0; -} + switch (trans_pcie->rx_buf_size) { + case IWL_AMSDU_4K: + rb_size = RFH_RXF_DMA_RB_SIZE_4K; + break; + case IWL_AMSDU_8K: + rb_size = RFH_RXF_DMA_RB_SIZE_8K; + break; + case IWL_AMSDU_12K: + rb_size = RFH_RXF_DMA_RB_SIZE_12K; + break; + default: + WARN_ON(1); + rb_size = RFH_RXF_DMA_RB_SIZE_4K; + } -static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba) -{ - int i; + /* Stop Rx DMA */ + iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0); + /* disable free amd used rx queue operation */ + iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, 0); - lockdep_assert_held(&rba->lock); + for (i = 0; i < trans->num_rx_queues; i++) { + /* Tell device where to find RBD free table in DRAM */ + iwl_pcie_write_prph_64(trans, RFH_Q_FRBDCB_BA_LSB(i), + (u64)(rxq->bd_dma)); + /* Tell device where to find RBD used table in DRAM */ + iwl_pcie_write_prph_64(trans, RFH_Q_URBDCB_BA_LSB(i), + (u64)(rxq->used_bd_dma)); + /* Tell device where in DRAM to update its Rx status */ + iwl_pcie_write_prph_64(trans, RFH_Q_URBD_STTS_WPTR_LSB(i), + rxq->rb_stts_dma); + /* Reset device indice tables */ + iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(i), 0); + iwl_write_prph(trans, RFH_Q_FRBDCB_RIDX(i), 0); + iwl_write_prph(trans, RFH_Q_URBDCB_WIDX(i), 0); + + enabled |= BIT(i) | BIT(i + 16); + } - INIT_LIST_HEAD(&rba->rbd_allocated); - INIT_LIST_HEAD(&rba->rbd_empty); + /* restock default queue */ + iwl_pcie_rxq_mq_restock(trans, &trans_pcie->rxq[0]); - for (i = 0; i < RX_POOL_SIZE; i++) - list_add(&rba->pool[i].list, &rba->rbd_empty); + /* + * Enable Rx DMA + * Single frame mode + * Rx buffer size 4 or 8k or 12k + * Min RB size 4 or 8 + * 512 RBDs + */ + iwl_write_prph(trans, RFH_RXF_DMA_CFG, + RFH_DMA_EN_ENABLE_VAL | + rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK | + RFH_RXF_DMA_MIN_RB_4_8 | + RFH_RXF_DMA_RBDCB_SIZE_512); + + iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP | + RFH_GEN_CFG_SERVICE_DMA_SNOOP); + iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, enabled); + + /* Set interrupt coalescing timer to default (2048 usecs) */ + iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); } -static void iwl_pcie_rx_free_rba(struct iwl_trans *trans) +static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rb_allocator *rba = &trans_pcie->rba; - int i; - - lockdep_assert_held(&rba->lock); + lockdep_assert_held(&rxq->lock); - for (i = 0; i < RX_POOL_SIZE; i++) { - if (!rba->pool[i].page) - continue; - dma_unmap_page(trans->dev, rba->pool[i].page_dma, - PAGE_SIZE << trans_pcie->rx_page_order, - DMA_FROM_DEVICE); - __free_pages(rba->pool[i].page, trans_pcie->rx_page_order); - rba->pool[i].page = NULL; - } + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + rxq->free_count = 0; + rxq->used_count = 0; } int iwl_pcie_rx_init(struct iwl_trans *trans) @@ -706,7 +813,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *def_rxq; struct iwl_rb_allocator *rba = &trans_pcie->rba; - int i, err; + int i, err, num_rbds, allocator_pool_size; if (!trans_pcie->rxq) { err = iwl_pcie_rx_alloc(trans); @@ -722,9 +829,8 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) spin_lock(&rba->lock); atomic_set(&rba->req_pending, 0); atomic_set(&rba->req_ready, 0); - /* free all first - we might be reconfigured for a different size */ - iwl_pcie_rx_free_rba(trans); - iwl_pcie_rx_init_rba(rba); + INIT_LIST_HEAD(&rba->rbd_allocated); + INIT_LIST_HEAD(&rba->rbd_empty); spin_unlock(&rba->lock); /* free all first - we might be reconfigured for a different size */ @@ -736,6 +842,8 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) for (i = 0; i < trans->num_rx_queues; i++) { struct iwl_rxq *rxq = &trans_pcie->rxq[i]; + rxq->id = i; + spin_lock(&rxq->lock); /* * Set read write pointer to reflect that we have processed @@ -752,13 +860,29 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) spin_unlock(&rxq->lock); } - /* move the entire pool to the default queue ownership */ - for (i = 0; i < RX_QUEUE_SIZE; i++) - list_add(&trans_pcie->rx_pool[i].list, &def_rxq->rx_used); + /* move the pool to the default queue and allocator ownerships */ + num_rbds = trans->cfg->mq_rx_supported ? + MQ_RX_POOL_SIZE : RX_QUEUE_SIZE; + allocator_pool_size = trans->num_rx_queues * + (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC); + for (i = 0; i < num_rbds; i++) { + struct iwl_rx_mem_buffer *rxb = &trans_pcie->rx_pool[i]; + + if (i < allocator_pool_size) + list_add(&rxb->list, &rba->rbd_empty); + else + list_add(&rxb->list, &def_rxq->rx_used); + trans_pcie->global_table[i] = rxb; + rxb->vid = (u16)i; + } iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq); - iwl_pcie_rxq_restock(trans, def_rxq); - iwl_pcie_rx_hw_init(trans, def_rxq); + if (trans->cfg->mq_rx_supported) { + iwl_pcie_rx_mq_hw_init(trans, def_rxq); + } else { + iwl_pcie_rxq_restock(trans, def_rxq); + iwl_pcie_rx_hw_init(trans, def_rxq); + } spin_lock(&def_rxq->lock); iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq); @@ -771,6 +895,8 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; + int free_size = trans->cfg->mq_rx_supported ? sizeof(__le64) : + sizeof(__le32); int i; /* @@ -788,10 +914,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) rba->alloc_wq = NULL; } - spin_lock(&rba->lock); - iwl_pcie_rx_free_rba(trans); - spin_unlock(&rba->lock); - iwl_pcie_free_rbs_pool(trans); for (i = 0; i < trans->num_rx_queues; i++) { @@ -799,7 +921,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) if (rxq->bd) dma_free_coherent(trans->dev, - sizeof(__le32) * RX_QUEUE_SIZE, + free_size * rxq->queue_size, rxq->bd, rxq->bd_dma); rxq->bd_dma = 0; rxq->bd = NULL; @@ -811,8 +933,14 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) else IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); - } + if (rxq->used_bd) + dma_free_coherent(trans->dev, + sizeof(__le32) * rxq->queue_size, + rxq->used_bd, rxq->used_bd_dma); + rxq->used_bd_dma = 0; + rxq->used_bd = NULL; + } kfree(trans_pcie->rxq); } @@ -1009,16 +1137,26 @@ restart: while (i != r) { struct iwl_rx_mem_buffer *rxb; - if (unlikely(rxq->used_count == RX_QUEUE_SIZE / 2)) + if (unlikely(rxq->used_count == rxq->queue_size / 2)) emergency = true; - rxb = rxq->queue[i]; - rxq->queue[i] = NULL; + if (trans->cfg->mq_rx_supported) { + /* + * used_bd is a 32 bit but only 12 are used to retrieve + * the vid + */ + u16 vid = (u16)le32_to_cpu(rxq->used_bd[i]); + + rxb = trans_pcie->global_table[vid]; + } else { + rxb = rxq->queue[i]; + rxq->queue[i] = NULL; + } IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d\n", r, i); iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency); - i = (i + 1) & RX_QUEUE_MASK; + i = (i + 1) & (rxq->queue_size - 1); /* If we have RX_CLAIM_REQ_ALLOC released rx buffers - * try to claim the pre-allocated buffers from the allocator */ @@ -1056,7 +1194,7 @@ restart: count++; if (count == 8) { count = 0; - if (rxq->used_count < RX_QUEUE_SIZE / 3) + if (rxq->used_count < rxq->queue_size / 3) emergency = false; spin_unlock(&rxq->lock); iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); @@ -1071,7 +1209,10 @@ restart: if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) { rxq->read = i; spin_unlock(&rxq->lock); - iwl_pcie_rxq_restock(trans, rxq); + if (trans->cfg->mq_rx_supported) + iwl_pcie_rxq_mq_restock(trans, rxq); + else + iwl_pcie_rxq_restock(trans, rxq); goto restart; } } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 0302aede4fdf..35810965221c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2403,7 +2403,8 @@ static struct iwl_trans_dump_data u32 len, num_rbs; u32 monitor_len; int i, ptr; - bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status); + bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && + !trans->cfg->mq_rx_supported; /* transport dump header */ len = sizeof(*dump_data); @@ -2562,7 +2563,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans_pcie *trans_pcie; struct iwl_trans *trans; u16 pci_cmd; - int ret; + int ret, addr_size; trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, cfg, &trans_ops_pcie, 0); @@ -2600,11 +2601,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, PCIE_LINK_STATE_CLKPM); } + if (cfg->mq_rx_supported) + addr_size = 64; + else + addr_size = 36; + pci_set_master(pdev); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(addr_size)); if (!ret) - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); + ret = pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(addr_size)); if (ret) { ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (!ret) -- cgit v1.2.3 From b3ff1270566d41eb8ab2d67844bf17b7fa9fee78 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 6 Jan 2016 18:40:38 -0200 Subject: iwlwifi: pcie: add initial RTPM support for PCI Add an initial implementation of runtime power management (RTPM) for PCI devices. With this patch, RTPM is only used when wifi is off (i.e. the wifi interface is down). This implementation is behind a new Kconfig flag, IWLWIFI_PCIE_RTPM. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/Kconfig | 12 +++++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 60 +++++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 27 +++++++++++ 3 files changed, 96 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 866067789330..11932d53ea24 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -99,6 +99,18 @@ config IWLWIFI_UAPSD If unsure, say N. +config IWLWIFI_PCIE_RTPM + bool "Enable runtime power management mode for PCIe devices" + depends on IWLMVM && PM + default false + help + Say Y here to enable runtime power management for PCIe + devices. If enabled, the device will go into low power mode + when idle for a short period of time, allowing for improved + power saving during runtime. + + If unsure, say N. + menu "Debugging Options" config IWLWIFI_DEBUG diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 6261a68cae90..676d2391eb66 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -7,6 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -66,6 +67,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#ifdef CONFIG_IWLWIFI_PCIE_RTPM +#include +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ #include #include #include @@ -623,6 +627,13 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_free_drv; +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, + iwlwifi_mod_params.d0i3_entry_delay); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_allow(&pdev->dev); +#endif return 0; out_free_drv: @@ -689,15 +700,58 @@ static int iwl_pci_resume(struct device *device) return 0; } -static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); +#ifdef CONFIG_IWLWIFI_PCIE_RTPM +static int iwl_pci_runtime_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct iwl_trans *trans = pci_get_drvdata(pdev); + + IWL_DEBUG_RPM(trans, "entering runtime suspend\n"); + + /* For now we only allow D0I3 if the device is off */ + if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + return -EBUSY; + + trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3; + + iwl_trans_d3_suspend(trans, false); + + return 0; +} + +static int iwl_pci_runtime_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct iwl_trans *trans = pci_get_drvdata(pdev); + enum iwl_d3_status d3_status; + + IWL_DEBUG_RPM(trans, "exiting runtime suspend (resume)\n"); + + iwl_trans_d3_resume(trans, &d3_status, false); + + trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + + return 0; +} +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ + +static const struct dev_pm_ops iwl_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(iwl_pci_suspend, + iwl_pci_resume) +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend, + iwl_pci_runtime_resume, + NULL) +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ +}; #define IWL_PM_OPS (&iwl_dev_pm_ops) -#else +#else /* CONFIG_PM_SLEEP */ #define IWL_PM_OPS NULL -#endif +#endif /* CONFIG_PM_SLEEP */ static struct pci_driver iwl_pci_driver = { .name = DRV_NAME, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 35810965221c..db94fe1e1bc6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -72,6 +72,9 @@ #include #include #include +#ifdef CONFIG_IWLWIFI_PCIE_RTPM +#include +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ #include "iwl-drv.h" #include "iwl-trans.h" @@ -1194,6 +1197,9 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) if (hw_rfkill != was_hw_rfkill) iwl_trans_pcie_rf_kill(trans, hw_rfkill); +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + pm_runtime_put_sync(trans->dev); +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ /* re-take ownership to prevent other users from stealing the deivce */ iwl_pcie_prepare_card_hw(trans); } @@ -1353,6 +1359,9 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) /* ... rfkill can call stop_device and set it false if needed */ iwl_trans_pcie_rf_kill(trans, hw_rfkill); +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + pm_runtime_get_sync(trans->dev); +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ return 0; } @@ -1476,6 +1485,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + /* TODO: check if this is really needed */ + pm_runtime_disable(trans->dev); +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ synchronize_irq(trans_pcie->pci_dev->irq); iwl_pcie_tx_free(trans); @@ -1831,6 +1844,9 @@ void iwl_trans_pcie_ref(struct iwl_trans *trans) spin_lock_irqsave(&trans_pcie->ref_lock, flags); IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count); trans_pcie->ref_count++; +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + pm_runtime_get(&trans_pcie->pci_dev->dev); +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); } @@ -1849,6 +1865,11 @@ void iwl_trans_pcie_unref(struct iwl_trans *trans) return; } trans_pcie->ref_count--; +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + pm_runtime_mark_last_busy(&trans_pcie->pci_dev->dev); + pm_runtime_put_autosuspend(&trans_pcie->pci_dev->dev); +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); } @@ -2728,6 +2749,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->inta_mask = CSR_INI_SET_MASK; +#ifdef CONFIG_IWLWIFI_PCIE_RTPM + trans->runtime_pm_mode = IWL_PLAT_PM_MODE_D0I3; +#else + trans->runtime_pm_mode = IWL_PLAT_PM_MODE_DISABLED; +#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ + return trans; out_free_ict: -- cgit v1.2.3 From 4cbb8e50338a2f2453ba399ce52562e0a111fc1f Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 18 Aug 2015 16:02:38 +0300 Subject: iwlwifi: pcie: add RTPM support when wifi is enabled Enable runtime power management (RTPM) for PCIe devices and implement the corresponding functions to enable D0i3 mode when the device is idle. Additionally, remove some unnecessary #ifdef's because the RTPM code will not be called if runtime PM is not configured. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 5 ++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 98 +++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 5 ++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 43 ++++++---- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 17 +++- 5 files changed, 141 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 82fb3a97a46d..fe170a3fb1a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -736,6 +736,11 @@ enum iwl_plat_pm_mode { IWL_PLAT_PM_MODE_D0I3, }; +/* Max time to wait for trans to become idle/non-idle on d0i3 + * enter/exit (in msecs). + */ +#define IWL_TRANS_IDLE_TIMEOUT 2000 + /** * struct iwl_trans - transport common data * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 676d2391eb66..16b579a5aa6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -67,9 +67,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#ifdef CONFIG_IWLWIFI_PCIE_RTPM #include -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ #include #include #include @@ -627,13 +625,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_free_drv; -#ifdef CONFIG_IWLWIFI_PCIE_RTPM - pm_runtime_set_active(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, + /* if RTPM is in use, enable it in our device */ + if (iwl_trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) { + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, iwlwifi_mod_params.d0i3_entry_delay); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_allow(&pdev->dev); -#endif + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_allow(&pdev->dev); + } + return 0; out_free_drv: @@ -700,17 +700,90 @@ static int iwl_pci_resume(struct device *device) return 0; } +int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + if (test_bit(STATUS_FW_ERROR, &trans->status)) + return 0; + + set_bit(STATUS_TRANS_GOING_IDLE, &trans->status); + + /* config the fw */ + ret = iwl_op_mode_enter_d0i3(trans->op_mode); + if (ret == 1) { + IWL_DEBUG_RPM(trans, "aborting d0i3 entrance\n"); + clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status); + return -EBUSY; + } + if (ret) + goto err; + + ret = wait_event_timeout(trans_pcie->d0i3_waitq, + test_bit(STATUS_TRANS_IDLE, &trans->status), + msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT)); + if (!ret) { + IWL_ERR(trans, "Timeout entering D0i3\n"); + ret = -ETIMEDOUT; + goto err; + } + + clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status); + + return 0; +err: + clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status); + iwl_trans_fw_error(trans); + return ret; +} + +int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + /* sometimes a D0i3 entry is not followed through */ + if (!test_bit(STATUS_TRANS_IDLE, &trans->status)) + return 0; + + /* config the fw */ + ret = iwl_op_mode_exit_d0i3(trans->op_mode); + if (ret) + goto err; + + /* we clear STATUS_TRANS_IDLE only when D0I3_END command is completed */ + + ret = wait_event_timeout(trans_pcie->d0i3_waitq, + !test_bit(STATUS_TRANS_IDLE, &trans->status), + msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT)); + if (!ret) { + IWL_ERR(trans, "Timeout exiting D0i3\n"); + ret = -ETIMEDOUT; + goto err; + } + + return 0; +err: + clear_bit(STATUS_TRANS_IDLE, &trans->status); + iwl_trans_fw_error(trans); + return ret; +} + #ifdef CONFIG_IWLWIFI_PCIE_RTPM static int iwl_pci_runtime_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct iwl_trans *trans = pci_get_drvdata(pdev); + int ret; IWL_DEBUG_RPM(trans, "entering runtime suspend\n"); - /* For now we only allow D0I3 if the device is off */ - if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) - return -EBUSY; + if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) { + ret = iwl_pci_fw_enter_d0i3(trans); + if (ret < 0) + return ret; + } trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3; @@ -729,7 +802,8 @@ static int iwl_pci_runtime_resume(struct device *device) iwl_trans_d3_resume(trans, &d3_status, false); - trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + return iwl_pci_fw_exit_d0i3(trans); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index bdda7028c393..7bc02e0cdd93 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -2,6 +2,7 @@ * * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -374,6 +375,7 @@ struct iwl_trans_pcie { bool ucode_write_complete; wait_queue_head_t ucode_write_waitq; wait_queue_head_t wait_command_queue; + wait_queue_head_t d0i3_waitq; u8 cmd_queue; u8 cmd_fifo; @@ -594,4 +596,7 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) } #endif +int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans); +int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans); + #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index db94fe1e1bc6..cfdc7f6e554a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -72,9 +72,7 @@ #include #include #include -#ifdef CONFIG_IWLWIFI_PCIE_RTPM #include -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ #include "iwl-drv.h" #include "iwl-trans.h" @@ -1197,9 +1195,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) if (hw_rfkill != was_hw_rfkill) iwl_trans_pcie_rf_kill(trans, hw_rfkill); -#ifdef CONFIG_IWLWIFI_PCIE_RTPM - pm_runtime_put_sync(trans->dev); -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ /* re-take ownership to prevent other users from stealing the deivce */ iwl_pcie_prepare_card_hw(trans); } @@ -1359,9 +1354,10 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) /* ... rfkill can call stop_device and set it false if needed */ iwl_trans_pcie_rf_kill(trans, hw_rfkill); -#ifdef CONFIG_IWLWIFI_PCIE_RTPM - pm_runtime_get_sync(trans->dev); -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ + /* Make sure we sync here, because we'll need full access later */ + if (low_power) + pm_runtime_resume(trans->dev); + return 0; } @@ -1485,10 +1481,9 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; -#ifdef CONFIG_IWLWIFI_PCIE_RTPM /* TODO: check if this is really needed */ pm_runtime_disable(trans->dev); -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ + synchronize_irq(trans_pcie->pci_dev->irq); iwl_pcie_tx_free(trans); @@ -1844,9 +1839,7 @@ void iwl_trans_pcie_ref(struct iwl_trans *trans) spin_lock_irqsave(&trans_pcie->ref_lock, flags); IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count); trans_pcie->ref_count++; -#ifdef CONFIG_IWLWIFI_PCIE_RTPM pm_runtime_get(&trans_pcie->pci_dev->dev); -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); } @@ -1865,10 +1858,9 @@ void iwl_trans_pcie_unref(struct iwl_trans *trans) return; } trans_pcie->ref_count--; -#ifdef CONFIG_IWLWIFI_PCIE_RTPM + pm_runtime_mark_last_busy(&trans_pcie->pci_dev->dev); pm_runtime_put_autosuspend(&trans_pcie->pci_dev->dev); -#endif /* CONFIG_IWLWIFI_PCIE_RTPM */ spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); } @@ -2536,6 +2528,22 @@ static struct iwl_trans_dump_data return dump_data; } +#ifdef CONFIG_PM_SLEEP +static int iwl_trans_pcie_suspend(struct iwl_trans *trans) +{ + if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3) + return iwl_pci_fw_enter_d0i3(trans); + + return 0; +} + +static void iwl_trans_pcie_resume(struct iwl_trans *trans) +{ + if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3) + iwl_pci_fw_exit_d0i3(trans); +} +#endif /* CONFIG_PM_SLEEP */ + static const struct iwl_trans_ops trans_ops_pcie = { .start_hw = iwl_trans_pcie_start_hw, .op_mode_leave = iwl_trans_pcie_op_mode_leave, @@ -2546,6 +2554,11 @@ static const struct iwl_trans_ops trans_ops_pcie = { .d3_suspend = iwl_trans_pcie_d3_suspend, .d3_resume = iwl_trans_pcie_d3_resume, +#ifdef CONFIG_PM_SLEEP + .suspend = iwl_trans_pcie_suspend, + .resume = iwl_trans_pcie_resume, +#endif /* CONFIG_PM_SLEEP */ + .send_cmd = iwl_trans_pcie_send_hcmd, .tx = iwl_trans_pcie_tx, @@ -2735,6 +2748,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); + init_waitqueue_head(&trans_pcie->d0i3_waitq); + ret = iwl_pcie_alloc_ict(trans); if (ret) goto out_pci_disable_msi; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index b0b0fd9e2eff..c499345ba526 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1,7 +1,8 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -1727,6 +1728,20 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, wake_up(&trans_pcie->wait_command_queue); } + if (meta->flags & CMD_MAKE_TRANS_IDLE) { + IWL_DEBUG_INFO(trans, "complete %s - mark trans as idle\n", + iwl_get_cmd_string(trans, cmd->hdr.cmd)); + set_bit(STATUS_TRANS_IDLE, &trans->status); + wake_up(&trans_pcie->d0i3_waitq); + } + + if (meta->flags & CMD_WAKE_UP_TRANS) { + IWL_DEBUG_INFO(trans, "complete %s - clear trans idle flag\n", + iwl_get_cmd_string(trans, cmd->hdr.cmd)); + clear_bit(STATUS_TRANS_IDLE, &trans->status); + wake_up(&trans_pcie->d0i3_waitq); + } + meta->flags = 0; spin_unlock_bh(&txq->lock); -- cgit v1.2.3 From 23ae61282b88873bec2d56c78fea531f8485146c Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Thu, 31 Dec 2015 18:18:02 +0200 Subject: iwlwifi: mvm: Do not switch to D3 image on suspend Currently when the driver is configured with wowlan parameters, and enters D3 mode, the driver switches the FW image to D3, and when it exists suspend, it reloads the D0 image. If the firmware supports the consolidation of the D0 & D3 images there is no need to load the D3 image on suspend, and no need to reload the D0 image on resume. Do not switch images on suspend / resume, for firmwares that support consolidated images. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 4 +- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 13 +++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 70 ++++++++++++++++------- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 11 ++-- 7 files changed, 70 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 29ea1c6705b4..4db4cb7aa73a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -396,7 +396,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - iwl_trans_d3_suspend(priv->trans, false); + iwl_trans_d3_suspend(priv->trans, false, true); goto out; @@ -469,7 +469,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) /* we'll clear ctx->vif during iwlagn_prepare_restart() */ vif = ctx->vif; - ret = iwl_trans_d3_resume(priv->trans, &d3_status, false); + ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true); if (ret) goto out_unlock; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 84f8aeb926c8..2273908ad83a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -297,6 +297,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), * which also implies support for the scheduler configuration command * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching + * @IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload @@ -330,6 +331,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = (__force iwl_ucode_tlv_capa_t)11, IWL_UCODE_TLV_CAPA_DQA_SUPPORT = (__force iwl_ucode_tlv_capa_t)12, IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG = (__force iwl_ucode_tlv_capa_t)17, IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18, IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index fe170a3fb1a6..e6a5e99f95e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -618,9 +618,9 @@ struct iwl_trans_ops { void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); void (*stop_device)(struct iwl_trans *trans, bool low_power); - void (*d3_suspend)(struct iwl_trans *trans, bool test); + void (*d3_suspend)(struct iwl_trans *trans, bool test, bool reset); int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test); + bool test, bool reset); int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); @@ -925,22 +925,23 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) _iwl_trans_stop_device(trans, true); } -static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) +static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, + bool reset) { might_sleep(); if (trans->ops->d3_suspend) - trans->ops->d3_suspend(trans, test); + trans->ops->d3_suspend(trans, test, reset); } static inline int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test) + bool test, bool reset) { might_sleep(); if (!trans->ops->d3_resume) return 0; - return trans->ops->d3_resume(trans, status, test); + return trans->ops->d3_resume(trans, status, test, reset); } static inline void iwl_trans_ref(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d3e21d95cece..78572ef89b26 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1023,14 +1025,18 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, struct ieee80211_sta *ap_sta) { int ret; + bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - ret = iwl_mvm_switch_to_d3(mvm); - if (ret) - return ret; + if (!unified_image) { + ret = iwl_mvm_switch_to_d3(mvm); + if (ret) + return ret; - ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); - if (ret) - return ret; + ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); + if (ret) + return ret; + } if (!iwlwifi_mod_params.sw_crypto) { /* @@ -1072,10 +1078,14 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm, { struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; int ret; + bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - ret = iwl_mvm_switch_to_d3(mvm); - if (ret) - return ret; + if (!unified_image) { + ret = iwl_mvm_switch_to_d3(mvm); + if (ret) + return ret; + } /* rfkill release can be either for wowlan or netdetect */ if (wowlan->rfkill_release) @@ -1151,6 +1161,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, }; int ret; int len __maybe_unused; + bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); if (!wowlan) { /* @@ -1236,7 +1248,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - iwl_trans_d3_suspend(mvm->trans, test); + iwl_trans_d3_suspend(mvm->trans, test, !unified_image); out: if (ret < 0) { iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -1299,7 +1311,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); - iwl_trans_d3_suspend(trans, false); + iwl_trans_d3_suspend(trans, false, false); return 0; } @@ -2041,9 +2053,14 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) { struct ieee80211_vif *vif = NULL; - int ret; + int ret = 1; enum iwl_d3_status d3_status; bool keep = false; + bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); + + u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | + CMD_WAKE_UP_TRANS; mutex_lock(&mvm->mutex); @@ -2052,7 +2069,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) if (IS_ERR_OR_NULL(vif)) goto err; - ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); + ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !unified_image); if (ret) goto err; @@ -2095,17 +2112,28 @@ out_iterate: iwl_mvm_d3_disconnect_iter, keep ? vif : NULL); out: - /* return 1 to reconfigure the device */ + if (unified_image && !ret) { + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); + if (!ret) /* D3 ended successfully - no need to reset device */ + return 0; + } + + /* + * Reconfigure the device in one of the following cases: + * 1. We are not using a unified image + * 2. We are using a unified image but had an error while exiting D3 + */ set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status); - - /* We always return 1, which causes mac80211 to do a reconfig - * with IEEE80211_RECONFIG_TYPE_RESTART. This type of - * reconfig calls iwl_mvm_restart_complete(), where we unref - * the IWL_MVM_REF_UCODE_DOWN, so we need to take the - * reference here. + /* + * When switching images we return 1, which causes mac80211 + * to do a reconfig with IEEE80211_RECONFIG_TYPE_RESTART. + * This type of reconfig calls iwl_mvm_restart_complete(), + * where we unref the IWL_MVM_REF_UCODE_DOWN, so we need + * to take the reference here. */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + return 1; } @@ -2122,7 +2150,7 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) enum iwl_d3_status d3_status; struct iwl_trans *trans = mvm->trans; - iwl_trans_d3_resume(trans, &d3_status, false); + iwl_trans_d3_resume(trans, &d3_status, false, false); /* * make sure to clear D0I3_DEFER_WAKEUP before diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 9a15642f80dd..0476e7688e9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1109,7 +1109,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params, vif)); - if (type == IWL_MVM_SCAN_SCHED) + if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); if (iwl_mvm_scan_use_ebs(mvm, vif)) @@ -1351,7 +1351,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, IWL_MVM_SCAN_SCHED); + ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, type); } else { hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; ret = iwl_mvm_scan_lmac(mvm, vif, ¶ms); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 16b579a5aa6b..762e7c4d96b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -787,7 +787,7 @@ static int iwl_pci_runtime_suspend(struct device *device) trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3; - iwl_trans_d3_suspend(trans, false); + iwl_trans_d3_suspend(trans, false, false); return 0; } @@ -800,7 +800,7 @@ static int iwl_pci_runtime_resume(struct device *device) IWL_DEBUG_RPM(trans, "exiting runtime suspend (resume)\n"); - iwl_trans_d3_resume(trans, &d3_status, false); + iwl_trans_d3_resume(trans, &d3_status, false, false); if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) return iwl_pci_fw_exit_d0i3(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index cfdc7f6e554a..abe091698471 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1219,11 +1219,12 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) _iwl_trans_pcie_stop_device(trans, true); } -static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) +static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, + bool reset) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) { + if (!reset) { /* Enable persistence mode to avoid reset */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PERSIST_MODE); @@ -1247,7 +1248,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D3) { + if (reset) { /* * reset TX queues -- some of their registers reset during S3 * so if we don't reset everything here the D3 image would try @@ -1261,7 +1262,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test) + bool test, bool reset) { u32 val; int ret; @@ -1296,7 +1297,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, false); - if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) { + if (!reset) { iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } else { -- cgit v1.2.3 From 15ffd075e4088d3fc83ce8db914e7d3b6f31bc1c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 24 Jan 2016 23:04:22 +0200 Subject: iwlwifi: various comments and code cleanups No need to include net/ip6_checksum.h twice. Remove TODOs. Remove trailing space. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 - drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 1 - 4 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index e6a5e99f95e0..0ca0f13b69b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -506,7 +506,7 @@ struct iwl_trans_config { bool sw_csum_tx; const struct iwl_hcmd_arr *command_groups; int command_groups_size; - + u32 sdio_adma_addr; }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index fb6d341d6f3d..ab467cb9b97c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -287,16 +287,13 @@ enum iwl_rx_mpdu_status { IWL_RX_MPDU_STATUS_KEY_ERROR = BIT(4), IWL_RX_MPDU_STATUS_ICV_OK = BIT(5), IWL_RX_MPDU_STATUS_MIC_OK = BIT(6), - /* TODO - verify this is the correct value */ IWL_RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), IWL_RX_MPDU_STATUS_SEC_MASK = 0x7 << 8, IWL_RX_MPDU_STATUS_SEC_NONE = 0x0 << 8, IWL_RX_MPDU_STATUS_SEC_WEP = 0x1 << 8, IWL_RX_MPDU_STATUS_SEC_CCM = 0x2 << 8, IWL_RX_MPDU_STATUS_SEC_TKIP = 0x3 << 8, - /* TODO - define IWL_RX_MPDU_STATUS_SEC_EXT_ENC - this is a stub */ IWL_RX_MPDU_STATUS_SEC_EXT_ENC = 0x4 << 8, - /* TODO - define IWL_RX_MPDU_STATUS_SEC_GCM - this is a stub */ IWL_RX_MPDU_STATUS_SEC_GCM = 0x5 << 8, IWL_RX_MPDU_STATUS_DECRYPTED = BIT(11), IWL_RX_MPDU_STATUS_WEP_MATCH = BIT(12), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 89ea70deeb84..6bf2bde239a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -392,7 +392,6 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = { [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names), }; - /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); static void iwl_mvm_d0i3_exit_work(struct work_struct *wk); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index c499345ba526..837a7d536874 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "iwl-debug.h" #include "iwl-csr.h" -- cgit v1.2.3 From bdf408eca877a2ae310e3df9f05e865ffe10e4de Mon Sep 17 00:00:00 2001 From: Hubert Tarasiuk Date: Sun, 24 Jan 2016 13:35:06 +0100 Subject: iwlwifi: dvm: handle zero brightness for wifi LED In order to have the LED being OFF constantly when the brightness is set to 0, we need to pass IWL_LED_SOLID to iwl_led_cmd as the off parameter, otherwise the led will stay on constantly. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=110551 Signed-off-by: Hubert Tarasiuk [reworked the commit message] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/dvm/led.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.c b/drivers/net/wireless/intel/iwlwifi/dvm/led.c index 1aabb5ec096f..1bbd17ada974 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.c @@ -152,11 +152,14 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev, { struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); unsigned long on = 0; + unsigned long off = 0; if (brightness > 0) on = IWL_LED_SOLID; + else + off = IWL_LED_SOLID; - iwl_led_cmd(priv, on, 0); + iwl_led_cmd(priv, on, off); } static int iwl_led_blink_set(struct led_classdev *led_cdev, -- cgit v1.2.3 From d1cae0fd22e9d0c55c97da29dcdfe28d99d96ea6 Mon Sep 17 00:00:00 2001 From: Rodrigo Freire Date: Wed, 6 Jan 2016 20:24:01 -0200 Subject: iwlwifi: Document missing module options This patch documents two missing module options in the internal code comment block. Signed-off-by: Rodrigo Freire Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index fd42f63f5e84..b88ecc7892a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -108,6 +108,8 @@ enum iwl_amsdu_size { * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 + * @nvm_file: specifies a external NVM file + * @uapsd_disable: disable U-APSD, default = 1 * @d0i3_disable: disable d0i3, default = 1, * @d0i3_entry_delay: time to wait after no refs are taken before * entering D0i3 (in msecs) -- cgit v1.2.3 From 25657fec94f87308da19bb3d5063feef04d5ba20 Mon Sep 17 00:00:00 2001 From: Golan Ben-Ami Date: Wed, 2 Sep 2015 12:34:23 +0300 Subject: iwlwifi: mvm: add trigger for firmware dump upon TX response status This will allow to collect the data when the firmware sends a specific tx response status. Signed-off-by: Golan Ben-Ami Signed-off-by: Emmanuel Grumbach --- .../net/wireless/intel/iwlwifi/iwl-fw-error-dump.h | 3 ++ drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 13 +++++++++ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 33 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h index a5aaf6853704..8425e1a587d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h @@ -293,6 +293,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a * threshold. * @FW_DBG_TDLS: trigger log collection upon TDLS related events. + * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when + * the firmware sends a tx reply. */ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_INVALID = 0, @@ -309,6 +311,7 @@ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_BA, FW_DBG_TRIGGER_TX_LATENCY, FW_DBG_TRIGGER_TDLS, + FW_DBG_TRIGGER_TX_STATUS, /* must be last */ FW_DBG_TRIGGER_MAX, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 2273908ad83a..4050b4af7e45 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -749,6 +749,19 @@ struct iwl_fw_dbg_trigger_tdls { u8 reserved[4]; } __packed; +/** + * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response + * status. + * @statuses: the list of statuses to trigger the collection on + */ +struct iwl_fw_dbg_trigger_tx_status { + struct tx_status { + u8 status; + u8 reserved[3]; + } __packed statuses[16]; + __le32 reserved[2]; +} __packed; + /** * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration. * @id: conf id diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8bf48a7d0f4e..5d73db2534a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -736,6 +736,37 @@ static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags, iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r); } +static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, + u32 status) +{ + struct iwl_fw_dbg_trigger_tlv *trig; + struct iwl_fw_dbg_trigger_tx_status *status_trig; + int i; + + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS)) + return; + + trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS); + status_trig = (void *)trig->data; + + if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig)) + return; + + for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) { + /* don't collect on status 0 */ + if (!status_trig->statuses[i].status) + break; + + if (status_trig->statuses[i].status != (status & TX_STATUS_MSK)) + continue; + + iwl_mvm_fw_dbg_collect_trig(mvm, trig, + "Tx status %d was received", + status & TX_STATUS_MSK); + break; + } +} + static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { @@ -784,6 +815,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, break; } + iwl_mvm_tx_status_check_trigger(mvm, status); + info->status.rates[0].count = tx_resp->failure_frame + 1; iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate), info); -- cgit v1.2.3 From ee95ed3728cb3ed70b76fb770fff66133ff8b1fa Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 25 Nov 2015 13:17:10 +0200 Subject: iwlwifi: mvm: Add P2P client snoozing Enable snoozing and U-APSD on P2P client. The firwmare will support this only if the BSS vif is not associated. Make this configurable by a constant variable and disable it by default. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 +++++ drivers/net/wireless/intel/iwlwifi/mvm/power.c | 39 ++++++++++++++++++++-- 4 files changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 4050b4af7e45..dbf08c493654 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -302,6 +302,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics + * @IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different * sources for the MCC. This TLV bit is a future replacement to @@ -336,6 +337,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22, + IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD = (__force iwl_ucode_tlv_capa_t)26, IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index b00c03fcd447..959fc4d33d16 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -73,6 +73,7 @@ #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */ #define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */ +#define IWL_MVM_P2P_UAPSD_STANDALONE 0 #define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE 0 #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5f3ac8cccf49..5a92ab1b3787 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1005,6 +1005,14 @@ static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm) IWL_MVM_BT_COEX_MPLUT; } +static inline +bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm) +{ + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD) && + IWL_MVM_P2P_UAPSD_STANDALONE; +} + static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm) { /* firmware flag isn't defined yet */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 9de159f1ef2d..16b3e36fb1ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -259,6 +259,26 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; } +static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + bool *is_p2p_standalone = _data; + + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + *is_p2p_standalone = false; + break; + case NL80211_IFTYPE_STATION: + if (vif->bss_conf.assoc) + *is_p2p_standalone = false; + break; + + default: + break; + } +} + static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -268,9 +288,6 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, ETH_ALEN)) return false; - if (vif->p2p && - !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD)) - return false; /* * Avoid using uAPSD if P2P client is associated to GO that uses * opportunistic power save. This is due to current FW limitation. @@ -287,6 +304,22 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, if (iwl_mvm_phy_ctx_count(mvm) >= 2) return false; + if (vif->p2p) { + /* Allow U-APSD only if p2p is stand alone */ + bool is_p2p_standalone = true; + + if (!iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) + return false; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_p2p_standalone_iterator, + &is_p2p_standalone); + + if (!is_p2p_standalone) + return false; + } + return true; } -- cgit v1.2.3 From 33efe947e797c0f26b81bfe1b1eaf53501a6cd8e Mon Sep 17 00:00:00 2001 From: Golan Ben-Ami Date: Wed, 23 Dec 2015 17:53:27 +0200 Subject: iwlwifi: mvm: make collecting fw debug data optional Slow platforms may have issues with dumping data upon firmware assert. Make it easier to disable it for those platform. Signed-off-by: Golan Ben-Ami Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 7 +++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 959fc4d33d16..4b560e4417ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -6,7 +6,8 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +33,8 @@ * BSD LICENSE * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -108,6 +110,7 @@ #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1 #define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_SW_TX_CSUM_OFFLOAD 0 +#define IWL_MVM_COLLECT_FW_ERR_DUMP 1 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index 0813f8184e10..94ec3f0c15cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -435,6 +435,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) bool monitor_dump_only = false; int i; + if (!IWL_MVM_COLLECT_FW_ERR_DUMP && + !mvm->trans->dbg_dest_tlv) + return; + lockdep_assert_held(&mvm->mutex); /* there's no point in fw dump if the bus is dead */ -- cgit v1.2.3 From d8f7c5115d09e4b6b72b5b33414853aaa39bf837 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jan 2016 10:46:38 +0100 Subject: iwlwifi: mvm: remove shadowing variable The outer scope has a perfectly suitable 'i' variable, use it instead of adding a shadowing one in the inner scope. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index 94ec3f0c15cf..4856eac120f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -644,8 +644,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) /* Dump fw's virtual image */ if (mvm->fw->img[mvm->cur_ucode].paging_mem_size) { - u32 i; - for (i = 1; i < mvm->num_of_paging_blk + 1; i++) { struct iwl_fw_error_dump_paging *paging; struct page *pages = -- cgit v1.2.3 From 27e070d3d3c2f6ab925ffd7c54814cabd95db51c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jan 2016 10:55:22 +0100 Subject: iwlwifi: mvm: fix debugfs signedness warning Using kstrtouint() with a signed int isn't really right, use kstrotoint() instead. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 90500e2d107b..8059efafcb80 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -983,7 +983,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm, trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) return -EOPNOTSUPP; - ret = kstrtouint(buf, 0, &rec_mode); + ret = kstrtoint(buf, 0, &rec_mode); if (ret) return ret; -- cgit v1.2.3 From 7869318e4296e27d4cb97505e8739d62b48b2d58 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Sun, 27 Dec 2015 13:45:42 +0200 Subject: iwlwifi: mvm: add support for negative temperatures The driver should support also negative temperatures. So there is a need to separate between the return value and temperature in order to be able to distinguish between a negative temperature and error value. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 9 +++++---- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 17 ++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 8059efafcb80..5c0f93997b7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -261,17 +261,18 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, { struct iwl_mvm *mvm = file->private_data; char buf[16]; - int pos, temp; + int pos, ret; + s32 temp; if (!mvm->ucode_loaded) return -EIO; mutex_lock(&mvm->mutex); - temp = iwl_mvm_get_temp(mvm); + ret = iwl_mvm_get_temp(mvm, &temp); mutex_unlock(&mvm->mutex); - if (temp < 0) - return temp; + if (ret) + return -EIO; pos = scnprintf(buf , sizeof(buf), "%d\n", temp); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5a92ab1b3787..216c8d6275a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1489,7 +1489,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm); void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); void iwl_mvm_tt_exit(struct iwl_mvm *mvm); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); -int iwl_mvm_get_temp(struct iwl_mvm *mvm); +int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp); /* Location Aware Regulatory */ struct iwl_mcc_update_resp * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index fb76004eede4..758d05a8c6aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -194,12 +194,12 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd); } -int iwl_mvm_get_temp(struct iwl_mvm *mvm) +int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp) { struct iwl_notification_wait wait_temp_notif; static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE) }; - int ret, temp; + int ret; if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR)) temp_notif[0] = DTS_MEASUREMENT_NOTIFICATION; @@ -208,7 +208,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm) iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, temp_notif, ARRAY_SIZE(temp_notif), - iwl_mvm_temp_notif_wait, &temp); + iwl_mvm_temp_notif_wait, temp); ret = iwl_mvm_get_temp_cmd(mvm); if (ret) { @@ -219,12 +219,10 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm) ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); - if (ret) { + if (ret) IWL_ERR(mvm, "Getting the temperature timed out\n"); - return ret; - } - return temp; + return ret; } static void check_exit_ctkill(struct work_struct *work) @@ -233,6 +231,7 @@ static void check_exit_ctkill(struct work_struct *work) struct iwl_mvm *mvm; u32 duration; s32 temp; + int ret; tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work); mvm = container_of(tt, struct iwl_mvm, thermal_throttle); @@ -250,13 +249,13 @@ static void check_exit_ctkill(struct work_struct *work) goto reschedule; } - temp = iwl_mvm_get_temp(mvm); + ret = iwl_mvm_get_temp(mvm, &temp); iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); __iwl_mvm_mac_stop(mvm); - if (temp < 0) + if (ret) goto reschedule; IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); -- cgit v1.2.3 From 0db056d32490181be48efc2ca7cfa7494b13e6b5 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 29 Dec 2015 11:07:15 +0200 Subject: iwlwifi: mvm: support beacon storing Currently firmware is configured to filter out beacons. In case a beacon was changed - it is waking the host. However, some vendors change their IEs frequently without any significant change, and redundant wakeups are triggered as a result. As a solution disable beacon filtering when entering d0i3. Instead, firmware will store the latest beacon and upon exiting d0i3 it will send it up to the host, so the host can act upon changes (if there were any). This beacon will arrive as a dedicated notification - support it as well. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 3 ++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 29 +++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 41 ++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 22 ++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 33 ++++++++++++----- 8 files changed, 120 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index dbf08c493654..5152987c8b8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -315,6 +315,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what * antenna the beacon should be transmitted + * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon + * from AP and will send it upon d0i3 exit. * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used @@ -346,6 +348,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, + IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, NUM_IWL_UCODE_TLV_CAPA diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 78572ef89b26..346376187ef8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -853,7 +853,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; wowlan_config_cmd->flags = ENABLE_L3_FILTERING | - ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; + ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING | + ENABLE_STORE_BEACON; /* Query the last used seqno and set it */ ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index 62b9a0a96700..eec52c57f718 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -251,6 +251,7 @@ enum iwl_wowlan_flags { ENABLE_L3_FILTERING = BIT(1), ENABLE_NBNS_FILTERING = BIT(2), ENABLE_DHCP_FILTERING = BIT(3), + ENABLE_STORE_BEACON = BIT(4), }; struct iwl_wowlan_config_cmd { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 82049bb139c2..b6b57273b8ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -280,11 +280,16 @@ enum iwl_phy_ops_subcmd_ids { DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; +enum iwl_prot_offload_subcmd_ids { + STORED_BEACON_NTF = 0xFF, +}; + /* command groups */ enum { LEGACY_GROUP = 0x0, LONG_GROUP = 0x1, PHY_OPS_GROUP = 0x4, + PROT_OFFLOAD_GROUP = 0xb, }; /** @@ -1851,4 +1856,28 @@ struct iwl_shared_mem_cfg { __le32 page_buff_size; } __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ +#define MAX_STORED_BEACON_SIZE 600 + +/** + * Stored beacon notification + * + * @system_time: system time on air rise + * @tsf: TSF on air rise + * @beacon_timestamp: beacon on air rise + * @phy_flags: general phy flags: band, modulation, etc. + * @channel: channel this beacon was received on + * @rates: rate in ucode internal format + * @byte_count: frame's byte count + */ +struct iwl_stored_beacon_notif { + __le32 system_time; + __le64 tsf; + __le32 beacon_timestamp; + __le16 phy_flags; + __le16 channel; + __le32 rates; + __le32 byte_count; + u8 data[MAX_STORED_BEACON_SIZE]; +} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index bf1e5eb5dbdb..62927f567afc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1462,3 +1462,40 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, iwl_mvm_beacon_loss_iterator, mb); } + +void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_stored_beacon_notif *sb = (void *)pkt->data; + struct ieee80211_rx_status rx_status; + struct sk_buff *skb; + u32 size = le32_to_cpu(sb->byte_count); + + if (size == 0) + return; + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + IWL_ERR(mvm, "alloc_skb failed\n"); + return; + } + + /* update rx_status according to the notification's metadata */ + memset(&rx_status, 0, sizeof(rx_status)); + rx_status.mactime = le64_to_cpu(sb->tsf); + rx_status.device_timestamp = le32_to_cpu(sb->system_time); + rx_status.band = + (sb->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(sb->channel), + rx_status.band); + + /* copy the data */ + memcpy(skb_put(skb, size), sb->data, size); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + + /* pass it as regular rx to mac80211 */ + ieee80211_rx_napi(mvm->hw, skb, NULL); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 216c8d6275a1..b45cf4f63781 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1192,6 +1192,8 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 6bf2bde239a0..3c869ad6aaec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -33,6 +33,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -267,6 +268,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { true), RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true), + RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, + iwl_mvm_rx_stored_beacon_notif, false), }; #undef RX_HANDLER @@ -386,10 +389,18 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), }; +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = { + HCMD_NAME(STORED_BEACON_NTF), +}; + static const struct iwl_hcmd_arr iwl_mvm_groups[] = { [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names), + [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names), }; /* this forward declaration can avoid to export the function */ @@ -1195,7 +1206,7 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; cmd->offloading_tid = iter_data->offloading_tid; cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | - ENABLE_DHCP_FILTERING; + ENABLE_DHCP_FILTERING | ENABLE_STORE_BEACON; /* * The d0i3 uCode takes care of the nonqos counters, * so configure only the qos seq ones. @@ -1216,8 +1227,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) struct iwl_wowlan_config_cmd wowlan_config_cmd = { .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | IWL_WOWLAN_WAKEUP_BEACON_MISS | - IWL_WOWLAN_WAKEUP_LINK_CHANGE | - IWL_WOWLAN_WAKEUP_BCN_FILTERING), + IWL_WOWLAN_WAKEUP_LINK_CHANGE), }; struct iwl_d3_manager_config d3_cfg_cmd = { .min_sleep_time = cpu_to_le32(1000), @@ -1267,6 +1277,12 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) /* configure wowlan configuration only if needed */ if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) { + /* wake on beacons only if beacon storing isn't supported */ + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BEACON_STORING)) + wowlan_config_cmd.wakeup_filter |= + cpu_to_le32(IWL_WOWLAN_WAKEUP_BCN_FILTERING); + iwl_mvm_wowlan_config_key_params(mvm, d0i3_iter_data.connected_vif, true, flags); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 16b3e36fb1ba..0d03b3e3cf4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -903,9 +903,9 @@ static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false); } -int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 flags) +static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 flags, bool d0i3) { struct iwl_beacon_filter_cmd cmd = {}; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -916,12 +916,20 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags); - if (!ret) + /* don't change bf_enabled in case of temporary d0i3 configuration */ + if (!ret && !d0i3) mvmvif->bf_data.bf_enabled = false; return ret; } +int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 flags) +{ + return _iwl_mvm_disable_beacon_filter(mvm, vif, flags, false); +} + static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm) { bool disable_ps; @@ -1058,8 +1066,17 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, IWL_BF_CMD_CONFIG_D0I3, .bf_enable_beacon_filter = cpu_to_le32(1), }; - ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, - flags, true); + /* + * When beacon storing is supported - disable beacon filtering + * altogether - the latest beacon will be sent when exiting d0i3 + */ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BEACON_STORING)) + ret = _iwl_mvm_disable_beacon_filter(mvm, vif, flags, + true); + else + ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, + flags, true); } else { if (mvmvif->bf_data.bf_enabled) ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags); -- cgit v1.2.3 From b525d08125e61e262be63ea250e3e13e93b6a92a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Jan 2016 10:01:41 +0100 Subject: iwlwifi: mvm: track low-latency sources separately To be able to test low-latency behaviour properly, split the different low-latency sources so that setting any one of them, for example from debugfs, is sufficient; this avoids getting the debug setting overwritten by other sources. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 19 ++++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 12 +++++++----- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 6 ++---- 3 files changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 9e0d46368cdd..c286a5f8d8bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1255,6 +1257,7 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; + bool prev; u8 value; int ret; @@ -1265,7 +1268,9 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, return -EINVAL; mutex_lock(&mvm->mutex); - iwl_mvm_update_low_latency(mvm, vif, value); + prev = iwl_mvm_vif_low_latency(mvmvif); + mvmvif->low_latency_dbgfs = value; + iwl_mvm_update_low_latency(mvm, vif, prev); mutex_unlock(&mvm->mutex); return count; @@ -1277,11 +1282,15 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, { struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - char buf[2]; + char buf[30] = {}; + int len; - buf[0] = mvmvif->low_latency ? '1' : '0'; - buf[1] = '\n'; - return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); + len = snprintf(buf, sizeof(buf) - 1, + "traffic=%d\ndbgfs=%d\nvcmd=%d\n", + mvmvif->low_latency_traffic, + mvmvif->low_latency_dbgfs, + mvmvif->low_latency_vcmd); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b45cf4f63781..418aeffd9bab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -346,8 +346,9 @@ struct iwl_mvm_vif_bf_data { * @pm_enabled - Indicate if MAC power management is allowed * @monitor_active: indicates that monitor context is configured, and that the * interface should get quota etc. - * @low_latency: indicates that this interface is in low-latency mode - * (VMACLowLatencyMode) + * @low_latency_traffic: indicates low latency traffic was detected + * @low_latency_dbgfs: low latency mode set from debugfs + * @low_latency_vcmd: low latency mode set from vendor command * @ps_disabled: indicates that this interface requires PS to be disabled * @queue_params: QoS params for this MAC * @bcast_sta: station used for broadcast packets. Used by the following @@ -375,7 +376,7 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; - bool low_latency; + bool low_latency_traffic, low_latency_dbgfs, low_latency_vcmd; bool ps_disabled; struct iwl_mvm_vif_bf_data bf_data; @@ -1427,8 +1428,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) * binding, so this has no real impact. For now, just return * the current desired low-latency state. */ - - return mvmvif->low_latency; + return mvmvif->low_latency_dbgfs || + mvmvif->low_latency_traffic || + mvmvif->low_latency_vcmd; } /* hw scheduler queue config */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 3a989f5c20db..59453c176580 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -937,18 +937,16 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) } int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - bool value) + bool prev) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int res; lockdep_assert_held(&mvm->mutex); - if (mvmvif->low_latency == value) + if (iwl_mvm_vif_low_latency(mvmvif) == prev) return 0; - mvmvif->low_latency = value; - res = iwl_mvm_update_quotas(mvm, false, NULL); if (res) return res; -- cgit v1.2.3 From a80c1cf9b4b2937cfe782aba7b54a5144fe7eec2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jan 2016 15:01:00 +0100 Subject: iwlwifi: mvm: support setting minimum quota from debugfs For debug purposes, allow setting minimum quota (for a single virtual interface) from debugfs. This is an absolute minimum, so it can only be set up to 95%. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 56 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/quota.c | 16 +++++++ 3 files changed, 73 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index c286a5f8d8bd..14004456bf55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1372,6 +1372,59 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); } +static void iwl_dbgfs_quota_check(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int *ret = data; + + if (mvmvif->dbgfs_quota_min) + *ret = -EINVAL; +} + +static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + u16 value; + int ret; + + ret = kstrtou16(buf, 0, &value); + if (ret) + return ret; + + if (value > 95) + return -EINVAL; + + mutex_lock(&mvm->mutex); + + mvmvif->dbgfs_quota_min = 0; + ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_dbgfs_quota_check, &ret); + if (ret == 0) { + mvmvif->dbgfs_quota_min = value; + iwl_mvm_update_quotas(mvm, false, NULL); + } + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_quota_min_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + char buf[10]; + int len; + + len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -1395,6 +1448,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -1432,6 +1486,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 418aeffd9bab..5a34808fdeed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -433,6 +433,7 @@ struct iwl_mvm_vif { struct iwl_dbgfs_pm dbgfs_pm; struct iwl_dbgfs_bf dbgfs_bf; struct iwl_mac_power_cmd mac_pwr_cmd; + int dbgfs_quota_min; #endif enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c index 0b762b4f8fad..2141db5bff82 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -74,6 +76,9 @@ struct iwl_mvm_quota_iterator_data { int n_interfaces[MAX_BINDINGS]; int colors[MAX_BINDINGS]; int low_latency[MAX_BINDINGS]; +#ifdef CONFIG_IWLWIFI_DEBUGFS + int dbgfs_min[MAX_BINDINGS]; +#endif int n_low_latency_bindings; struct ieee80211_vif *disabled_vif; }; @@ -129,6 +134,12 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, data->n_interfaces[id]++; +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvmvif->dbgfs_quota_min) + data->dbgfs_min[id] = max(data->dbgfs_min[id], + mvmvif->dbgfs_quota_min); +#endif + if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) { data->n_low_latency_bindings++; data->low_latency[id] = true; @@ -259,6 +270,11 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, if (data.n_interfaces[i] <= 0) cmd.quotas[idx].quota = cpu_to_le32(0); +#ifdef CONFIG_IWLWIFI_DEBUGFS + else if (data.dbgfs_min[i]) + cmd.quotas[idx].quota = + cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100); +#endif else if (data.n_low_latency_bindings == 1 && n_non_lowlat && data.low_latency[i]) /* -- cgit v1.2.3 From 0c1c6e37137fc2333ef9898c24ea0cb9efbd8df0 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 16 Dec 2015 21:17:06 +0200 Subject: iwlwifi: mvm: change access to ieee80211_hdr Make the code clearer. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 0c073e02fd4c..4cce37238a08 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -294,7 +294,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct ieee80211_rx_status *rx_status; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; - struct ieee80211_hdr *hdr = (void *)(desc + 1); + struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc)); u32 len = le16_to_cpu(desc->mpdu_len); u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); struct ieee80211_sta *sta = NULL; -- cgit v1.2.3 From 1c4e15a23d27e2efd56d2b9b7436bff060f126ef Mon Sep 17 00:00:00 2001 From: Max Stepanov Date: Mon, 4 Jan 2016 11:09:14 +0200 Subject: iwlwifi: mvm: add debug print if scan config is ignored Print a debug message in iwl_mvm_config_scan() if a scan configuration data is decided not to be sent to FW. Signed-off-by: Max Stepanov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 0476e7688e9b..1e1ab9daaec9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -930,8 +930,11 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) return -ENOBUFS; - if (type == mvm->scan_type) + if (type == mvm->scan_type) { + IWL_DEBUG_SCAN(mvm, + "Ignoring UMAC scan config of the same type\n"); return 0; + } cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels; -- cgit v1.2.3 From 837c4da98481d4e504b2aba077c8528fee1b6d13 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 7 Jan 2016 16:50:45 +0200 Subject: iwlwifi: mvm: change the check for ADD_STA status The firmware will return the baid for BA session in the ADD_STA command response. This requires masking the check of the status, which is actually only 8 bits, and not the whole 32 bits. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 6fca4fb1d306..1eb3983decc3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -253,6 +253,9 @@ struct iwl_mvm_keyinfo { __le64 hw_tkip_mic_tx_key; } __packed; +#define IWL_ADD_STA_STATUS_MASK 0xFF +#define IWL_ADD_STA_BAID_MASK 0xFF00 + /** * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b556e33658d7..84b7fd1c4c70 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -192,7 +192,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (ret) return ret; - switch (status) { + switch (status & IWL_ADD_STA_STATUS_MASK) { case ADD_STA_SUCCESS: IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n"); break; @@ -362,7 +362,7 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, if (ret) return ret; - switch (status) { + switch (status & IWL_ADD_STA_STATUS_MASK) { case ADD_STA_SUCCESS: IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n", mvmsta->sta_id); @@ -628,7 +628,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, if (ret) return ret; - switch (status) { + switch (status & IWL_ADD_STA_STATUS_MASK) { case ADD_STA_SUCCESS: IWL_DEBUG_INFO(mvm, "Internal station added.\n"); return 0; @@ -851,7 +851,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (ret) return ret; - switch (status) { + switch (status & IWL_ADD_STA_STATUS_MASK) { case ADD_STA_SUCCESS: IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n", start ? "start" : "stopp"); @@ -909,7 +909,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (ret) return ret; - switch (status) { + switch (status & IWL_ADD_STA_STATUS_MASK) { case ADD_STA_SUCCESS: break; default: -- cgit v1.2.3 From 81f02ba3dbe0c9133dc4490f0a7d3acd99a89aad Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 30 Dec 2015 23:58:29 +0200 Subject: iwlwifi: mvm: add tlv for multi queue rx support Previous patches enabled the multi-queue rx path based on iwl_mvm_has_new_rx_api() which returned false by default. Change it to return the actual value based on the firmware TLV which is now defined. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 5152987c8b8d..e2dbc67a367b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -347,6 +347,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, + IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT = (__force iwl_ucode_tlv_capa_t)68, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5a34808fdeed..f87aa972fdce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1017,8 +1017,8 @@ bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm) { - /* firmware flag isn't defined yet */ - return false; + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT); } extern const u8 iwl_mvm_ac_to_tx_fifo[]; -- cgit v1.2.3 From c257d5fb52872213f33016c0750bc2334a781700 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 24 Jan 2016 15:28:43 +0100 Subject: iwlwifi: treat iwl_parse_nvm_data() MAC addr as little endian The MAC address parameters passed to iwl_parse_nvm_data() are passed on to iwl_set_hw_address_family_8000() which treats them as little endian. Annotate them as such, and add the missing byte-swapping in mvm. While at it, add the MAC address to the error to make debugging issues with it easier. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 7 ++++--- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 8 +++++--- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 7b89bfc8c8ac..50f4cc60cf3e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -539,7 +539,7 @@ static void iwl_set_hw_address_family_8000(struct device *dev, struct iwl_nvm_data *data, const __le16 *mac_override, const __le16 *nvm_hw, - u32 mac_addr0, u32 mac_addr1) + __le32 mac_addr0, __le32 mac_addr1) { const u8 *hw_addr; @@ -583,7 +583,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev, if (!is_valid_ether_addr(data->hw_addr)) IWL_ERR_DEV(dev, - "mac address from hw section is not valid\n"); + "mac address (%pM) from hw section is not valid\n", + data->hw_addr); return; } @@ -597,7 +598,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, bool lar_fw_supported, - u32 mac_addr0, u32 mac_addr1) + __le32 mac_addr0, __le32 mac_addr1) { struct iwl_nvm_data *data; u32 sku; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 92466ee72806..4e8e0dc474d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -79,7 +79,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, bool lar_fw_supported, - u32 mac_addr0, u32 mac_addr1); + __le32 mac_addr0, __le32 mac_addr1); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 7a3da2da6fd0..c446e0da9789 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -300,7 +300,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) struct iwl_nvm_section *sections = mvm->nvm_sections; const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; bool lar_enabled; - u32 mac_addr0, mac_addr1; + __le32 mac_addr0, mac_addr1; /* Checking for required sections */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { @@ -337,8 +337,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return NULL; /* read the mac address from WFMP registers */ - mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0); - mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1); + mac_addr0 = cpu_to_le32(iwl_trans_read_prph(mvm->trans, + WFMP_MAC_ADDR_0)); + mac_addr1 = cpu_to_le32(iwl_trans_read_prph(mvm->trans, + WFMP_MAC_ADDR_1)); hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; -- cgit v1.2.3 From 8812182e5df31e49cd888bafa36bcccf87787940 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 24 Jan 2016 15:18:59 +0200 Subject: iwlwifi: mvm: Remove bf_vif from iwl_power_vifs This member is actually not needed as beacon abort is only allowed for a bss station. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 28 ++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 0d03b3e3cf4e..83e686dd86ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -577,7 +577,6 @@ void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, struct iwl_power_vifs { struct iwl_mvm *mvm; - struct ieee80211_vif *bf_vif; struct ieee80211_vif *bss_vif; struct ieee80211_vif *p2p_vif; struct ieee80211_vif *ap_vif; @@ -650,11 +649,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->bss_active = true; - - if (mvmvif->bf_data.bf_enabled && - !WARN_ON(power_iterator->bf_vif)) - power_iterator->bf_vif = vif; - break; default: @@ -959,21 +953,19 @@ static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm) } static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, - struct iwl_power_vifs *vifs) + struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); bool ba_enable; - if (!vifs->bf_vif) + if (!mvmvif->bf_data.bf_enabled) return 0; - mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif); - ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || - !vifs->bf_vif->bss_conf.ps || + !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); - return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable); + return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); } int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) @@ -994,7 +986,10 @@ int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) if (ret) return ret; - return iwl_mvm_power_set_ba(mvm, &vifs); + if (vifs.bss_vif) + return iwl_mvm_power_set_ba(mvm, vifs.bss_vif); + + return 0; } int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) @@ -1029,7 +1024,10 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) return ret; } - return iwl_mvm_power_set_ba(mvm, &vifs); + if (vifs.bss_vif) + return iwl_mvm_power_set_ba(mvm, vifs.bss_vif); + + return 0; } int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, -- cgit v1.2.3 From 416ec4f3928544fcedba5a4d98866e74ce44f369 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 24 Jan 2016 15:56:11 +0200 Subject: iwlwifi: mvm: Remove iwl_mvm_update_beacon_abort It is only called from iwl_mvm_power_set_ba() so simplify things by removing it. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 37 +++++++++----------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 83e686dd86ee..f313910cd026 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -877,26 +877,6 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false); } -static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool enable) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_beacon_filter_cmd cmd = { - IWL_BF_CMD_CONFIG_DEFAULTS, - .bf_enable_beacon_filter = cpu_to_le32(1), - }; - - if (!mvmvif->bf_data.bf_enabled) - return 0; - - if (mvm->cur_ucode == IWL_UCODE_WOWLAN) - cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); - - mvmvif->bf_data.ba_enabled = enable; - return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false); -} - static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 flags, bool d0i3) @@ -956,16 +936,23 @@ static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool ba_enable; + struct iwl_beacon_filter_cmd cmd = { + IWL_BF_CMD_CONFIG_DEFAULTS, + .bf_enable_beacon_filter = cpu_to_le32(1), + }; if (!mvmvif->bf_data.bf_enabled) return 0; - ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || - !vif->bss_conf.ps || - iwl_mvm_vif_low_latency(mvmvif)); + if (mvm->cur_ucode == IWL_UCODE_WOWLAN) + cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); + + mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled || + mvm->ps_disabled || + !vif->bss_conf.ps || + iwl_mvm_vif_low_latency(mvmvif)); - return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); + return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false); } int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) -- cgit v1.2.3 From 854c57057390e45041a56c3d3228eb805e980c99 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 26 Jan 2016 13:17:47 +0200 Subject: iwlwifi: mvm: add new ADD_STA command version The 9000 hardware introduces the frame releaser, which keeps track of the aggregation window and notifies host of the window status. This requires in turn updating the hardware with the RX BA session window size. Firmware API was changed to enable that, update the driver accordingly. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 66 +++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 40 ++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 +- 4 files changed, 99 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 1eb3983decc3..90d911394836 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -256,6 +258,65 @@ struct iwl_mvm_keyinfo { #define IWL_ADD_STA_STATUS_MASK 0xFF #define IWL_ADD_STA_BAID_MASK 0xFF00 +/** + * struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table. + * ( REPLY_ADD_STA = 0x18 ) + * @add_modify: 1: modify existing, 0: add new station + * @awake_acs: + * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable + * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. + * @mac_id_n_color: the Mac context this station belongs to + * @addr[ETH_ALEN]: station's MAC address + * @sta_id: index of station in uCode's station table + * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave + * alone. 1 - modify, 0 - don't change. + * @station_flags: look at %iwl_sta_flags + * @station_flags_msk: what of %station_flags have changed + * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) + * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set + * add_immediate_ba_ssn. + * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) + * Set %STA_MODIFY_REMOVE_BA_TID to use this field + * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with + * add_immediate_ba_tid. + * @sleep_tx_count: number of packets to transmit to station even though it is + * asleep. Used to synchronise PS-poll and u-APSD responses while ucode + * keeps track of STA sleep state. + * @sleep_state_flags: Look at %iwl_sta_sleep_flag. + * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP + * mac-addr. + * @beamform_flags: beam forming controls + * @tfd_queue_msk: tfd queues used by this station + * + * The device contains an internal table of per-station information, with info + * on security keys, aggregation parameters, and Tx rates for initial Tx + * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). + * + * ADD_STA sets up the table entry for one station, either creating a new + * entry, or modifying a pre-existing one. + */ +struct iwl_mvm_add_sta_cmd_v7 { + u8 add_modify; + u8 awake_acs; + __le16 tid_disable_tx; + __le32 mac_id_n_color; + u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ + __le16 reserved2; + u8 sta_id; + u8 modify_mask; + __le16 reserved3; + __le32 station_flags; + __le32 station_flags_msk; + u8 add_immediate_ba_tid; + u8 remove_immediate_ba_tid; + __le16 add_immediate_ba_ssn; + __le16 sleep_tx_count; + __le16 sleep_state_flags; + __le16 assoc_id; + __le16 beamform_flags; + __le32 tfd_queue_msk; +} __packed; /* ADD_STA_CMD_API_S_VER_7 */ + /** * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) @@ -285,6 +346,7 @@ struct iwl_mvm_keyinfo { * mac-addr. * @beamform_flags: beam forming controls * @tfd_queue_msk: tfd queues used by this station + * @rx_ba_window: aggregation window size * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx @@ -313,7 +375,9 @@ struct iwl_mvm_add_sta_cmd { __le16 assoc_id; __le16 beamform_flags; __le32 tfd_queue_msk; -} __packed; /* ADD_STA_CMD_API_S_VER_7 */ + __le16 rx_ba_window; + __le16 reserved; +} __packed; /* ADD_STA_CMD_API_S_VER_8 */ /** * struct iwl_mvm_add_sta_key_cmd - add/modify sta key diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d70a1716f3e0..01476f545695 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -884,10 +884,10 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, ret = -EINVAL; break; } - ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true); + ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size); break; case IEEE80211_AMPDU_RX_STOP: - ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); + ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size); break; case IEEE80211_AMPDU_TX_START: if (!iwl_enable_tx_ampdu(mvm->cfg)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 84b7fd1c4c70..4854e79cbda8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +70,18 @@ #include "sta.h" #include "rs.h" +/* + * New version of ADD_STA_sta command added new fields at the end of the + * structure, so sending the size of the relevant API's structure is enough to + * support both API versions. + */ +static inline int iwl_mvm_add_sta_cmd_size(struct iwl_mvm *mvm) +{ + return iwl_mvm_has_new_rx_api(mvm) ? + sizeof(struct iwl_mvm_add_sta_cmd) : + sizeof(struct iwl_mvm_add_sta_cmd_v7); +} + static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype) { @@ -187,7 +201,8 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd), + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), &add_sta_cmd, &status); if (ret) return ret; @@ -357,7 +372,8 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), &cmd, &status); if (ret) return ret; @@ -623,7 +639,8 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, if (addr) memcpy(cmd.addr, addr, ETH_ALEN); - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), &cmd, &status); if (ret) return ret; @@ -819,7 +836,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) #define IWL_MAX_RX_BA_SESSIONS 16 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, u16 ssn, bool start) + int tid, u16 ssn, bool start, u8 buf_size) { struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = {}; @@ -839,6 +856,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (start) { cmd.add_immediate_ba_tid = (u8) tid; cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); + cmd.rx_ba_window = cpu_to_le16((u16)buf_size); } else { cmd.remove_immediate_ba_tid = (u8) tid; } @@ -846,7 +864,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, STA_MODIFY_REMOVE_BA_TID; status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), &cmd, &status); if (ret) return ret; @@ -904,7 +923,8 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), &cmd, &status); if (ret) return ret; @@ -1640,7 +1660,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, }; int ret; - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, + iwl_mvm_add_sta_cmd_size(mvm), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } @@ -1731,7 +1752,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK, - sizeof(cmd), &cmd); + iwl_mvm_add_sta_cmd_size(mvm), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } @@ -1766,7 +1787,8 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, }; int ret; - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, + iwl_mvm_add_sta_cmd_size(mvm), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 39fdf5224e81..e3b9446ee995 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -401,7 +401,7 @@ void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, /* AMPDU */ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int tid, u16 ssn, bool start); + int tid, u16 ssn, bool start, u8 buf_size); int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -- cgit v1.2.3 From 6ad6c01fa74f649722eeca7308dc1fc4e43235cd Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 27 Jan 2016 00:10:15 +0200 Subject: iwlwifi: mvm: rs: fix TPC action decision algorithm Decreasing Tx power is allowed only when success ratio is above the threshold defined in the algorithm. Add this condition. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 7bb6fd0e4391..986e12ab9dc2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2040,7 +2040,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm, } /* try decreasing first if applicable */ - if (weak != TPC_INVALID) { + if (sr >= RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) && + weak != TPC_INVALID) { if (weak_tpt == IWL_INVALID_VALUE && (strong_tpt == IWL_INVALID_VALUE || current_tpt >= strong_tpt)) { -- cgit v1.2.3 From 43413a975d06e5e34016751fac27e29ec3d4d10f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 31 Dec 2015 11:49:18 +0200 Subject: iwlwifi: mvm: support rss queues configuration command 9000 series supports multi-queue rx. The hardware needs to be configured with the hash functions to perform and indirection table that maps hash results to the relevant CPUs\queues. Support this configuration. Add debugfs hook to configure the indirection table in order to enable performance analysis. The configuration is stateless, receives a partial or full pattern and sends the command to the firmware. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 44 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 33 +++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 29 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 ++ 6 files changed, 111 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 5c0f93997b7b..005cc09757d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -943,6 +944,47 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return count; } +static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_rss_config_cmd cmd = { + .flags = cpu_to_le32(IWL_RSS_ENABLE), + .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | + IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | + IWL_RSS_HASH_TYPE_IPV6_TCP | + IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, + }; + int ret, i, num_repeats, nbytes = count / 2; + + ret = hex2bin(cmd.indirection_table, buf, nbytes); + if (ret) + return ret; + + /* + * The input is the redirection table, partial or full. + * Repeat the pattern if needed. + * For example, input of 01020F will be repeated 42 times, + * indirecting RSS hash results to queues 1, 2, 15 (skipping + * queues 3 - 14). + */ + num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes; + for (i = 1; i < num_repeats; i++) + memcpy(&cmd.indirection_table[i * nbytes], + cmd.indirection_table, nbytes); + /* handle cut in the middle pattern for the last places */ + memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table, + ARRAY_SIZE(cmd.indirection_table) % nbytes); + + memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key)); + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1455,6 +1497,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, 16); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -1499,6 +1542,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR); if (!debugfs_create_bool("enable_scan_iteration_notif", S_IRUSR | S_IWUSR, mvm->debugfs_dir, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index ab467cb9b97c..b45c61e1f45c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -362,4 +362,33 @@ struct iwl_frame_release { __le16 nssn; }; +enum iwl_rss_hash_func_en { + IWL_RSS_HASH_TYPE_IPV4_TCP, + IWL_RSS_HASH_TYPE_IPV4_UDP, + IWL_RSS_HASH_TYPE_IPV4_PAYLOAD, + IWL_RSS_HASH_TYPE_IPV6_TCP, + IWL_RSS_HASH_TYPE_IPV6_UDP, + IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, +}; + +#define IWL_RSS_HASH_KEY_CNT 10 +#define IWL_RSS_INDIRECTION_TABLE_SIZE 128 +#define IWL_RSS_ENABLE 1 + +/** + * struct iwl_rss_config_cmd - RSS (Receive Side Scaling) configuration + * + * @flags: 1 - enable, 0 - disable + * @hash_mask: Type of RSS to use. Values are from %iwl_rss_hash_func_en + * @secret_key: 320 bit input of random key configuration from driver + * @indirection_table: indirection table + */ +struct iwl_rss_config_cmd { + __le32 flags; + u8 hash_mask; + u8 reserved[3]; + __le32 secret_key[IWL_RSS_HASH_KEY_CNT]; + u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE]; +} __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */ + #endif /* __fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index b6b57273b8ba..f332497e29d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -213,6 +213,8 @@ enum { MFUART_LOAD_NOTIFICATION = 0xb1, + RSS_CONFIG_CMD = 0xb3, + REPLY_RX_PHY_CMD = 0xc0, REPLY_RX_MPDU_CMD = 0xc1, FRAME_RELEASE = 0xc3, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 4ed5180c547b..070e2af05ca2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -107,6 +108,24 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) sizeof(tx_ant_cmd), &tx_ant_cmd); } +static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) +{ + int i; + struct iwl_rss_config_cmd cmd = { + .flags = cpu_to_le32(IWL_RSS_ENABLE), + .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | + IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | + IWL_RSS_HASH_TYPE_IPV6_TCP | + IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, + }; + + for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) + cmd.indirection_table[i] = i % mvm->trans->num_rx_queues; + memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key)); + + return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); +} + static void iwl_free_fw_paging(struct iwl_mvm *mvm) { int i; @@ -894,6 +913,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; + /* Init RSS configuration */ + if (iwl_mvm_has_new_rx_api(mvm)) { + ret = iwl_send_rss_cfg_cmd(mvm); + if (ret) { + IWL_ERR(mvm, "Failed to configure RSS queues: %d\n", + ret); + goto error; + } + } + /* init the fw <-> mac80211 STA mapping */ for (i = 0; i < IWL_MVM_STATION_COUNT; i++) RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f87aa972fdce..747f7eb80f47 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -647,6 +647,7 @@ struct iwl_mvm { atomic_t pending_frames[IWL_MVM_STATION_COUNT]; u32 tfd_drained[IWL_MVM_STATION_COUNT]; u8 rx_ba_sessions; + u32 secret_key[IWL_RSS_HASH_KEY_CNT]; /* configured by mac80211 */ u32 rts_threshold; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3c869ad6aaec..325ff8aa33f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -347,6 +347,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(MAC_PM_POWER_TABLE), HCMD_NAME(TDLS_CHANNEL_SWITCH_NOTIFICATION), HCMD_NAME(MFUART_LOAD_NOTIFICATION), + HCMD_NAME(RSS_CONFIG_CMD), HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC), HCMD_NAME(REPLY_RX_PHY_CMD), HCMD_NAME(REPLY_RX_MPDU_CMD), @@ -651,6 +652,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_tof_init(mvm); + /* init RSS hash key */ + get_random_bytes(mvm->secret_key, ARRAY_SIZE(mvm->secret_key)); + return op_mode; out_unregister: -- cgit v1.2.3 From bce977310416a2b6c9ad774dfe2071eaacd3d90b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 25 Jan 2016 18:14:49 +0200 Subject: iwlwifi: pcie: enable multi-queue rx path Previous patches enabled new 9000 hardware DMA for one queue only. Enable the actual multi-queue path and configuration now. This requires also per-queue NAPI struct. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 35 +++++++++++++++++----- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 14 +-------- 3 files changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 7bc02e0cdd93..2f959162d045 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -136,6 +136,7 @@ struct iwl_rxq { struct iwl_rb_status *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; + struct napi_struct napi; struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; }; @@ -345,7 +346,6 @@ struct iwl_trans_pcie { struct iwl_drv *drv; struct net_device napi_dev; - struct napi_struct napi; struct __percpu iwl_tso_hdr_page *tso_hdr_page; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a385f3cddb5d..51314e56209d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -2,6 +2,7 @@ * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -730,7 +731,7 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE); } -static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) +static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 rb_size, enabled = 0; @@ -759,13 +760,13 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) for (i = 0; i < trans->num_rx_queues; i++) { /* Tell device where to find RBD free table in DRAM */ iwl_pcie_write_prph_64(trans, RFH_Q_FRBDCB_BA_LSB(i), - (u64)(rxq->bd_dma)); + (u64)(trans_pcie->rxq[i].bd_dma)); /* Tell device where to find RBD used table in DRAM */ iwl_pcie_write_prph_64(trans, RFH_Q_URBDCB_BA_LSB(i), - (u64)(rxq->used_bd_dma)); + (u64)(trans_pcie->rxq[i].used_bd_dma)); /* Tell device where in DRAM to update its Rx status */ iwl_pcie_write_prph_64(trans, RFH_Q_URBD_STTS_WPTR_LSB(i), - rxq->rb_stts_dma); + trans_pcie->rxq[i].rb_stts_dma); /* Reset device indice tables */ iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(i), 0); iwl_write_prph(trans, RFH_Q_FRBDCB_RIDX(i), 0); @@ -808,6 +809,12 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) rxq->used_count = 0; } +static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget) +{ + WARN_ON(1); + return 0; +} + int iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -857,6 +864,10 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) iwl_pcie_rx_init_rxb_lists(rxq); + if (!rxq->napi.poll) + netif_napi_add(&trans_pcie->napi_dev, &rxq->napi, + iwl_pcie_dummy_napi_poll, 64); + spin_unlock(&rxq->lock); } @@ -878,7 +889,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq); if (trans->cfg->mq_rx_supported) { - iwl_pcie_rx_mq_hw_init(trans, def_rxq); + iwl_pcie_rx_mq_hw_init(trans); } else { iwl_pcie_rxq_restock(trans, def_rxq); iwl_pcie_rx_hw_init(trans, def_rxq); @@ -940,6 +951,9 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) rxq->used_bd, rxq->used_bd_dma); rxq->used_bd_dma = 0; rxq->used_bd = NULL; + + if (rxq->napi.poll) + netif_napi_del(&rxq->napi); } kfree(trans_pcie->rxq); } @@ -1055,7 +1069,12 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, index = SEQ_TO_INDEX(sequence); cmd_index = get_cmd_index(&txq->q, index); - iwl_op_mode_rx(trans->op_mode, &trans_pcie->napi, &rxcb); + if (rxq->id == 0) + iwl_op_mode_rx(trans->op_mode, &rxq->napi, + &rxcb); + else + iwl_op_mode_rx_rss(trans->op_mode, &rxq->napi, + &rxcb, rxq->id); if (reclaim) { kzfree(txq->entries[cmd_index].free_buf); @@ -1236,8 +1255,8 @@ restart: if (unlikely(emergency && count)) iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); - if (trans_pcie->napi.poll) - napi_gro_flush(&trans_pcie->napi, false); + if (rxq->napi.poll) + napi_gro_flush(&rxq->napi, false); } /* diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index abe091698471..b796952da644 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1428,12 +1428,6 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val); } -static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget) -{ - WARN_ON(1); - return 0; -} - static void iwl_trans_pcie_configure(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg) { @@ -1470,11 +1464,8 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, * As this function may be called again in some corner cases don't * do anything if NAPI was already initialized. */ - if (!trans_pcie->napi.poll) { + if (trans_pcie->napi_dev.reg_state != NETREG_DUMMY) init_dummy_netdev(&trans_pcie->napi_dev); - netif_napi_add(&trans_pcie->napi_dev, &trans_pcie->napi, - iwl_pcie_dummy_napi_poll, 64); - } } void iwl_trans_pcie_free(struct iwl_trans *trans) @@ -1498,9 +1489,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) pci_release_regions(trans_pcie->pci_dev); pci_disable_device(trans_pcie->pci_dev); - if (trans_pcie->napi.poll) - netif_napi_del(&trans_pcie->napi); - iwl_pcie_free_fw_monitor(trans); for_each_possible_cpu(i) { -- cgit v1.2.3 From d56a7801b544d63b0d32bc8bca0c12a259b1d8e9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 26 Jan 2016 12:35:13 +0200 Subject: iwlwifi: pcie: update iwl_mpdu_desc fields Final API of iwl_mpdu_desc has a change in the order of the fields and does not include energy from the third antenna (which is perfectly fine, since we don't have one). Update the structure accordingly. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 11 ++++------- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index b45c61e1f45c..df939f51d9b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -347,11 +347,11 @@ struct iwl_rx_mpdu_desc { /* DW8 */ __le32 filter_match; /* DW9 */ - __le32 gp2_on_air_rise; - /* DW10 */ __le32 rate_n_flags; + /* DW10 */ + u8 energy_a, energy_b, channel, reserved; /* DW11 */ - u8 energy_a, energy_b, energy_c, channel; + __le32 gp2_on_air_rise; /* DW12 & DW13 */ __le64 tsf_on_air_rise; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 4cce37238a08..615dea143d4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -201,25 +201,22 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, struct iwl_rx_mpdu_desc *desc, struct ieee80211_rx_status *rx_status) { - int energy_a, energy_b, energy_c, max_energy; + int energy_a, energy_b, max_energy; energy_a = desc->energy_a; energy_a = energy_a ? -energy_a : S8_MIN; energy_b = desc->energy_b; energy_b = energy_b ? -energy_b : S8_MIN; - energy_c = desc->energy_c; - energy_c = energy_c ? -energy_c : S8_MIN; max_energy = max(energy_a, energy_b); - max_energy = max(max_energy, energy_c); - IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n", - energy_a, energy_b, energy_c, max_energy); + IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n", + energy_a, energy_b, max_energy); rx_status->signal = max_energy; rx_status->chains = 0; /* TODO: phy info */ rx_status->chain_signal[0] = energy_a; rx_status->chain_signal[1] = energy_b; - rx_status->chain_signal[2] = energy_c; + rx_status->chain_signal[2] = S8_MIN; } static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, -- cgit v1.2.3 From c89e333d5e4a27f736c960b29040b261c21563a5 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 26 Jan 2016 18:12:28 +0200 Subject: iwlwifi: mvm: allow to disable beacon filtering for AP/GO interface When in AP mode we need to filter in beacons from other APs to update HT operation mode. As a power optimization the beacons are filtered out when there are no associated stations. As a result, when there are no associated stations, we will not update the HT operation mode until a station connects. Add a debugfs parameter that allows to disable this optimization. Signed-off-by: Andrei Otcheretianski Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 005cc09757d2..c529e5355803 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1548,6 +1548,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) mvm->debugfs_dir, &mvm->scan_iter_notif_enabled)) goto err; + if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR, + mvm->debugfs_dir, &mvm->drop_bcn_ap_mode)) + goto err; #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 62927f567afc..535134d639e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -744,7 +744,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, * wake-ups. */ cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); - if (mvmvif->ap_assoc_sta_count) { + if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) { cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON); IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n"); } else { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 747f7eb80f47..ebe37bb0ce4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -859,6 +859,12 @@ struct iwl_mvm { u32 ciphers[6]; struct iwl_mvm_tof_data tof_data; + + /* + * Drop beacons from other APs in AP mode when there are no connected + * clients. + */ + bool drop_bcn_ap_mode; }; /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 325ff8aa33f5..09a94a5efb61 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -492,6 +492,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, } mvm->sf_state = SF_UNINIT; mvm->cur_ucode = IWL_UCODE_INIT; + mvm->drop_bcn_ap_mode = true; mutex_init(&mvm->mutex); mutex_init(&mvm->d0i3_suspend_mutex); -- cgit v1.2.3 From 875e94392ad2be9776c8325d3573160eb1455a2b Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Jan 2016 19:24:02 +0200 Subject: wil6210: prevent access to vring_tx_data lock during its init wil_tx_vring locks the vring_tx_data lock before accessing the TX vring to check if it is enabled and valid for use. In case of quick disconnect / connect events for the same station, spin_lock(&txdata->lock) can be called during the lock initialization in the vring init function. To prevent such a race, the TX vrings spin lock should be initialized once during wil6210 driver initialization. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 3 +++ drivers/net/wireless/ath/wil6210/txrx.c | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0652efed6b5d..712ebbfbdeb8 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -438,6 +438,9 @@ int wil_priv_init(struct wil6210_priv *wil) for (i = 0; i < WIL6210_MAX_CID; i++) spin_lock_init(&wil->sta[i].tid_rx_lock); + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) + spin_lock_init(&wil->vring_tx_data[i].lock); + mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); mutex_init(&wil->back_rx_mutex); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 9680b970b863..6af20903cf89 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -717,6 +717,21 @@ void wil_rx_fini(struct wil6210_priv *wil) wil_vring_free(wil, vring, 0); } +static inline void wil_tx_data_init(struct vring_tx_data *txdata) +{ + spin_lock_bh(&txdata->lock); + txdata->dot1x_open = 0; + txdata->enabled = 0; + txdata->idle = 0; + txdata->last_idle = 0; + txdata->begin = 0; + txdata->agg_wsize = 0; + txdata->agg_timeout = 0; + txdata->agg_amsdu = 0; + txdata->addba_in_progress = false; + spin_unlock_bh(&txdata->lock); +} + int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, int cid, int tid) { @@ -758,8 +773,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, goto out; } - memset(txdata, 0, sizeof(*txdata)); - spin_lock_init(&txdata->lock); + wil_tx_data_init(txdata); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -791,8 +805,10 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, return 0; out_free: + spin_lock_bh(&txdata->lock); txdata->dot1x_open = false; txdata->enabled = 0; + spin_unlock_bh(&txdata->lock); wil_vring_free(wil, vring, 1); wil->vring2cid_tid[id][0] = WIL6210_MAX_CID; wil->vring2cid_tid[id][1] = 0; @@ -834,8 +850,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) goto out; } - memset(txdata, 0, sizeof(*txdata)); - spin_lock_init(&txdata->lock); + wil_tx_data_init(txdata); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -865,8 +880,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) return 0; out_free: + spin_lock_bh(&txdata->lock); txdata->enabled = 0; txdata->dot1x_open = false; + spin_unlock_bh(&txdata->lock); wil_vring_free(wil, vring, 1); out: @@ -894,7 +911,6 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) napi_synchronize(&wil->napi_tx); wil_vring_free(wil, vring, 1); - memset(txdata, 0, sizeof(*txdata)); } static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, -- cgit v1.2.3 From 78771d76f826202012201d700028a2d866d03fb3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 28 Jan 2016 19:24:03 +0200 Subject: wil6210: wait for disconnect completion cfg80211_ops.disconnect() should wait for disconnect flow to complete. If it does not, internal state becomes out of sync with one in cfg80211. If one does stress test connect/disconnect sequence, cfg80211 will issue next connect before disconnect completed internally. Signed-off-by: Vladimir Kondratiev Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 13 ++++++++++++- drivers/net/wireless/ath/wil6210/main.c | 28 +++++++++------------------- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 774352f9e256..97ad91eef4a6 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -535,7 +535,18 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code); - rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); + if (!(test_bit(wil_status_fwconnecting, wil->status) || + test_bit(wil_status_fwconnected, wil->status))) { + wil_err(wil, "%s: Disconnect was called while disconnected\n", + __func__); + return 0; + } + + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + WMI_DISCONNECT_EVENTID, NULL, 0, + WIL6210_DISCONNECT_TO_MS); + if (rc) + wil_err(wil, "%s: disconnect error %d\n", __func__, rc); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 712ebbfbdeb8..78ba6e04c944 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -23,9 +23,6 @@ #include "wmi.h" #include "boot_loader.h" -#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 -#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 - bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug"); @@ -942,8 +939,7 @@ int wil_up(struct wil6210_priv *wil) int __wil_down(struct wil6210_priv *wil) { - int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS / - WAIT_FOR_DISCONNECT_INTERVAL_MS; + int rc; WARN_ON(!mutex_is_locked(&wil->mutex)); @@ -967,22 +963,16 @@ int __wil_down(struct wil6210_priv *wil) } if (test_bit(wil_status_fwconnected, wil->status) || - test_bit(wil_status_fwconnecting, wil->status)) - wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); + test_bit(wil_status_fwconnecting, wil->status)) { - /* make sure wil is idle (not connected) */ - mutex_unlock(&wil->mutex); - while (iter--) { - int idle = !test_bit(wil_status_fwconnected, wil->status) && - !test_bit(wil_status_fwconnecting, wil->status); - if (idle) - break; - msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS); + mutex_unlock(&wil->mutex); + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + WMI_DISCONNECT_EVENTID, NULL, 0, + WIL6210_DISCONNECT_TO_MS); + mutex_lock(&wil->mutex); + if (rc) + wil_err(wil, "timeout waiting for disconnect\n"); } - mutex_lock(&wil->mutex); - - if (iter < 0) - wil_err(wil, "timeout waiting for idle FW/HW\n"); wil_reset(wil, false); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1b8fa1d2bae9..950296507dd1 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -92,6 +92,7 @@ static inline u32 wil_mtu2macbuf(u32 mtu) #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ #define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000) #define WIL6210_SCAN_TO msecs_to_jiffies(10000) +#define WIL6210_DISCONNECT_TO_MS (2000) #define WIL6210_RX_HIGH_TRSH_INIT (0) #define WIL6210_RX_HIGH_TRSH_DEFAULT \ (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3)) -- cgit v1.2.3 From fe5c271e2878fb080f1b32fec5b4e3f7a6070152 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 28 Jan 2016 19:24:04 +0200 Subject: wil6210: protect synchronous wmi commands handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case there are multiple WMI commands with the same reply_id, the following scenario can occur: - Driver sends the first command to the device - The reply didn’t get on time and there is timeout - Reply_id, reply_buf and reply_size are set to 0 - Driver sends second wmi command with the same reply_id as the first - Driver sets wil->reply_id - Reply for the first wmi command arrives and handled by wmi_recv_cmd - As its ID fits the reply_id but the reply_buf is not set yet it is handled as a reply with event handler, and WARN_ON is printed This patch guarantee atomic setting of all the reply variables and prevents the above scenario. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index e1a6cb8840ed..493e721c4fa7 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -838,6 +838,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->id); u32 tstamp = le32_to_cpu(wmi->timestamp); + spin_lock_irqsave(&wil->wmi_ev_lock, flags); if (wil->reply_id && wil->reply_id == id) { if (wil->reply_buf) { memcpy(wil->reply_buf, wmi, @@ -845,6 +846,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) immed_reply = true; } } + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n", id, wmi->mid, tstamp); @@ -888,13 +890,16 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, mutex_lock(&wil->wmi_mutex); + spin_lock(&wil->wmi_ev_lock); + wil->reply_id = reply_id; + wil->reply_buf = reply; + wil->reply_size = reply_size; + spin_unlock(&wil->wmi_ev_lock); + rc = __wmi_send(wil, cmdid, buf, len); if (rc) goto out; - wil->reply_id = reply_id; - wil->reply_buf = reply; - wil->reply_size = reply_size; remain = wait_for_completion_timeout(&wil->wmi_call, msecs_to_jiffies(to_msec)); if (0 == remain) { @@ -907,10 +912,14 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, cmdid, reply_id, to_msec - jiffies_to_msecs(remain)); } + +out: + spin_lock(&wil->wmi_ev_lock); wil->reply_id = 0; wil->reply_buf = NULL; wil->reply_size = 0; - out: + spin_unlock(&wil->wmi_ev_lock); + mutex_unlock(&wil->wmi_mutex); return rc; -- cgit v1.2.3 From ee5dfe0d240e21afe63bdd77bf1d4a386203aa6e Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Thu, 28 Jan 2016 19:24:05 +0200 Subject: wil6210: TX vring optimization Tx vring needs to be enlarged to get better performance for traffic over 2Gbps. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 6 +++--- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 97bc186f9728..98c9148a3450 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -68,13 +68,13 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, seq_puts(s, "???\n"); } - if (vring->va && (vring->size < 1025)) { + if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { uint i; for (i = 0; i < vring->size; i++) { volatile struct vring_tx_desc *d = &vring->va[i].tx; - if ((i % 64) == 0 && (i != 0)) + if ((i % 128) == 0 && (i != 0)) seq_puts(s, "\n"); seq_printf(s, "%c", (d->dma.status & BIT(0)) ? _s : (vring->ctx[i].skb ? _h : 'h')); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 950296507dd1..8427d68b6fa8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -51,7 +51,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) -#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_RING_SIZE_ORDER_DEFAULT (12) #define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7) #define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */ /* limit ring size in range [32..32k] */ -- cgit v1.2.3 From 0b3d76e9f8b4a2b67358b454843ede30555f93a5 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Thu, 28 Jan 2016 13:54:07 -0800 Subject: ath10k: rename Mesh related service names WMI_10_4_SERVICE_MESH bit is for non IEEE802.11s Mesh. Hence rename it to WMI_10_4_SERVICE_MESH_NON_11S. Also add _11S as post-fix to each of WMI_SERVICE_MESH and WMI_VDEV_SUBTYPE_MESH specifying the service is for 11s Mesh. This will help users to distinguish 11s Mesh from non 11s Mesh. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++-- drivers/net/wireless/ath/ath10k/wmi.h | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ef0438d2cc8f..1406b0f1d883 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4380,8 +4380,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->vdev_type = WMI_VDEV_TYPE_IBSS; break; case NL80211_IFTYPE_MESH_POINT: - if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) { - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH; + if (test_bit(WMI_SERVICE_MESH_11S, ar->wmi.svc_map)) { + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { ret = -EINVAL; ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n"); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 806d4bb6e7d6..0458bf6bcdfc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -176,7 +176,8 @@ enum wmi_service { WMI_SERVICE_AUX_CHAN_LOAD_INTF, WMI_SERVICE_BSS_CHANNEL_INFO_64, WMI_SERVICE_EXT_RES_CFG_SUPPORT, - WMI_SERVICE_MESH, + WMI_SERVICE_MESH_11S, + WMI_SERVICE_MESH_NON_11S, WMI_SERVICE_PEER_STATS, /* keep last */ @@ -296,7 +297,7 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT, - WMI_10_4_SERVICE_MESH, + WMI_10_4_SERVICE_MESH_NON_11S, }; static inline char *wmi_service_name(int service_id) @@ -387,7 +388,8 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF); SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64); SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT); - SVCSTR(WMI_SERVICE_MESH); + SVCSTR(WMI_SERVICE_MESH_11S); + SVCSTR(WMI_SERVICE_MESH_NON_11S); SVCSTR(WMI_SERVICE_PEER_STATS); default: return NULL; @@ -463,7 +465,7 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, SVCMAP(WMI_10X_SERVICE_BSS_CHANNEL_INFO_64, WMI_SERVICE_BSS_CHANNEL_INFO_64, len); SVCMAP(WMI_10X_SERVICE_MESH, - WMI_SERVICE_MESH, len); + WMI_SERVICE_MESH_11S, len); SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT, WMI_SERVICE_EXT_RES_CFG_SUPPORT, len); SVCMAP(WMI_10X_SERVICE_PEER_STATS, @@ -628,8 +630,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_BSS_CHANNEL_INFO_64, len); SVCMAP(WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT, WMI_SERVICE_EXT_RES_CFG_SUPPORT, len); - SVCMAP(WMI_10_4_SERVICE_MESH, - WMI_SERVICE_MESH, len); + SVCMAP(WMI_10_4_SERVICE_MESH_NON_11S, + WMI_SERVICE_MESH_NON_11S, len); } #undef SVCMAP @@ -4287,7 +4289,7 @@ enum wmi_vdev_subtype { WMI_VDEV_SUBTYPE_P2P_CLIENT = 2, WMI_VDEV_SUBTYPE_P2P_GO = 3, WMI_VDEV_SUBTYPE_PROXY_STA = 4, - WMI_VDEV_SUBTYPE_MESH = 5, + WMI_VDEV_SUBTYPE_MESH_11S = 5, }; /* values for vdev_subtype */ -- cgit v1.2.3 From e70e9ba9df8609908c34d042cf980c1a59c56900 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Thu, 28 Jan 2016 13:54:08 -0800 Subject: ath10k: update 10.4 WMI service map Update 10.4 WMI service map to sync to the latest 10.4 firmware as of 1/20/2016. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 0458bf6bcdfc..031018a07231 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -179,6 +179,7 @@ enum wmi_service { WMI_SERVICE_MESH_11S, WMI_SERVICE_MESH_NON_11S, WMI_SERVICE_PEER_STATS, + WMI_SERVICE_RESTRT_CHNL_SUPPORT, /* keep last */ WMI_SERVICE_MAX, @@ -298,6 +299,9 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT, WMI_10_4_SERVICE_MESH_NON_11S, + WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT, + WMI_10_4_SERVICE_PEER_STATS, + WMI_10_4_SERVICE_MESH_11S, }; static inline char *wmi_service_name(int service_id) @@ -391,6 +395,7 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_MESH_11S); SVCSTR(WMI_SERVICE_MESH_NON_11S); SVCSTR(WMI_SERVICE_PEER_STATS); + SVCSTR(WMI_SERVICE_RESTRT_CHNL_SUPPORT); default: return NULL; } @@ -632,6 +637,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_EXT_RES_CFG_SUPPORT, len); SVCMAP(WMI_10_4_SERVICE_MESH_NON_11S, WMI_SERVICE_MESH_NON_11S, len); + SVCMAP(WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT, + WMI_SERVICE_RESTRT_CHNL_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_PEER_STATS, + WMI_SERVICE_PEER_STATS, len); + SVCMAP(WMI_10_4_SERVICE_MESH_11S, + WMI_SERVICE_MESH_11S, len); } #undef SVCMAP -- cgit v1.2.3 From 08c27be1db84dcdad14e86ec76d9c9915deb14eb Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Thu, 28 Jan 2016 13:54:09 -0800 Subject: ath10k: use vif->type and vif->p2p for P2P_GO check Interface type P2P_GO can be checked by either arvif->vdev_type and arvif->vdev_subtype or vif->type and vif->p2p. Use later one to avoid more cpu consumption that could happen when subtype abstraction layer change is introduced. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 8 ++------ drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1406b0f1d883..addf3cb3aeb1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1358,10 +1358,7 @@ static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif, const u8 *p2p_ie; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) - return 0; - - if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + if (arvif->vif->type != NL80211_IFTYPE_AP || !arvif->vif->p2p) return 0; mgmt = (void *)bcn->data; @@ -3259,8 +3256,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); /* This is case only for P2P_GO */ - if (arvif->vdev_type != WMI_VDEV_TYPE_AP || - arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + if (vif->type != NL80211_IFTYPE_AP || !vif->p2p) return; if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0f01a8d99604..5158716d6dff 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3196,7 +3196,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, const struct wmi_p2p_noa_info *noa) { - if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + if (!arvif->vif->p2p) return; ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed); -- cgit v1.2.3 From 6e4de1a49aa3254f46f66db5aac530707c193cde Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Thu, 28 Jan 2016 13:54:10 -0800 Subject: ath10k: add abstraction layer for vdev subtype Abstraction layer for vdev subtype is added to solve subtype mismatch and to give flexible compatibility among different firmware revisions. For instance, 10.2 and 10.4 firmware has different definition of their vdev subtypes for Mesh. 10.4 defined subtype 6 for 802.11s Mesh while 10.2 uses 5. Hence use the abstraction API to get right subtype to use. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 15 ++++--- drivers/net/wireless/ath/ath10k/wmi-ops.h | 11 +++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 70 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 42 ++++++++++++++++--- 5 files changed, 128 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index addf3cb3aeb1..96e2f8ad22fc 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4359,25 +4359,29 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, bit, ar->free_vdev_map); arvif->vdev_id = bit; - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; + arvif->vdev_subtype = + ath10k_wmi_get_vdev_subtype(ar, WMI_VDEV_SUBTYPE_NONE); switch (vif->type) { case NL80211_IFTYPE_P2P_DEVICE: arvif->vdev_type = WMI_VDEV_TYPE_STA; - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype + (ar, WMI_VDEV_SUBTYPE_P2P_DEVICE); break; case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; if (vif->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; + arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype + (ar, WMI_VDEV_SUBTYPE_P2P_CLIENT); break; case NL80211_IFTYPE_ADHOC: arvif->vdev_type = WMI_VDEV_TYPE_IBSS; break; case NL80211_IFTYPE_MESH_POINT: if (test_bit(WMI_SERVICE_MESH_11S, ar->wmi.svc_map)) { - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; + arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype + (ar, WMI_VDEV_SUBTYPE_MESH_11S); } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { ret = -EINVAL; ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n"); @@ -4389,7 +4393,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->vdev_type = WMI_VDEV_TYPE_AP; if (vif->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; + arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype + (ar, WMI_VDEV_SUBTYPE_P2P_GO); break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 8f4f6a892581..32ab34edceb5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -186,6 +186,8 @@ struct wmi_ops { u8 enable, u32 detect_level, u32 detect_margin); + int (*get_vdev_subtype)(struct ath10k *ar, + enum wmi_vdev_subtype subtype); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -1327,4 +1329,13 @@ ath10k_wmi_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable, ar->wmi.cmd->pdev_enable_adaptive_cca_cmdid); } +static inline int +ath10k_wmi_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype) +{ + if (!ar->wmi.ops->get_vdev_subtype) + return -EOPNOTSUPP; + + return ar->wmi.ops->get_vdev_subtype(ar, subtype); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 3b3a27b859f3..108593202052 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3483,6 +3483,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, }; static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 5158716d6dff..04799c73ebc8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -7413,6 +7413,71 @@ unlock: buf[len] = 0; } +int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, + enum wmi_vdev_subtype subtype) +{ + switch (subtype) { + case WMI_VDEV_SUBTYPE_NONE: + return WMI_VDEV_SUBTYPE_LEGACY_NONE; + case WMI_VDEV_SUBTYPE_P2P_DEVICE: + return WMI_VDEV_SUBTYPE_LEGACY_P2P_DEV; + case WMI_VDEV_SUBTYPE_P2P_CLIENT: + return WMI_VDEV_SUBTYPE_LEGACY_P2P_CLI; + case WMI_VDEV_SUBTYPE_P2P_GO: + return WMI_VDEV_SUBTYPE_LEGACY_P2P_GO; + case WMI_VDEV_SUBTYPE_PROXY_STA: + return WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA; + case WMI_VDEV_SUBTYPE_MESH_11S: + case WMI_VDEV_SUBTYPE_MESH_NON_11S: + return -ENOTSUPP; + } + return -ENOTSUPP; +} + +static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar, + enum wmi_vdev_subtype subtype) +{ + switch (subtype) { + case WMI_VDEV_SUBTYPE_NONE: + return WMI_VDEV_SUBTYPE_10_2_4_NONE; + case WMI_VDEV_SUBTYPE_P2P_DEVICE: + return WMI_VDEV_SUBTYPE_10_2_4_P2P_DEV; + case WMI_VDEV_SUBTYPE_P2P_CLIENT: + return WMI_VDEV_SUBTYPE_10_2_4_P2P_CLI; + case WMI_VDEV_SUBTYPE_P2P_GO: + return WMI_VDEV_SUBTYPE_10_2_4_P2P_GO; + case WMI_VDEV_SUBTYPE_PROXY_STA: + return WMI_VDEV_SUBTYPE_10_2_4_PROXY_STA; + case WMI_VDEV_SUBTYPE_MESH_11S: + return WMI_VDEV_SUBTYPE_10_2_4_MESH_11S; + case WMI_VDEV_SUBTYPE_MESH_NON_11S: + return -ENOTSUPP; + } + return -ENOTSUPP; +} + +static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar, + enum wmi_vdev_subtype subtype) +{ + switch (subtype) { + case WMI_VDEV_SUBTYPE_NONE: + return WMI_VDEV_SUBTYPE_10_4_NONE; + case WMI_VDEV_SUBTYPE_P2P_DEVICE: + return WMI_VDEV_SUBTYPE_10_4_P2P_DEV; + case WMI_VDEV_SUBTYPE_P2P_CLIENT: + return WMI_VDEV_SUBTYPE_10_4_P2P_CLI; + case WMI_VDEV_SUBTYPE_P2P_GO: + return WMI_VDEV_SUBTYPE_10_4_P2P_GO; + case WMI_VDEV_SUBTYPE_PROXY_STA: + return WMI_VDEV_SUBTYPE_10_4_PROXY_STA; + case WMI_VDEV_SUBTYPE_MESH_11S: + return WMI_VDEV_SUBTYPE_10_4_MESH_11S; + case WMI_VDEV_SUBTYPE_MESH_NON_11S: + return WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S; + } + return -ENOTSUPP; +} + static const struct wmi_ops wmi_ops = { .rx = ath10k_wmi_op_rx, .map_svc = wmi_main_svc_map, @@ -7472,6 +7537,7 @@ static const struct wmi_ops wmi_ops = { .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ @@ -7539,6 +7605,7 @@ static const struct wmi_ops wmi_10_1_ops = { .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ @@ -7607,6 +7674,7 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, .gen_delba_send = ath10k_wmi_op_gen_delba_send, .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, /* .gen_pdev_enable_adaptive_cca not implemented */ }; @@ -7673,6 +7741,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, .gen_pdev_enable_adaptive_cca = ath10k_wmi_op_gen_pdev_enable_adaptive_cca, + .get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ @@ -7739,6 +7808,7 @@ static const struct wmi_ops wmi_10_4_ops = { /* shared with 10.2 */ .gen_request_stats = ath10k_wmi_op_gen_request_stats, .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature, + .get_vdev_subtype = ath10k_wmi_10_4_op_get_vdev_subtype, }; int ath10k_wmi_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 031018a07231..049c61820765 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4295,12 +4295,40 @@ enum wmi_vdev_type { }; enum wmi_vdev_subtype { - WMI_VDEV_SUBTYPE_NONE = 0, - WMI_VDEV_SUBTYPE_P2P_DEVICE = 1, - WMI_VDEV_SUBTYPE_P2P_CLIENT = 2, - WMI_VDEV_SUBTYPE_P2P_GO = 3, - WMI_VDEV_SUBTYPE_PROXY_STA = 4, - WMI_VDEV_SUBTYPE_MESH_11S = 5, + WMI_VDEV_SUBTYPE_NONE, + WMI_VDEV_SUBTYPE_P2P_DEVICE, + WMI_VDEV_SUBTYPE_P2P_CLIENT, + WMI_VDEV_SUBTYPE_P2P_GO, + WMI_VDEV_SUBTYPE_PROXY_STA, + WMI_VDEV_SUBTYPE_MESH_11S, + WMI_VDEV_SUBTYPE_MESH_NON_11S, +}; + +enum wmi_vdev_subtype_legacy { + WMI_VDEV_SUBTYPE_LEGACY_NONE = 0, + WMI_VDEV_SUBTYPE_LEGACY_P2P_DEV = 1, + WMI_VDEV_SUBTYPE_LEGACY_P2P_CLI = 2, + WMI_VDEV_SUBTYPE_LEGACY_P2P_GO = 3, + WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA = 4, +}; + +enum wmi_vdev_subtype_10_2_4 { + WMI_VDEV_SUBTYPE_10_2_4_NONE = 0, + WMI_VDEV_SUBTYPE_10_2_4_P2P_DEV = 1, + WMI_VDEV_SUBTYPE_10_2_4_P2P_CLI = 2, + WMI_VDEV_SUBTYPE_10_2_4_P2P_GO = 3, + WMI_VDEV_SUBTYPE_10_2_4_PROXY_STA = 4, + WMI_VDEV_SUBTYPE_10_2_4_MESH_11S = 5, +}; + +enum wmi_vdev_subtype_10_4 { + WMI_VDEV_SUBTYPE_10_4_NONE = 0, + WMI_VDEV_SUBTYPE_10_4_P2P_DEV = 1, + WMI_VDEV_SUBTYPE_10_4_P2P_CLI = 2, + WMI_VDEV_SUBTYPE_10_4_P2P_GO = 3, + WMI_VDEV_SUBTYPE_10_4_PROXY_STA = 4, + WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S = 5, + WMI_VDEV_SUBTYPE_10_4_MESH_11S = 6, }; /* values for vdev_subtype */ @@ -6471,5 +6499,7 @@ size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head); void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats, char *buf); +int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, + enum wmi_vdev_subtype subtype); #endif /* _WMI_H_ */ -- cgit v1.2.3 From b1a958c933c5b0f967844ec05e76ec2985450782 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 29 Jan 2016 16:35:11 +0530 Subject: ath10k: add qca4019 hw params Add a new entry in hw_params_list for qca4019 with list of it's own details. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 20 ++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 8 ++++++++ drivers/net/wireless/ath/ath10k/targaddrs.h | 3 +++ 3 files changed, 31 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 1f4a27881936..79043872e7ac 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -201,6 +201,26 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, }, }, + { + .id = QCA4019_HW_1_0_DEV_VERSION, + .dev_id = 0, + .name = "qca4019 hw1.0", + .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .otp_exe_param = 0x0010000, + .continuous_frag_desc = true, + .channel_counters_freq_hz = 125000, + .max_probe_resp_desc_thres = 24, + .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, + .fw = { + .dir = QCA4019_HW_1_0_FW_DIR, + .fw = QCA4019_HW_1_0_FW_FILE, + .otp = QCA4019_HW_1_0_OTP_FILE, + .board = QCA4019_HW_1_0_BOARD_DATA_FILE, + .board_size = QCA4019_BOARD_DATA_SZ, + .board_ext_size = QCA4019_BOARD_EXT_DATA_SZ, + }, + }, }; static const char *const ath10k_core_fw_feature_str[] = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 4217bdbe9f01..291ca1f798e3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -106,6 +106,14 @@ enum qca9377_chip_id_rev { #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234 +/* QCA4019 1.0 definitions */ +#define QCA4019_HW_1_0_DEV_VERSION 0x01000000 +#define QCA4019_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA4019/hw1.0" +#define QCA4019_HW_1_0_FW_FILE "firmware.bin" +#define QCA4019_HW_1_0_OTP_FILE "otp.bin" +#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin" +#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234 + #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index 05a421bc322a..361f143b019c 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -456,4 +456,7 @@ Fw Mode/SubMode Mask #define QCA99X0_BOARD_DATA_SZ 12288 #define QCA99X0_BOARD_EXT_DATA_SZ 0 +#define QCA4019_BOARD_DATA_SZ 12064 +#define QCA4019_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ -- cgit v1.2.3 From 5699a6f238ebfc8a6be3963a30d86d6f1e8aaaf9 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 29 Jan 2016 16:35:12 +0530 Subject: ath10k: populate qca4019 fw specific wmi init params Some of the parameter like tx/rx chain mask, number of htt tx desc, qcache active peer count, etc goes via wmi init cmd to qca4019 firmware are different. To make use of 10.4 gen_init function for qca4019, change wmi service ready handler and 10.4 wmi init functions to adapt qca4019 specific init values. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 14 ++++++++++++-- drivers/net/wireless/ath/ath10k/core.h | 6 ++++++ drivers/net/wireless/ath/ath10k/hw.h | 6 ------ drivers/net/wireless/ath/ath10k/wmi.c | 12 ++++++------ drivers/net/wireless/ath/ath10k/wmi.h | 1 - 5 files changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 79043872e7ac..4d3176492ae7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -156,6 +156,11 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .channel_counters_freq_hz = 150000, .max_probe_resp_desc_thres = 24, .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, + .num_msdu_desc = 1424, + .qcache_active_peers = 50, + .tx_chain_mask = 0xf, + .rx_chain_mask = 0xf, + .max_spatial_stream = 4, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, @@ -212,6 +217,11 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .channel_counters_freq_hz = 125000, .max_probe_resp_desc_thres = 24, .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, + .num_msdu_desc = 2500, + .qcache_active_peers = 35, + .tx_chain_mask = 0x3, + .rx_chain_mask = 0x3, + .max_spatial_stream = 2, .fw = { .dir = QCA4019_HW_1_0_FW_DIR, .fw = QCA4019_HW_1_0_FW_FILE, @@ -1523,9 +1533,9 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; - ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; + ar->htt.max_num_pending_tx = ar->hw_params.num_msdu_desc; ar->fw_stats_req_mask = WMI_STAT_PEER; - ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM; + ar->max_spatial_stream = ar->hw_params.max_spatial_stream; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2e411b5258c2..a62b62a62266 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -680,6 +680,12 @@ struct ath10k { /* The padding bytes's location is different on various chips */ enum ath10k_hw_4addr_pad hw_4addr_pad; + u32 num_msdu_desc; + u32 qcache_active_peers; + u32 tx_chain_mask; + u32 rx_chain_mask; + u32 max_spatial_stream; + struct ath10k_hw_params_fw { const char *dir; const char *fw; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 291ca1f798e3..2dece8db83f8 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -426,16 +426,11 @@ enum ath10k_hw_4addr_pad { #define TARGET_10_4_ACTIVE_PEERS 0 #define TARGET_10_4_NUM_QCACHE_PEERS_MAX 512 -#define TARGET_10_4_QCACHE_ACTIVE_PEERS 50 #define TARGET_10_4_NUM_OFFLOAD_PEERS 0 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 #define TARGET_10_4_NUM_PEER_KEYS 2 #define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2) #define TARGET_10_4_AST_SKID_LIMIT 32 -#define TARGET_10_4_TX_CHAIN_MASK (BIT(0) | BIT(1) | \ - BIT(2) | BIT(3)) -#define TARGET_10_4_RX_CHAIN_MASK (BIT(0) | BIT(1) | \ - BIT(2) | BIT(3)) /* 100 ms for video, best-effort, and background */ #define TARGET_10_4_RX_TIMEOUT_LO_PRI 100 @@ -461,7 +456,6 @@ enum ath10k_hw_4addr_pad { #define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 #define TARGET_10_4_VOW_CONFIG 0 #define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV 3 -#define TARGET_10_4_NUM_MSDU_DESC (1024 + 400) #define TARGET_10_4_11AC_TX_MAX_FRAGS 2 #define TARGET_10_4_MAX_PEER_EXT_STATS 16 #define TARGET_10_4_SMART_ANT_CAP 0 diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 04799c73ebc8..1ce67423224a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4618,9 +4618,9 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) { ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX + - TARGET_10_4_NUM_VDEVS; - ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS + - TARGET_10_4_NUM_VDEVS; + ar->max_num_vdevs; + ar->num_active_peers = ar->hw_params.qcache_active_peers + + ar->max_num_vdevs; ar->num_tids = ar->num_active_peers * 2; ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX; } @@ -5602,8 +5602,8 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS); config.num_peer_keys = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS); config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT); - config.tx_chain_mask = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK); - config.rx_chain_mask = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK); + config.tx_chain_mask = __cpu_to_le32(ar->hw_params.tx_chain_mask); + config.rx_chain_mask = __cpu_to_le32(ar->hw_params.rx_chain_mask); config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); @@ -5634,7 +5634,7 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG); config.gtk_offload_max_vdev = __cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV); - config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC); + config.num_msdu_desc = __cpu_to_le32(ar->htt.max_num_pending_tx); config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS); config.max_peer_ext_stats = __cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 049c61820765..4d3cbc44fcd2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1818,7 +1818,6 @@ enum wmi_channel_change_cause { #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13) #define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */ -#define WMI_10_4_MAX_SPATIAL_STREAM 4 /* HT Capabilities*/ #define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ -- cgit v1.2.3 From 67edf354faaf93156646e741483b2313bc756c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Jan 2016 08:45:25 +0100 Subject: bcma: use _PMU_ in all names of PMU registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PMU (Power Management Unit) seems to be a separated piece of hardware, just accessed using ChipCommon core registers. In recent Broadcom chipsets PMU is not bounded to CC but available as separated core. To make code cleaner & easier to review (for a correct R/W access) use clearer names. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index ec013fbd6a81..c279211e49f9 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev) case B43_BUS_BCMA: bcma_cc = &dev->dev->bdev->bus->drv_cc; - bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0); - bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4); - bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4); - bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4); + bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0); + bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4); + bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4); + bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4); break; #endif #ifdef CONFIG_B43_SSB -- cgit v1.2.3 From 36e8072ebeb1981074c7ec1b63bae3ecc3295b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 20 Jan 2016 16:46:04 +0100 Subject: brcmfmac: fix setting primary channel for 80 MHz width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First of all it changes the way we calculate primary channel offset. If we use e.g. 80 MHz channel with primary frequency 5180 MHz (which means center frequency is 5210 MHz) it makes sense to calculate primary offset as -30 MHz. Then it fixes values we compare primary_offset with. We were comparing offset in MHz against -2 or 2 which was resulting in picking a wrong primary channel. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 23 ++++++++++------------ 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 7b01e4ddb315..d00c5c1d58bf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n", ch->chan->center_freq, ch->center_freq1, ch->width); ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1); - primary_offset = ch->center_freq1 - ch->chan->center_freq; + primary_offset = ch->chan->center_freq - ch->center_freq1; switch (ch->width) { case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20_NOHT: @@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, break; case NL80211_CHAN_WIDTH_40: ch_inf.bw = BRCMU_CHAN_BW_40; - if (primary_offset < 0) + if (primary_offset > 0) ch_inf.sb = BRCMU_CHAN_SB_U; else ch_inf.sb = BRCMU_CHAN_SB_L; break; case NL80211_CHAN_WIDTH_80: ch_inf.bw = BRCMU_CHAN_BW_80; - if (primary_offset < 0) { - if (primary_offset < -CH_10MHZ_APART) - ch_inf.sb = BRCMU_CHAN_SB_UU; - else - ch_inf.sb = BRCMU_CHAN_SB_UL; - } else { - if (primary_offset > CH_10MHZ_APART) - ch_inf.sb = BRCMU_CHAN_SB_LL; - else - ch_inf.sb = BRCMU_CHAN_SB_LU; - } + if (primary_offset == -30) + ch_inf.sb = BRCMU_CHAN_SB_LL; + else if (primary_offset == -10) + ch_inf.sb = BRCMU_CHAN_SB_LU; + else if (primary_offset == 10) + ch_inf.sb = BRCMU_CHAN_SB_UL; + else + ch_inf.sb = BRCMU_CHAN_SB_UU; break; case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160: -- cgit v1.2.3 From a4f4abd037c1f8c6a834c95a46a2514d4b350888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 26 Jan 2016 17:57:01 +0100 Subject: brcmfmac: analyze descriptors of current component only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far we were looking for address descriptors without a check for crossing current component border. In case of dealing with unsupported descriptor or descriptor missing at all the code would incorrectly get data from another component. Consider this binary-described component from BCM4366 EROM: 4bf83b01 TAG==CI CID==0x83b 20080201 TAG==CI PORTS==0+1 WRAPPERS==0+1 18400035 TAG==ADDR SZ_SZD TYPE_SLAVE 00050000 18107085 TAG==ADDR SZ_4K TYPE_SWRAP Driver was assigning invalid base address to this core: brcmfmac: [6 ] core 0x83b:32 base 0x18109000 wrap 0x18107000 which came from totally different component defined in EROM: 43b36701 TAG==CI CID==0x367 00000201 TAG==CI PORTS==0+1 WRAPPERS==0+0 18109005 TAG==ADDR SZ_4K TYPE_SLAVE This change will also allow us to support components without wrapper address in the future. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 82e4382eb177..e434e2a52098 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, *eromaddr -= 4; return -EFAULT; } - } while (desc != DMP_DESC_ADDRESS); + } while (desc != DMP_DESC_ADDRESS && + desc != DMP_DESC_COMPONENT); + + /* stop if we crossed current component border */ + if (desc == DMP_DESC_COMPONENT) { + *eromaddr -= 4; + return 0; + } /* skip upper 32-bit address descriptor */ if (val & DMP_DESC_ADDRSIZE_GT32) -- cgit v1.2.3 From 44977b81823f4801d45d61fb9b278b4483923ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 26 Jan 2016 17:57:02 +0100 Subject: brcmfmac: allow storing PMU core without wrapper address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separated PMU core can be found in new devices and should be used for accessing PMU registers (which were routed through ChipCommon so far). This core is one of exceptions that doesn't have or need wrapper address to be still safely accessible. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index e434e2a52098..55952d43dfb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -883,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; /* need core with ports */ - if (nmw + nsw == 0) + if (nmw + nsw == 0 && + id != BCMA_CORE_PMU) continue; /* try to obtain register address info */ -- cgit v1.2.3 From 9befe9195a17856f8bf5ede7a5c067bd0a281be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 26 Jan 2016 17:57:03 +0100 Subject: brcmfmac: read extended capabilities of ChipCommon core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an extra bitfield with info about some present hardware. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 3 +++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 55952d43dfb5..f4a4d00cb4a2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -1025,6 +1025,9 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip) /* get chipcommon capabilites */ pub->cc_caps = chip->ops->read32(chip->ctx, CORE_CC_REG(base, capabilities)); + pub->cc_caps_ext = chip->ops->read32(chip->ctx, + CORE_CC_REG(base, + capabilities_ext)); /* get pmu caps & rev */ if (pub->cc_caps & CC_CAP_PMU) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h index f6b5feea23d2..cb9145f1786a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h @@ -27,6 +27,7 @@ * @chip: chip identifier. * @chiprev: chip revision. * @cc_caps: chipcommon core capabilities. + * @cc_caps_ext: chipcommon core extended capabilities. * @pmucaps: PMU capabilities. * @pmurev: PMU revision. * @rambase: RAM base address (only applicable for ARM CR4 chips). @@ -38,6 +39,7 @@ struct brcmf_chip { u32 chip; u32 chiprev; u32 cc_caps; + u32 cc_caps_ext; u32 pmucaps; u32 pmurev; u32 rambase; -- cgit v1.2.3 From e2b397f18cc6423c2dad87f9a633add762d869dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 26 Jan 2016 17:57:04 +0100 Subject: brcmfmac: access PMU registers using standalone PMU core if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On recent Broadcom chipsets PMU is present as separated core and it can't be accessed using ChipCommon anymore as it fails with e.g.: [ 18.198412] Unhandled fault: imprecise external abort (0x1406) at 0xb6da200f Add a new helper function that will return a proper core that should be used for accessing PMU registers. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 30 ++++++++++++++++++---- .../wireless/broadcom/brcm80211/brcmfmac/chip.h | 1 + .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 9 +++---- 3 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index f4a4d00cb4a2..0e8f2a079907 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -1014,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip) { struct brcmf_chip *pub; struct brcmf_core_priv *cc; + struct brcmf_core *pmu; u32 base; u32 val; int ret = 0; @@ -1030,9 +1031,10 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip) capabilities_ext)); /* get pmu caps & rev */ + pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */ if (pub->cc_caps & CC_CAP_PMU) { val = chip->ops->read32(chip->ctx, - CORE_CC_REG(base, pmucapabilities)); + CORE_CC_REG(pmu->base, pmucapabilities)); pub->pmurev = val & PCAP_REV_MASK; pub->pmucaps = val; } @@ -1131,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub) return &cc->pub; } +struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub) +{ + struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub); + struct brcmf_core *pmu; + + /* See if there is separated PMU core available */ + if (cc->rev >= 35 && + pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) { + pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU); + if (pmu) + return pmu; + } + + /* Fallback to ChipCommon core for older hardware */ + return cc; +} + bool brcmf_chip_iscoreup(struct brcmf_core *pub) { struct brcmf_core_priv *core; @@ -1301,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) { u32 base, addr, reg, pmu_cc3_mask = ~0; struct brcmf_chip_priv *chip; + struct brcmf_core *pmu = brcmf_chip_get_pmu(pub); brcmf_dbg(TRACE, "Enter\n"); @@ -1320,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) case BRCM_CC_4335_CHIP_ID: case BRCM_CC_4339_CHIP_ID: /* read PMU chipcontrol register 3 */ - addr = CORE_CC_REG(base, chipcontrol_addr); + addr = CORE_CC_REG(pmu->base, chipcontrol_addr); chip->ops->write32(chip->ctx, addr, 3); - addr = CORE_CC_REG(base, chipcontrol_data); + addr = CORE_CC_REG(pmu->base, chipcontrol_data); reg = chip->ops->read32(chip->ctx, addr); return (reg & pmu_cc3_mask) != 0; case BRCM_CC_43430_CHIP_ID: @@ -1330,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) reg = chip->ops->read32(chip->ctx, addr); return reg != 0; default: - addr = CORE_CC_REG(base, pmucapabilities_ext); + addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); reg = chip->ops->read32(chip->ctx, addr); if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) return false; - addr = CORE_CC_REG(base, retention_ctl); + addr = CORE_CC_REG(pmu->base, retention_ctl); reg = chip->ops->read32(chip->ctx, addr); return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h index cb9145f1786a..dd0ec3eba6a9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h @@ -85,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, void brcmf_chip_detach(struct brcmf_chip *chip); struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); +struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub); bool brcmf_chip_iscoreup(struct brcmf_core *core); void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index dd6614332836..80b5d4784645 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, const struct sdiod_drive_str *str_tab = NULL; u32 str_mask; u32 str_shift; - u32 base; u32 i; u32 drivestrength_sel = 0; u32 cc_data_temp; @@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, } if (str_tab != NULL) { + struct brcmf_core *pmu = brcmf_chip_get_pmu(ci); + for (i = 0; str_tab[i].strength != 0; i++) { if (drivestrength >= str_tab[i].strength) { drivestrength_sel = str_tab[i].sel; break; } } - base = brcmf_chip_get_chipcommon(ci)->base; - addr = CORE_CC_REG(base, chipcontrol_addr); + addr = CORE_CC_REG(pmu->base, chipcontrol_addr); brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); cc_data_temp &= ~str_mask; @@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) goto fail; /* set PMUControl so a backplane reset does PMU state reload */ - reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base, - pmucontrol); + reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); if (err) goto fail; -- cgit v1.2.3 From f66ab2a7da8ffd78ba26048f8108577ba73a1828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 26 Jan 2016 17:57:05 +0100 Subject: brcmfmac: add support for 14e4:4365 PCI ID with BCM4366 chipset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Broadcom ARM routers BCM4366 cards are available with 14e4:4365 ID. Unfortunately this ID was already used by Broadcom for cards with BCM43142, a totally different chipset requiring SoftMAC driver. To avoid a conflict between brcmfmac and bcma use more specific ID entry with subvendor and subdevice specified. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 0480b70e3eb8..d5f9ef470447 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { #define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } +#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \ + BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ + subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } static struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), @@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID), + BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), -- cgit v1.2.3 From d1e61b86a2b1b99e5dcd4d41aa23d033b83542a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 31 Jan 2016 12:14:34 +0100 Subject: brcmfmac: treat NULL character in NVRAM as separator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Platform NVRAM (stored on a flash partition) has entries separated by a NULL (\0) char. Our parsing code switches from VALUE state to IDLE whenever it meets a NULL (\0). When that happens our IDLE handler should simply consume it and analyze whatever is placed ahead. This fixes harmless warnings spamming debugging output: [ 155.165624] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=20: ignoring invalid character [ 155.180806] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=44: ignoring invalid character [ 155.195971] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=63: ignoring invalid character Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 1365c12b78fc..7269056d0044 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp) c = nvp->data[nvp->pos]; if (c == '\n') return COMMENT; - if (is_whitespace(c)) + if (is_whitespace(c) || c == '\0') goto proceed; if (c == '#') return COMMENT; -- cgit v1.2.3 From 97f1a17109272b9f060cbd6d1d5be41528643000 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Mon, 25 Jan 2016 11:47:29 +0100 Subject: brcmfmac: sdio: Increase the default timeouts a bit On a Radxa Rock2 board with a Ampak AP6335 (Broadcom 4339 core) it seems the card responds very quickly most of the time, unfortunately during initialisation it sometimes seems to take just a bit over 2 seconds to respond. This results intialization failing with message like: brcmf_c_preinit_dcmds: Retreiving cur_etheraddr failed, -52 brcmf_bus_start: failed: -52 brcmf_sdio_firmware_callback: dongle is not responding Increasing the timeout to allow for a bit more headroom allows the card to initialize reliably. A quick search online after diagnosing/fixing this showed that Google has a similar patch in their ChromeOS tree, so this doesn't seem specific to the board I'm using. Signed-off-by: Sjoerd Simons Reviewed-by: Julian Calaby Acked-by: Arend van Spriel Reviewed-by: Douglas Anderson Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 80b5d4784645..6776e45b2958 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -45,8 +45,8 @@ #include "chip.h" #include "firmware.h" -#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000) -#define CTL_DONE_TIMEOUT msecs_to_jiffies(2000) +#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) +#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) #ifdef DEBUG -- cgit v1.2.3 From 48dc5fb3ba53b20418de8514700f63d88c5de3a3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 28 Jan 2016 22:58:28 +0100 Subject: hostap: avoid uninitialized variable use in hfa384x_get_rid The driver reads a value from hfa384x_from_bap(), which may fail, and then assigns the value to a local variable. gcc detects that in in the failure case, the 'rlen' variable now contains uninitialized data: In file included from ../drivers/net/wireless/intersil/hostap/hostap_pci.c:220:0: drivers/net/wireless/intersil/hostap/hostap_hw.c: In function 'hfa384x_get_rid': drivers/net/wireless/intersil/hostap/hostap_hw.c:842:5: warning: 'rec' may be used uninitialized in this function [-Wmaybe-uninitialized] if (le16_to_cpu(rec.len) == 0) { This restructures the function as suggested by Russell King, to make it more readable and get more reliable error handling, by handling each failure mode using a goto. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/intersil/hostap/hostap_hw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index 6df3ee561d52..515aa3f993f3 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, spin_lock_bh(&local->baplock); res = hfa384x_setup_bap(dev, BAP0, rid, 0); - if (!res) - res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); + if (res) + goto unlock; + + res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); + if (res) + goto unlock; if (le16_to_cpu(rec.len) == 0) { /* RID not available */ res = -ENODATA; + goto unlock; } rlen = (le16_to_cpu(rec.len) - 1) * 2; - if (!res && exact_len && rlen != len) { + if (exact_len && rlen != len) { printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " "rid=0x%04x, len=%d (expected %d)\n", dev->name, rid, rlen, len); res = -ENODATA; } - if (!res) - res = hfa384x_from_bap(dev, BAP0, buf, len); + res = hfa384x_from_bap(dev, BAP0, buf, len); +unlock: spin_unlock_bh(&local->baplock); mutex_unlock(&local->rid_bap_mtx); -- cgit v1.2.3 From 44ca509cb9769f27ad8f7d662910e31329eed46f Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Sun, 31 Jan 2016 23:44:46 -0800 Subject: mwifiex: fix bandwidth display problem Instead of using HT info from beacon IEs, use HT info from association response frame to update bandwidth in cfg80211_get_channel handler. Signed-off-by: Nachiket Kukade Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 ++-- drivers/net/wireless/marvell/mwifiex/fw.h | 2 +- drivers/net/wireless/marvell/mwifiex/join.c | 15 +++++++++++++++ drivers/net/wireless/marvell/mwifiex/main.h | 2 ++ drivers/net/wireless/marvell/mwifiex/sta_event.c | 3 +++ 5 files changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 84615533986c..f2dce81ba36e 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3793,8 +3793,8 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, freq = ieee80211_channel_to_frequency(curr_bss->channel, band); chan = ieee80211_get_channel(wiphy, freq); - if (curr_bss->bcn_ht_oper) { - second_chan_offset = curr_bss->bcn_ht_oper->ht_param & + if (priv->ht_param_present) { + second_chan_offset = priv->assoc_resp_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; chan_type = mwifiex_sec_chan_offset_to_chan_type (second_chan_offset); diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 4af916817bcd..c134cf865291 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -1063,7 +1063,7 @@ struct ieee_types_assoc_rsp { __le16 cap_info_bitmap; __le16 status_code; __le16 a_id; - u8 ie_buffer[1]; + u8 ie_buffer[0]; } __packed; struct host_cmd_ds_802_11_associate_rsp { diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index cc09a81dbf6a..62211fca91b7 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -644,6 +644,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc; bool enable_data = true; u16 cap_info, status_code, aid; + const u8 *ie_ptr; + struct ieee80211_ht_operation *assoc_resp_ht_oper; assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; @@ -733,6 +735,19 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, = ((bss_desc->wmm_ie.qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); + /* Store the bandwidth information from assoc response */ + ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, + priv->assoc_rsp_size + - sizeof(struct ieee_types_assoc_rsp)); + if (ie_ptr) { + assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr + + sizeof(struct ieee_types_header)); + priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; + priv->ht_param_present = true; + } else { + priv->ht_param_present = false; + } + mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", priv->curr_pkt_filter); diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index c755be54cc83..89a1576d0a4b 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -674,6 +674,8 @@ struct mwifiex_private { struct mwifiex_ds_mem_rw mem_rw; struct sk_buff_head bypass_txq; struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX]; + u8 assoc_resp_ht_param; + bool ht_param_present; }; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index fd8061c73091..070bce401151 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -92,6 +92,9 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) priv->is_data_rate_auto = true; priv->data_rate = 0; + priv->assoc_resp_ht_param = 0; + priv->ht_param_present = false; + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) mwifiex_hist_data_reset(priv); -- cgit v1.2.3 From efdf0e393e76aa18e9c2ec0ca9b3a71ad410994b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Feb 2016 13:00:05 +0300 Subject: mwifiex: fix a reversed condition The NULL test here is reversed. Fixes: 7d7f07d8c5d3 ('mwifiex: add wowlan net-detect support') Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index fc8d8ca67453..489f7a911a83 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2196,7 +2196,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, pmatch = adapter->nd_info->matches[idx]; - if (!pmatch) { + if (pmatch) { memset(pmatch, 0, sizeof(*pmatch)); if (chan_band_tlv) { pmatch->n_channels = 1; -- cgit v1.2.3 From 0a7701b4defcebc7ce461355e6d9478df313b084 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Jan 2016 18:01:51 +0100 Subject: libertas: fix pointer bugs for PS_MODE commands struct cmd_ds_802_11_ps_mode contains the command header and a pointer to it was initialized with data points to the body which leads to mis-interpretation of the cmd_ds_802_11_ps_mode.action member. cmd[0] contains the header, &cmd[1] points beyond that. cmdnode->cmdbuf is a pointer to the command buffer This piece of code was unused since power saving was not enabled. Signed-off-by: Andreas Kemnade Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cmd.c | 4 ++-- drivers/net/wireless/marvell/libertas/cmdresp.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c index 0387a5b380c8..40467d646270 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.c +++ b/drivers/net/wireless/marvell/libertas/cmd.c @@ -957,7 +957,7 @@ static void lbs_queue_cmd(struct lbs_private *priv, /* Exit_PS command needs to be queued in the header always. */ if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) { - struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf; + struct cmd_ds_802_11_ps_mode *psm = (void *)cmdnode->cmdbuf; if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) { if (priv->psstate != PS_STATE_FULL_POWER) @@ -1387,7 +1387,7 @@ int lbs_execute_next_command(struct lbs_private *priv) * PS command. Ignore it if it is not Exit_PS. * otherwise send it down immediately. */ - struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1]; + struct cmd_ds_802_11_ps_mode *psm = (void *)cmd; lbs_deb_host( "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n", diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index e5442e8956f7..701125f9b060 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -123,7 +123,10 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) priv->cmd_timed_out = 0; if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { - struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1]; + /* struct cmd_ds_802_11_ps_mode also contains + * the header + */ + struct cmd_ds_802_11_ps_mode *psmode = (void *)resp; u16 action = le16_to_cpu(psmode->action); lbs_deb_host( -- cgit v1.2.3 From fae4f9f78ab11937bc45b0f3625efe2e35aed510 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Jan 2016 18:01:52 +0100 Subject: libertas: check whether bus can do more than polling If a sdio host does not support sdio irqs, polling is used instead. That has an impact on performance. Some functionality should not be enabled then. This add a variable in libertas_priv to indicate that. Signed-off-by: Andreas Kemnade Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/dev.h | 1 + drivers/net/wireless/marvell/libertas/if_sdio.c | 2 +- drivers/net/wireless/marvell/libertas/if_usb.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/dev.h b/drivers/net/wireless/marvell/libertas/dev.h index 6bd1608992b0..edf710bc5e77 100644 --- a/drivers/net/wireless/marvell/libertas/dev.h +++ b/drivers/net/wireless/marvell/libertas/dev.h @@ -99,6 +99,7 @@ struct lbs_private { /* Hardware access */ void *card; bool iface_running; + u8 is_polling; /* host has to poll the card irq */ u8 fw_ready; u8 surpriseremoved; u8 setup_fw_on_resume; diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 68fd3a9779bd..13eae9ff8c35 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1267,7 +1267,7 @@ static int if_sdio_probe(struct sdio_func *func, priv->reset_card = if_sdio_reset_card; priv->power_save = if_sdio_power_save; priv->power_restore = if_sdio_power_restore; - + priv->is_polling = !(func->card->host->caps & MMC_CAP_SDIO_IRQ); ret = if_sdio_power_on(card); if (ret) goto err_activate_card; diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index dff08a2896a3..aba0c9995b14 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -267,6 +267,7 @@ static int if_usb_probe(struct usb_interface *intf, priv->enter_deep_sleep = NULL; priv->exit_deep_sleep = NULL; priv->reset_deep_sleep_wakeup = NULL; + priv->is_polling = false; #ifdef CONFIG_OLPC if (machine_is_olpc()) priv->reset_card = if_usb_reset_olpc_card; -- cgit v1.2.3 From 57954b94cad77c3253beca805cf493861c7d92b5 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Jan 2016 18:01:53 +0100 Subject: libertas: do not confirm sleep if commands are pending If the main thread gets one PS AWAKE event and one PS SLEEP event in one iteration over event_fifo there will never be checks for commands to be processed, since psstate will always be PS_STATE_SLEEP or PS_STATE_PRE_SLEEP Signed-off-by: Andreas Kemnade Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cmdresp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index 701125f9b060..c95bf6dc9522 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -257,6 +257,10 @@ int lbs_process_event(struct lbs_private *priv, u32 event) "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n"); break; } + if (!list_empty(&priv->cmdpendingq)) { + lbs_deb_cmd("EVENT: commands in queue, do not sleep\n"); + break; + } priv->psstate = PS_STATE_PRE_SLEEP; lbs_ps_confirm_sleep(priv); -- cgit v1.2.3 From fada24a5477073dd8fa84baf25ead204dc1dcb18 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Jan 2016 18:01:54 +0100 Subject: libertas: go back to ps mode without commands pending Removes the old todo block and checks only whether ieee powersave mode is requested. We still have to check for being connected as this powersave mode includes logic for regularly waking up and checking for packets which only makes sense when connected. For not being connected, another mode is needed. Signed-off-by: Andreas Kemnade Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cmd.c | 36 ++++------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c index 40467d646270..4ddd0e5a6b85 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.c +++ b/drivers/net/wireless/marvell/libertas/cmd.c @@ -1428,40 +1428,14 @@ int lbs_execute_next_command(struct lbs_private *priv) * check if in power save mode, if yes, put the device back * to PS mode */ -#ifdef TODO - /* - * This was the old code for libertas+wext. Someone that - * understands this beast should re-code it in a sane way. - * - * I actually don't understand why this is related to WPA - * and to connection status, shouldn't powering should be - * independ of such things? - */ if ((priv->psmode != LBS802_11POWERMODECAM) && (priv->psstate == PS_STATE_FULL_POWER) && - ((priv->connect_status == LBS_CONNECTED) || - lbs_mesh_connected(priv))) { - if (priv->secinfo.WPAenabled || - priv->secinfo.WPA2enabled) { - /* check for valid WPA group keys */ - if (priv->wpa_mcast_key.len || - priv->wpa_unicast_key.len) { - lbs_deb_host( - "EXEC_NEXT_CMD: WPA enabled and GTK_SET" - " go back to PS_SLEEP"); - lbs_set_ps_mode(priv, - PS_MODE_ACTION_ENTER_PS, - false); - } - } else { - lbs_deb_host( - "EXEC_NEXT_CMD: cmdpendingq empty, " - "go back to PS_SLEEP"); - lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS, - false); - } + (priv->connect_status == LBS_CONNECTED)) { + lbs_deb_host( + "EXEC_NEXT_CMD: cmdpendingq empty, go back to PS_SLEEP"); + lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS, + false); } -#endif } ret = 0; -- cgit v1.2.3 From 0b8802dc5f59a4517e4130dc3606eb973760928a Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Jan 2016 18:01:55 +0100 Subject: libertas: fix ps-mode related removal problems When the device is remove e.g. because of going to suspend mode with powersaving enabled, lbs_remove_card tries to exit powersaving state even when already woken up. That command is not processed properly in that situation, since the command processing queue is already stopped, so it waits forever for the command being processed, so disable it. Signed-off-by: Andreas Kemnade Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index 8079560f4965..b35b8bcce24c 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -1060,7 +1060,12 @@ void lbs_remove_card(struct lbs_private *priv) if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { priv->psmode = LBS802_11POWERMODECAM; - lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true); + /* no need to wakeup if already woken up, + * on suspend, this exit ps command is not processed + * the driver hangs + */ + if (priv->psstate != PS_STATE_FULL_POWER) + lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true); } if (priv->is_deep_sleep) { -- cgit v1.2.3 From 143e49458424b80fd004963b6ba88ed583ea62da Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Jan 2016 18:01:56 +0100 Subject: libertas: add an cfg80211 interface for powersaving This patch adds an interface for handling commands like iwconfig wlanX power on/off. Such an interface formerly existed when the driver used wext. While performance with sdio in polling mode without using powersave mode is quite bad, powersaving mode is unusable, so do not enable it under such conditions. Signed-off-by: Andreas Kemnade Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cfg.c | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 86955c416b30..2eea76a340b7 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -2039,6 +2039,43 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct lbs_private *priv = wiphy_priv(wiphy); + + if (!(priv->fwcapinfo & FW_CAPINFO_PS)) { + if (!enabled) + return 0; + else + return -EINVAL; + } + /* firmware does not work well with too long latency with power saving + * enabled, so do not enable it if there is only polling, no + * interrupts (like in some sdio hosts which can only + * poll for sdio irqs) + */ + if (priv->is_polling) { + if (!enabled) + return 0; + else + return -EINVAL; + } + if (!enabled) { + priv->psmode = LBS802_11POWERMODECAM; + if (priv->psstate != PS_STATE_FULL_POWER) + lbs_set_ps_mode(priv, + PS_MODE_ACTION_EXIT_PS, + true); + return 0; + } + if (priv->psmode != LBS802_11POWERMODECAM) + return 0; + priv->psmode = LBS802_11POWERMODEMAX_PSP; + if (priv->connect_status == LBS_CONNECTED) + lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS, true); + return 0; +} /* * Initialization @@ -2057,6 +2094,7 @@ static struct cfg80211_ops lbs_cfg80211_ops = { .change_virtual_intf = lbs_change_intf, .join_ibss = lbs_join_ibss, .leave_ibss = lbs_leave_ibss, + .set_power_mgmt = lbs_set_power_mgmt, }; -- cgit v1.2.3 From ac2b335e7149e7dd0c8dcbb2b158a17b78c480a1 Mon Sep 17 00:00:00 2001 From: Paul Mcquade Date: Sat, 17 Oct 2015 21:04:39 +0100 Subject: net: wireless: rt2x00: Fixed Spacing issues Removed empty spaces before/after parenthesis Signed-off-by: Paul McQuade Acked-by: Helmut Schaa Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt61pci.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.h b/drivers/net/wireless/ralink/rt2x00/rt61pci.h index 1442075a8382..ab8641547a1f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.h +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.h @@ -138,14 +138,14 @@ #define PAIRWISE_TA_TABLE_BASE 0x1a00 #define SHARED_KEY_ENTRY(__idx) \ - ( SHARED_KEY_TABLE_BASE + \ - ((__idx) * sizeof(struct hw_key_entry)) ) + (SHARED_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry))) #define PAIRWISE_KEY_ENTRY(__idx) \ - ( PAIRWISE_KEY_TABLE_BASE + \ - ((__idx) * sizeof(struct hw_key_entry)) ) + (PAIRWISE_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry))) #define PAIRWISE_TA_ENTRY(__idx) \ - ( PAIRWISE_TA_TABLE_BASE + \ - ((__idx) * sizeof(struct hw_pairwise_ta_entry)) ) + (PAIRWISE_TA_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_pairwise_ta_entry))) struct hw_key_entry { u8 key[16]; @@ -180,7 +180,7 @@ struct hw_pairwise_ta_entry { #define HW_BEACON_BASE3 0x2f00 #define HW_BEACON_OFFSET(__index) \ - ( HW_BEACON_BASE0 + (__index * 0x0100) ) + (HW_BEACON_BASE0 + (__index * 0x0100)) /* * HOST-MCU shared memory. @@ -1287,9 +1287,9 @@ struct hw_pairwise_ta_entry { /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 16 * sizeof(__le32) ) -#define TXINFO_SIZE ( 6 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 16 * sizeof(__le32) ) +#define TXD_DESC_SIZE (16 * sizeof(__le32)) +#define TXINFO_SIZE (6 * sizeof(__le32)) +#define RXD_DESC_SIZE (16 * sizeof(__le32)) /* * TX descriptor format for TX, PRIO and Beacon Ring. -- cgit v1.2.3 From b2cc2dd8ebb885ad1b2ee4c5d35b40d98db211fa Mon Sep 17 00:00:00 2001 From: Paul Mcquade Date: Sat, 17 Oct 2015 22:06:43 +0100 Subject: net: wireless: rt2x00: Space issue Removed empty spaces before/after parenthesis Signed-off-by: Paul McQuade Acked-by: Helmut Schaa Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 3282ddb766f4..8c679f2d668d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -107,7 +107,7 @@ * amount of bytes needed to move the data. */ #define ALIGN_SIZE(__skb, __header) \ - ( ((unsigned long)((__skb)->data + (__header))) & 3 ) + (((unsigned long)((__skb)->data + (__header))) & 3) /* * Constants for extra TX headroom for alignment purposes. @@ -128,14 +128,14 @@ #define SLOT_TIME 20 #define SHORT_SLOT_TIME 9 #define SIFS 10 -#define PIFS ( SIFS + SLOT_TIME ) -#define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME ) -#define DIFS ( PIFS + SLOT_TIME ) -#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) -#define EIFS ( SIFS + DIFS + \ - GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) -#define SHORT_EIFS ( SIFS + SHORT_DIFS + \ - GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) +#define PIFS (SIFS + SLOT_TIME) +#define SHORT_PIFS (SIFS + SHORT_SLOT_TIME) +#define DIFS (PIFS + SLOT_TIME) +#define SHORT_DIFS (SHORT_PIFS + SHORT_SLOT_TIME) +#define EIFS (SIFS + DIFS + \ + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10)) +#define SHORT_EIFS (SIFS + SHORT_DIFS + \ + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10)) enum rt2x00_chip_intf { RT2X00_CHIP_INTF_PCI, -- cgit v1.2.3 From 5b451715e94d43fdb8f3cca67d1ec72184f294f9 Mon Sep 17 00:00:00 2001 From: Paul Mcquade Date: Sat, 17 Oct 2015 22:11:23 +0100 Subject: net: wireless: rt2x00: Space Required Space needed before open parenthesis Signed-off-by: Paul McQuade Acked-by: Helmut Schaa Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2x00debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 90fdb02b55e7..25ee3cb8e982 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -629,7 +629,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, data += sprintf(data, "register\tbase\twords\twordsize\n"); #define RT2X00DEBUGFS_SPRINTF_REGISTER(__name) \ { \ - if(debug->__name.read) \ + if (debug->__name.read) \ data += sprintf(data, __stringify(__name) \ "\t%d\t%d\t%d\n", \ debug->__name.word_base, \ @@ -699,7 +699,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ ({ \ - if(debug->__name.read) { \ + if (debug->__name.read) { \ (__intf)->__name##_off_entry = \ debugfs_create_u32(__stringify(__name) "_offset", \ S_IRUSR | S_IWUSR, \ -- cgit v1.2.3 From 6970cd446c25a4634f03c1adf0c12c010235bf3e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:02 -0800 Subject: mwifiex: display right transmit packet delay drv_pkt_delay_max should be assigned non-zero value, so that packet delay can be accumulate in the right way. Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/wmm.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 89a1576d0a4b..0433977c4e2f 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -298,6 +298,7 @@ struct mwifiex_tid_tbl { #define WMM_HIGHEST_PRIORITY 7 #define HIGH_PRIO_TID 7 #define LOW_PRIO_TID 0 +#define MWIFIEX_WMM_DRV_DELAY_MAX 510 struct mwifiex_wmm_desc { struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 499e5a741c62..0eb246502e1d 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -438,6 +438,7 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) mwifiex_set_ba_params(priv); mwifiex_reset_11n_rx_seq_num(priv); + priv->wmm.drv_pkt_delay_max = MWIFIEX_WMM_DRV_DELAY_MAX; atomic_set(&priv->wmm.tx_pkts_queued, 0); atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); } -- cgit v1.2.3 From af05148392f50490c662dccee6c502d9fcba33e2 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:03 -0800 Subject: mwifiex: process pcie io memory read failure case It is observed that ioread32 may fail to read pcie register in certain scenarios, this patch handles these cases. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 918e04954afe..b9fe1813cc4f 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -323,6 +323,8 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data) struct pcie_service_card *card = adapter->card; *data = ioread32(card->pci_mmap1 + reg); + if (*data == 0xffffffff) + return 0xffffffff; return 0; } -- cgit v1.2.3 From 0172404d79ec37e2c7d9dc90f6876dc314dc0fe5 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:04 -0800 Subject: mwifiex: skip firmware dump when read_regs() fails If we are not able to read registers or PCIe memory, it means PCIe device is in bad state. We will skip firmware dump in this case. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index b9fe1813cc4f..a18d944c2f31 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2366,9 +2366,13 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag) { int ret, tries; u8 ctrl_data; + u32 fw_status; struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) + return RDWR_STATUS_FAILURE; + ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY); if (ret) { mwifiex_dbg(adapter, ERROR, -- cgit v1.2.3 From 9a86232213b9498e0c0721fc508f760e7a089e59 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:05 -0800 Subject: mwifiex: keep original structure in decl header file memory_type_mapping strucuture did not refer to other mwifiex specific strture. A better software design method would keep it in decl header file, which does not include other mwifiex header file. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/decl.h | 21 +++++++++++++++++++++ drivers/net/wireless/marvell/mwifiex/main.h | 20 -------------------- drivers/net/wireless/marvell/mwifiex/pcie.h | 1 + 3 files changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index d9c15cd36f12..c744a7030866 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -270,4 +270,25 @@ struct mwifiex_11h_intf_state { bool is_11h_enabled; bool is_11h_active; } __packed; + +#define MWIFIEX_FW_DUMP_IDX 0xff +#define MWIFIEX_DRV_INFO_IDX 20 +#define FW_DUMP_MAX_NAME_LEN 8 +#define FW_DUMP_HOST_READY 0xEE +#define FW_DUMP_DONE 0xFF +#define FW_DUMP_READ_DONE 0xFE + +struct memory_type_mapping { + u8 mem_name[FW_DUMP_MAX_NAME_LEN]; + u8 *mem_ptr; + u32 mem_size; + u8 done_flag; +}; + +enum rdwr_status { + RDWR_STATUS_SUCCESS = 0, + RDWR_STATUS_FAILURE = 1, + RDWR_STATUS_DONE = 2 +}; + #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 0433977c4e2f..aea7aee46cf7 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -489,26 +489,6 @@ struct mwifiex_roc_cfg { struct ieee80211_channel chan; }; -#define MWIFIEX_FW_DUMP_IDX 0xff -#define MWIFIEX_DRV_INFO_IDX 20 -#define FW_DUMP_MAX_NAME_LEN 8 -#define FW_DUMP_HOST_READY 0xEE -#define FW_DUMP_DONE 0xFF -#define FW_DUMP_READ_DONE 0xFE - -struct memory_type_mapping { - u8 mem_name[FW_DUMP_MAX_NAME_LEN]; - u8 *mem_ptr; - u32 mem_size; - u8 done_flag; -}; - -enum rdwr_status { - RDWR_STATUS_SUCCESS = 0, - RDWR_STATUS_FAILURE = 1, - RDWR_STATUS_DONE = 2 -}; - enum mwifiex_iface_work_flags { MWIFIEX_IFACE_WORK_DEVICE_DUMP, MWIFIEX_IFACE_WORK_CARD_RESET, diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 9700ac355e55..8f190c44cb76 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -26,6 +26,7 @@ #include #include +#include "decl.h" #include "main.h" #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" -- cgit v1.2.3 From 50632092dfda712dec2232d6ddf75e803c397c70 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:06 -0800 Subject: mwifiex: use an extensible framework for firmware dump solution This patch apply an extensible firmware dump framework, so that other chipset can be easily added as needed. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 35 ++++++++++++----------------- drivers/net/wireless/marvell/mwifiex/pcie.h | 19 ++++++++++++++++ 2 files changed, 33 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index a18d944c2f31..c94d31e1b525 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -37,17 +37,6 @@ static struct mwifiex_if_ops pcie_ops; static struct semaphore add_remove_card_sem; -static struct memory_type_mapping mem_type_mapping_tbl[] = { - {"ITCM", NULL, 0, 0xF0}, - {"DTCM", NULL, 0, 0xF1}, - {"SQRAM", NULL, 0, 0xF2}, - {"IRAM", NULL, 0, 0xF3}, - {"APU", NULL, 0, 0xF4}, - {"CIU", NULL, 0, 0xF5}, - {"ICU", NULL, 0, 0xF6}, - {"MAC", NULL, 0, 0xF7}, -}; - static int mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, size_t size, int flags) @@ -206,6 +195,8 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->pcie.blksz_fw_dl = data->blksz_fw_dl; card->pcie.tx_buf_size = data->tx_buf_size; card->pcie.can_dump_fw = data->can_dump_fw; + card->pcie.mem_type_mapping_tbl = data->mem_type_mapping_tbl; + card->pcie.num_mem_types = data->num_mem_types; card->pcie.can_ext_scan = data->can_ext_scan; } @@ -2373,7 +2364,8 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag) if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) return RDWR_STATUS_FAILURE; - ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY); + ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, + reg->fw_dump_host_ready); if (ret) { mwifiex_dbg(adapter, ERROR, "PCIE write err\n"); @@ -2386,11 +2378,11 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag) return RDWR_STATUS_SUCCESS; if (doneflag && ctrl_data == doneflag) return RDWR_STATUS_DONE; - if (ctrl_data != FW_DUMP_HOST_READY) { + if (ctrl_data != reg->fw_dump_host_ready) { mwifiex_dbg(adapter, WARN, "The ctrl reg was changed, re-try again!\n"); ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, - FW_DUMP_HOST_READY); + reg->fw_dump_host_ready); if (ret) { mwifiex_dbg(adapter, ERROR, "PCIE write err\n"); @@ -2418,8 +2410,9 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) if (!card->pcie.can_dump_fw) return; - for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { - struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + for (idx = 0; idx < adapter->num_mem_types; idx++) { + struct memory_type_mapping *entry = + &adapter->mem_type_mapping_tbl[idx]; if (entry->mem_ptr) { vfree(entry->mem_ptr); @@ -2440,8 +2433,8 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) /* Read the length of every memory which will dump */ for (idx = 0; idx < dump_num; idx++) { - struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; - + struct memory_type_mapping *entry = + &adapter->mem_type_mapping_tbl[idx]; stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); if (stat == RDWR_STATUS_FAILURE) return; @@ -2457,7 +2450,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) if (memory_size == 0) { mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n"); ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl, - FW_DUMP_READ_DONE); + creg->fw_dump_read_done); if (ret) { mwifiex_dbg(adapter, ERROR, "PCIE write err\n"); return; @@ -2762,8 +2755,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) return -1; adapter->tx_buf_size = card->pcie.tx_buf_size; - adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; - adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); + adapter->mem_type_mapping_tbl = card->pcie.mem_type_mapping_tbl; + adapter->num_mem_types = card->pcie.num_mem_types; strcpy(adapter->fw_name, card->pcie.firmware); adapter->ext_scan = card->pcie.can_ext_scan; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 8f190c44cb76..8bc4390f0e20 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -136,6 +136,8 @@ struct mwifiex_pcie_card_reg { u16 fw_dump_ctrl; u16 fw_dump_start; u16 fw_dump_end; + u8 fw_dump_host_ready; + u8 fw_dump_read_done; u8 msix_support; }; @@ -203,6 +205,8 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { .fw_dump_ctrl = 0xcf4, .fw_dump_start = 0xcf8, .fw_dump_end = 0xcff, + .fw_dump_host_ready = 0xee, + .fw_dump_read_done = 0xfe, .msix_support = 0, }; @@ -238,12 +242,25 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .msix_support = 1, }; +static struct memory_type_mapping mem_type_mapping_tbl_w8897[] = { + {"ITCM", NULL, 0, 0xF0}, + {"DTCM", NULL, 0, 0xF1}, + {"SQRAM", NULL, 0, 0xF2}, + {"IRAM", NULL, 0, 0xF3}, + {"APU", NULL, 0, 0xF4}, + {"CIU", NULL, 0, 0xF5}, + {"ICU", NULL, 0, 0xF6}, + {"MAC", NULL, 0, 0xF7}, +}; + struct mwifiex_pcie_device { const char *firmware; const struct mwifiex_pcie_card_reg *reg; u16 blksz_fw_dl; u16 tx_buf_size; bool can_dump_fw; + struct memory_type_mapping *mem_type_mapping_tbl; + u8 num_mem_types; bool can_ext_scan; }; @@ -262,6 +279,8 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, .can_dump_fw = true, + .mem_type_mapping_tbl = mem_type_mapping_tbl_w8897, + .num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8897), .can_ext_scan = true, }; -- cgit v1.2.3 From 56486026c282983c390b264493a4619d997b86f1 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:07 -0800 Subject: mwifiex: dynamically increase preallocated firmware dump memory size This patch increase firmware dump memory 4K each time, until meet the demand. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/decl.h | 2 ++ drivers/net/wireless/marvell/mwifiex/pcie.c | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index c744a7030866..a184f9fdfbcb 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -122,6 +122,8 @@ #define BLOCK_NUMBER_OFFSET 15 #define SDIO_HEADER_OFFSET 28 +#define MWIFIEX_SIZE_4K 0x4000 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index c94d31e1b525..a62a09b028e5 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2402,7 +2402,8 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *creg = card->pcie.reg; unsigned int reg, reg_start, reg_end; - u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; + u8 *dbg_ptr, *end_ptr, *tmp_ptr, dump_num; + u8 idx, i, read_reg, doneflag = 0; enum rdwr_status stat; u32 memory_size; int ret; @@ -2485,11 +2486,21 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) mwifiex_read_reg_byte(adapter, reg, dbg_ptr); if (dbg_ptr < end_ptr) { dbg_ptr++; - } else { - mwifiex_dbg(adapter, ERROR, - "Allocated buf not enough\n"); - return; + continue; } + mwifiex_dbg(adapter, ERROR, + "pre-allocated buf not enough\n"); + tmp_ptr = + vzalloc(memory_size + MWIFIEX_SIZE_4K); + if (!tmp_ptr) + return; + memcpy(tmp_ptr, entry->mem_ptr, memory_size); + vfree(entry->mem_ptr); + entry->mem_ptr = tmp_ptr; + tmp_ptr = NULL; + dbg_ptr = entry->mem_ptr + memory_size; + memory_size += MWIFIEX_SIZE_4K; + end_ptr = entry->mem_ptr + memory_size; } if (stat != RDWR_STATUS_DONE) -- cgit v1.2.3 From 03f0f7cdebeb0872076817ff835ea812a62b37c6 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 2 Feb 2016 22:05:08 -0800 Subject: mwifiex: increase the priority of firmware dump message Firmware dump operation takes few seconds. Hence it's important to notify user in dmesg that firmware dump has started or completed. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index a62a09b028e5..14fe31671475 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2422,7 +2422,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) entry->mem_size = 0; } - mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump start ==\n"); + mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); /* Read the number of the memories which will dump */ stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); @@ -2512,7 +2512,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) break; } while (true); } - mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump end ==\n"); + mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); } static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter) -- cgit v1.2.3 From 11e70824e75f2cfbad9ae066ca5b29e1c361f19e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 2 Feb 2016 22:05:09 -0800 Subject: mwifiex: firmware dump support for w8997 chipset Current firmware dump solution support w8897 chipset, this patch extend the exist framework with support for w8997 chipset. Trigger firmware dump using, cat /sys/kernel/debug/mwifiex/mlan0/device_dump, data can be obtain by cat /sys/class/devcoredump/devcd*/data > data.txt after that. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/decl.h | 1 + drivers/net/wireless/marvell/mwifiex/pcie.c | 30 +++++++++++++++++++---------- drivers/net/wireless/marvell/mwifiex/pcie.h | 13 ++++++++++++- 3 files changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index a184f9fdfbcb..bec300b9c2ea 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -274,6 +274,7 @@ struct mwifiex_11h_intf_state { } __packed; #define MWIFIEX_FW_DUMP_IDX 0xff +#define MWIFIEX_FW_DUMP_MAX_MEMSIZE 0x160000 #define MWIFIEX_DRV_INFO_IDX 20 #define FW_DUMP_MAX_NAME_LEN 8 #define FW_DUMP_HOST_READY 0xEE diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 14fe31671475..cc072142411a 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2402,7 +2402,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *creg = card->pcie.reg; unsigned int reg, reg_start, reg_end; - u8 *dbg_ptr, *end_ptr, *tmp_ptr, dump_num; + u8 *dbg_ptr, *end_ptr, *tmp_ptr, fw_dump_num, dump_num; u8 idx, i, read_reg, doneflag = 0; enum rdwr_status stat; u32 memory_size; @@ -2430,22 +2430,32 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) return; reg = creg->fw_dump_start; - mwifiex_read_reg_byte(adapter, reg, &dump_num); + mwifiex_read_reg_byte(adapter, reg, &fw_dump_num); + + /* W8997 chipset firmware dump will be restore in single region*/ + if (fw_dump_num == 0) + dump_num = 1; + else + dump_num = fw_dump_num; /* Read the length of every memory which will dump */ for (idx = 0; idx < dump_num; idx++) { struct memory_type_mapping *entry = &adapter->mem_type_mapping_tbl[idx]; - stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); - if (stat == RDWR_STATUS_FAILURE) - return; - memory_size = 0; - reg = creg->fw_dump_start; - for (i = 0; i < 4; i++) { - mwifiex_read_reg_byte(adapter, reg, &read_reg); - memory_size |= (read_reg << (i * 8)); + if (fw_dump_num != 0) { + stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + return; + + reg = creg->fw_dump_start; + for (i = 0; i < 4; i++) { + mwifiex_read_reg_byte(adapter, reg, &read_reg); + memory_size |= (read_reg << (i * 8)); reg++; + } + } else { + memory_size = MWIFIEX_FW_DUMP_MAX_MEMSIZE; } if (memory_size == 0) { diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 8bc4390f0e20..29e58ce877e3 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -239,6 +239,11 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, + .fw_dump_ctrl = 0xcf4, + .fw_dump_start = 0xcf8, + .fw_dump_end = 0xcff, + .fw_dump_host_ready = 0xcc, + .fw_dump_read_done = 0xdd, .msix_support = 1, }; @@ -253,6 +258,10 @@ static struct memory_type_mapping mem_type_mapping_tbl_w8897[] = { {"MAC", NULL, 0, 0xF7}, }; +static struct memory_type_mapping mem_type_mapping_tbl_w8997[] = { + {"DUMP", NULL, 0, 0xDD}, +}; + struct mwifiex_pcie_device { const char *firmware; const struct mwifiex_pcie_card_reg *reg; @@ -289,7 +298,9 @@ static const struct mwifiex_pcie_device mwifiex_pcie8997 = { .reg = &mwifiex_reg_8997, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, - .can_dump_fw = false, + .can_dump_fw = true, + .mem_type_mapping_tbl = mem_type_mapping_tbl_w8997, + .num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8997), .can_ext_scan = true, }; -- cgit v1.2.3 From f06b7ab875037c3d99cd30a07c51caf34fbecb2c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jan 2016 14:21:01 +0100 Subject: mac80211_hwsim: remove shadowing variable The function here already has a variable hdr that even contains the right thing, so the inner scope's hdr variable that's shadowing the outer one can just be removed. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e31a94fd6135..ee37af1066d2 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1333,10 +1333,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, data->tx_bytes += skb->len; ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); - if (ack && skb->len >= 16) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (ack && skb->len >= 16) mac80211_hwsim_monitor_ack(channel, hdr->addr2); - } ieee80211_tx_info_clear_status(txi); -- cgit v1.2.3 From 34d505193bd10668acf1caba02d2f66bddc23fea Mon Sep 17 00:00:00 2001 From: Lior David Date: Thu, 28 Jan 2016 10:58:25 +0200 Subject: cfg80211: basic support for PBSS network type PBSS (Personal Basic Service Set) is a new BSS type for DMG networks. It is similar to infrastructure BSS, having an AP-like entity called PCP (PBSS Control Point), but it has few differences. PBSS support is mandatory for 11ad devices. Add support for PBSS by introducing a new PBSS flag attribute. The PBSS flag is used in the START_AP command to request starting a PCP instead of an AP, and in the CONNECT command to request connecting to a PCP instead of an AP. Signed-off-by: Lior David Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/wil6210/cfg80211.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 20d07ef679e8..1f231cd08138 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -422,6 +422,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, if (sme->privacy && !rsn_eid) wil_info(wil, "WSC connection\n"); + if (sme->pbss) { + wil_err(wil, "connect - PBSS not yet supported\n"); + return -EOPNOTSUPP; + } + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); @@ -870,6 +875,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } + if (info->pbss) { + wil_err(wil, "AP: PBSS not yet supported\n"); + return -EOPNOTSUPP; + } + switch (info->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: hidden_ssid = WMI_HIDDEN_SSID_DISABLED; -- cgit v1.2.3 From 1ad4f639cc3e09d6c8402a0fcc592e2391683e31 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Feb 2016 13:56:36 +0200 Subject: iwlwifi: mvm: move TX PN assignment for TKIP to the driver If protocol offloading is configured, the fw might generate some frames (e.g. arp response) on its own during d3/d0i3. On d3/d0i3 exit the driver queries the updated PN (if relevant), and updates its keys (for the d0i3 case, this is done by iwl_mvm_d0i3_exit_work(), which is scheduled on d0i3 exit) While in d0i3, iwlmvm defers tx frames until d0i3 exit, and then continues their processing. This is problematic with TKIP, since the frame's PN has already been set at this stage (in contrast to CCMP, where the PN is being set only later on), so both the frame's PN and the upcoming PN update (from d0i3 exit work) might be wrong. Fix it by moving the TX PN assignment (for TKIP) to the driver, similarly to CCMP. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 15 ++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 ++ 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d3e21d95cece..93e495861214 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -249,16 +249,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, return; case WLAN_CIPHER_SUITE_TKIP: if (sta) { + u64 pn64; + tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc; tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc; rx_p1ks = data->tkip->rx_uni; - ieee80211_get_key_tx_seq(key, &seq); - tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16); - tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32); + pn64 = atomic64_read(&key->tx_pn); + tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64)); + tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64)); - ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k); + ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64), + p1k); iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k); memcpy(data->tkip->mic_keys.tx, @@ -1601,7 +1604,9 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_TKIP: iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq); iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key); - ieee80211_set_key_tx_seq(key, &seq); + atomic64_set(&key->tx_pn, + (u64)seq.tkip.iv16 | + ((u64)seq.tkip.iv32 << 16)); break; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 1bd3f0b700d3..2b532925781a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2585,7 +2585,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; break; case WLAN_CIPHER_SUITE_CCMP: key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8bf48a7d0f4e..ca1e485a6adc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -299,6 +299,8 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_TKIP: tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; + pn = atomic64_inc_return(&keyconf->tx_pn); + ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn); ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); break; -- cgit v1.2.3 From ca48ebbc7ea7e82e3ae4b55aacead0cdb54ff008 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 15 Feb 2016 12:34:10 +0200 Subject: mac80211: remove ieee80211_get_key_tx_seq/ieee80211_set_key_tx_seq Since the PNs of all the tx keys are now tracked in the public part of the key struct (with atomic counter), we no longer need these functions. dvm and vt665{5,6} are currently the only users of these functions, so update them accordingly. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/dvm/lib.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 4841be2aa499..1799469268ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -943,14 +943,16 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: if (sta) { + u64 pn64; + tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc; tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc; rx_p1ks = data->tkip->rx_uni; - ieee80211_get_key_tx_seq(key, &seq); - tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16); - tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32); + pn64 = atomic64_read(&key->tx_pn); + tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64)); + tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64)); ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k); iwlagn_convert_p1k(p1k, data->tkip->tx.p1k); @@ -996,19 +998,13 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, break; case WLAN_CIPHER_SUITE_CCMP: if (sta) { - u8 *pn = seq.ccmp.pn; + u64 pn64; aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc; aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc; - ieee80211_get_key_tx_seq(key, &seq); - aes_tx_sc->pn = cpu_to_le64( - (u64)pn[5] | - ((u64)pn[4] << 8) | - ((u64)pn[3] << 16) | - ((u64)pn[2] << 24) | - ((u64)pn[1] << 32) | - ((u64)pn[0] << 40)); + pn64 = atomic64_read(&key->tx_pn); + aes_tx_sc->pn = cpu_to_le64(pn64); } else aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc; -- cgit v1.2.3 From 43154f6fd46bb3bcd363843c9e48f0b8b3a03a08 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:35 -0500 Subject: rtl8xxxu: Minor cleanup to rtl8xxxu_download_firmware() Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 6aed923a709a..6b39e4d0abfb 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2100,7 +2100,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) /* 8051 enable */ val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); - rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE); + val16 |= SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); /* MCU firmware download enable */ val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); -- cgit v1.2.3 From ef1c0499316b892d700201edeeb013b60be96877 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:36 -0500 Subject: rtl8xxxu: rtl8xxxu_download_firmware(): Cosmetic cleanups Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 6b39e4d0abfb..b6a264bc4463 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2105,15 +2105,18 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) /* MCU firmware download enable */ val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); - rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE); + val8 |= MCU_FW_DL_ENABLE; + rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8); /* 8051 reset */ val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL); - rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19)); + val32 &= ~BIT(19); + rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32); /* Reset firmware download checksum */ val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); - rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT); + val8 |= MCU_FW_DL_CSUM_REPORT; + rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8); pages = priv->fw_size / RTL_FW_PAGE_SIZE; remainder = priv->fw_size % RTL_FW_PAGE_SIZE; @@ -2122,7 +2125,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) for (i = 0; i < pages; i++) { val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8; - rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i); + val8 |= i; + rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8); ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS, fwptr, RTL_FW_PAGE_SIZE); @@ -2136,7 +2140,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) if (remainder) { val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8; - rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i); + val8 |= i; + rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8); ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS, fwptr, remainder); if (ret != remainder) { @@ -2149,8 +2154,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) fw_abort: /* MCU firmware download disable */ val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL); - rtl8xxxu_write16(priv, REG_MCU_FW_DL, - val16 & (~MCU_FW_DL_ENABLE & 0xff)); + val16 &= ~MCU_FW_DL_ENABLE; + rtl8xxxu_write16(priv, REG_MCU_FW_DL, val16); return ret; } -- cgit v1.2.3 From 216202ae20ea93585630e6a88486ea23200199cc Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:37 -0500 Subject: rtl8xxxu: If fw running in RAM, reset the 8051 before trying to download a new one Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index b6a264bc4463..e98e0535c14f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2089,7 +2089,7 @@ exit: static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) { int pages, remainder, i, ret; - u8 val8; + u8 val8, sys_func; u16 val16; u32 val32; u8 *fwptr; @@ -2103,6 +2103,23 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) val16 |= SYS_FUNC_CPU_ENABLE; rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); + if (val8 & MCU_FW_RAM_SEL) { + pr_info("do the RAM reset\n"); + rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 &= ~BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + sys_func = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1); + sys_func &= ~BIT(2); + rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, sys_func); + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 |= BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + sys_func |= BIT(2); + rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, sys_func); + } + /* MCU firmware download enable */ val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); val8 |= MCU_FW_DL_ENABLE; -- cgit v1.2.3 From 0635f8cede159bb2205021583a483b0cd3246c74 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:38 -0500 Subject: rtl8xxxu: Add RQPN_[NE]PQ_SHIFT values Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 23208f79b97c..8b27a1c763fd 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -352,6 +352,8 @@ #define REG_TXDMA_OFFSET_CHK 0x020c #define REG_TXDMA_STATUS 0x0210 #define REG_RQPN_NPQ 0x0214 +#define RQPN_NPQ_SHIFT 0 +#define RQPN_EPQ_SHIFT 16 /* 0x0280 ~ 0x02FF RXDMA Configuration */ #define REG_RXDMA_AGG_PG_TH 0x0280 -- cgit v1.2.3 From f076977537d9b6ac5d067d416b549aedd591da4f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:39 -0500 Subject: rtl8xxxu: Define SYS_CFG_SW_OFFLOAD_EN This is needed for chips with IOL support. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 8b27a1c763fd..7c795ce61aaa 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -213,6 +213,7 @@ #define SYS_CFG_PCIRSTB BIT(4) #define SYS_CFG_V15_VLD BIT(5) #define SYS_CFG_TRP_B15V_EN BIT(7) +#define SYS_CFG_SW_OFFLOAD_EN BIT(7) /* For chips with IOL support */ #define SYS_CFG_SIC_IDLE BIT(8) #define SYS_CFG_BD_MAC2 BIT(9) #define SYS_CFG_BD_MAC1 BIT(10) -- cgit v1.2.3 From cecfd3cb29f8f39b8859c3c189185df23b69e45c Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:40 -0500 Subject: rtl8xxxu: Add REG_TX_REPORT_* defines Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 7c795ce61aaa..89547b68a98b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -456,6 +456,8 @@ #define REG_NEED_CPU_HANDLE 0x04e0 #define REG_PKT_LOSE_RPT 0x04e1 #define REG_PTCL_ERR_STATUS 0x04e2 +#define REG_TX_REPORT_CTRL 0x04ec +#define REG_TX_REPORT_TIME 0x04f0 #define REG_DUMMY 0x04fc /* 0x0500 ~ 0x05FF EDCA Configuration */ -- cgit v1.2.3 From 22229fcb487a161561cfcb08e6a4028d6343b2e7 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:41 -0500 Subject: rtl8xxxu: Add more RCR bits Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 89547b68a98b..f7526027db53 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -568,9 +568,18 @@ #define RCR_ACCEPT_CTRL_FRAME BIT(12) #define RCR_ACCEPT_MGMT_FRAME BIT(13) #define RCR_HTC_LOC_CTRL BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */ +#define RCR_UC_DATA_PKT_INT_ENABLE BIT(16) /* Enable unicast data packet + interrupt */ +#define RCR_BM_DATA_PKT_INT_ENABLE BIT(17) /* Enable broadcast data packet + interrupt */ +#define RCR_TIM_PARSER_ENABLE BIT(18) /* Enable RX beacon TIM parser*/ #define RCR_MFBEN BIT(22) -#define RCR_LSIGEN BIT(23) +#define RCR_LSIG_ENABLE BIT(23) /* Enable LSIG TXOP Protection + function. Search KEYCAM for + each rx packet to check if + LSIGEN bit is set. */ #define RCR_MULTI_BSSID_ENABLE BIT(24) /* Enable Multiple BssId */ +#define RCR_FORCE_ACK BIT(26) #define RCR_ACCEPT_BA_SSN BIT(27) /* Accept BA SSN */ #define RCR_APPEND_PHYSTAT BIT(28) #define RCR_APPEND_ICV BIT(29) -- cgit v1.2.3 From c1edece3c22be23cee3b28f74aecd1736ee816a1 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 3 Feb 2016 13:39:42 -0500 Subject: rtl8xxxu: Fix typo in Kconfig help text Fix spelling of "benefits". Signed-off-by: Tobias Klauser Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig index dd4d626aecbc..8f053c350227 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig +++ b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig @@ -13,7 +13,7 @@ config RTL8XXXU This driver is under development and has a limited feature set. In particular it does not yet support 40MHz channels and power management. However it should have a smaller - memory footprint than the vendor drivers and benetifs + memory footprint than the vendor drivers and benefits from the in kernel mac80211 stack. It can coexist with drivers from drivers/staging/rtl8723au, -- cgit v1.2.3 From 98e27cbd9453cd99403ee5f929a11a1000a3090b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 3 Feb 2016 13:39:43 -0500 Subject: rtl8xxxu: Check return value of kmemdup() In rtl8xxxu_load_firmware() check the return value of kmemdup() and error out with -ENOMEM in case of NULL to prevent a NULL pointer dereference. Signed-off-by: Tobias Klauser Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e98e0535c14f..08d8e1fa44f0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2197,6 +2197,10 @@ static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) } priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL); + if (!priv->fw_data) { + ret = -ENOMEM; + goto exit; + } priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header); signature = le16_to_cpu(priv->fw_data->signature); -- cgit v1.2.3 From d48fe60e06f404acf1acb346a4bf2d7b0e1d4d86 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:44 -0500 Subject: rtl8xxxu: Implement rtl8xxxu_reset_8051() We need to reset the 8051 in order for it to launch the fw on the rtl8192eu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 38 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 08d8e1fa44f0..7a571efbdc1c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2043,6 +2043,24 @@ exit: return ret; } +static void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 sys_func; + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 &= ~BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); + sys_func &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 |= BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + sys_func |= SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); +} + static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv) { struct device *dev = &priv->udev->dev; @@ -2067,6 +2085,12 @@ static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv) val32 &= ~MCU_WINT_INIT_READY; rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32); + /* + * Reset the 8051 in order for the firmware to start running, + * otherwise it won't come up on the 8192eu + */ + rtl8xxxu_reset_8051(priv); + /* Wait for firmware to become ready */ for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) { val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL); @@ -2089,7 +2113,7 @@ exit: static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) { int pages, remainder, i, ret; - u8 val8, sys_func; + u8 val8; u16 val16; u32 val32; u8 *fwptr; @@ -2107,17 +2131,7 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) if (val8 & MCU_FW_RAM_SEL) { pr_info("do the RAM reset\n"); rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); - val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); - val8 &= ~BIT(3); - rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); - sys_func = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1); - sys_func &= ~BIT(2); - rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, sys_func); - val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); - val8 |= BIT(3); - rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); - sys_func |= BIT(2); - rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, sys_func); + rtl8xxxu_reset_8051(priv); } /* MCU firmware download enable */ -- cgit v1.2.3 From af9e4d6d9d07857b5fb7711832e8cda745e336ae Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:45 -0500 Subject: rtl8xxxu: Add definitions for antenna selection registers for 8723BU Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index f7526027db53..997a85792f48 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -756,6 +756,10 @@ #define REG_FPGA1_RF_MODE 0x0900 #define REG_FPGA1_TX_INFO 0x090c +#define REG_DPDT_CTRL 0x092c /* 8723BU */ +#define REG_RFE_CTRL_ANTA_SRC 0x0930 /* 8723BU */ +#define REG_RFE_PATH_SELECT 0x0940 /* 8723BU */ +#define REG_RFE_BUFFER 0x0944 /* 8723BU */ #define REG_CCK0_SYSTEM 0x0a00 #define CCK0_SIDEBAND BIT(4) -- cgit v1.2.3 From 29c2139cd04ad23226c690221450b93bedaceea4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:46 -0500 Subject: rtl8xxxu: Add mbox extension register definitions for 8723B Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 997a85792f48..991b3664bd7e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -341,6 +341,11 @@ #define REG_BB_ACCEESS_CTRL 0x01e8 #define REG_BB_ACCESS_DATA 0x01ec +#define REG_HMBOX_EXT0_8723B 0x01f0 +#define REG_HMBOX_EXT1_8723B 0x01f4 +#define REG_HMBOX_EXT2_8723B 0x01f8 +#define REG_HMBOX_EXT3_8723B 0x01fc + /* 0x0200 ~ 0x027F TXDMA Configuration */ #define REG_RQPN 0x0200 #define RQPN_HI_PQ_SHIFT 0 -- cgit v1.2.3 From ce6f2e3669547ad18ea67761aa9cc32cb4407bf2 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:47 -0500 Subject: rtl8xxxu: Add REG_OFDM0_RX_D_SYNC_PATH definitions Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 991b3664bd7e..d2995f8a3311 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -793,6 +793,9 @@ #define REG_OFDM0_ENERGY_CCA_THRES 0x0c4c +#define REG_OFDM0_RX_D_SYNC_PATH 0x0c40 +#define OFDM0_SYNC_PATH_NOTCH_FILTER BIT(1) + #define REG_OFDM0_XA_AGC_CORE1 0x0c50 #define REG_OFDM0_XA_AGC_CORE2 0x0c54 #define REG_OFDM0_XB_AGC_CORE1 0x0c58 -- cgit v1.2.3 From e5c447ccf8e568134847bb491663e26910a21d8a Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:48 -0500 Subject: rtl8xxxu: Remove unused clutter for handling recursive calls to rtl8xxxu_init_device() This was a leftover from the vendor driver that was never utilized. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 12 +----------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 7a571efbdc1c..4a6939f1454f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4289,17 +4289,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); - /* - * Not sure if we should get into this at all - */ - if (priv->iqk_initialized) { - rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg, - priv->bb_recovery_backup, - RTL8XXXU_BB_REGS); - } else { - rtl8723a_phy_iq_calibrate(priv); - priv->iqk_initialized = true; - } + rtl8723a_phy_iq_calibrate(priv); /* * This should enable thermal meter diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index f2a1bac6c8ec..f71fb8dd951c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -652,7 +652,6 @@ struct rtl8xxxu_priv { u32 bb_recovery_backup[RTL8XXXU_BB_REGS]; u32 rtlchip; u8 pi_enabled:1; - u8 iqk_initialized:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; }; -- cgit v1.2.3 From 38451998fb8a5f9c933b2c462a790d5633605ac8 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 3 Feb 2016 13:39:49 -0500 Subject: rtl8xxxu: Use REG_EFUSE_TEST register only on multifunctional devices rtl8192cu driver doesn't read/write the REG_EFUSE_TEST register. Neither does the rtl8188eu driver. Do it only for multifunc devices RTL8723AU/RTL8723BU. Signed-off-by: Jakub Sitnicki Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 9 ++++++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4a6939f1454f..94d3d845d36e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1704,6 +1704,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->has_bluetooth = 1; if (val32 & MULTI_GPS_FUNC_EN) priv->has_gps = 1; + priv->is_multi_func = 1; } else if (val32 & SYS_CFG_TYPE_ID) { bonding = rtl8xxxu_read32(priv, REG_HPON_FSM); bonding &= HPON_FSM_BONDING_MASK; @@ -1938,9 +1939,11 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) if (val16 & EEPROM_BOOT) priv->boot_eeprom = 1; - val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST); - val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT; - rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32); + if (priv->is_multi_func) { + val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST); + val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT; + rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32); + } dev_dbg(dev, "Booting from %s\n", priv->boot_eeprom ? "EEPROM" : "EFUSE"); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index f71fb8dd951c..bbd0f6b76b82 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -597,6 +597,7 @@ struct rtl8xxxu_priv { struct rtl8723au_idx ht20_max_power_offset[3]; u32 chip_cut:4; u32 rom_rev:4; + u32 is_multi_func:1; u32 has_wifi:1; u32 has_bluetooth:1; u32 enable_bluetooth:1; -- cgit v1.2.3 From 56e4374a5e08b6971069de4bb0824c2aa2149a8f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:50 -0500 Subject: rtl8xxxu: Fix cosmetics to quiet down checkpatch police Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 94d3d845d36e..ac4c211184df 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4415,7 +4415,7 @@ static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv, } static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, const u8* mac) + struct ieee80211_vif *vif, const u8 *mac) { struct rtl8xxxu_priv *priv = hw->priv; u8 val8; -- cgit v1.2.3 From 3bed4bfa51f2635ff21c73f83503e3e8ac233db2 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 3 Feb 2016 13:39:51 -0500 Subject: rtl8xxxu: Enable monitor mode by handling filters Monitor mode is enabled by handling the filter flags we get from mac80211 in rtl8xxxu_configure_filter() and writing them to the RCR register. By handling the filters, we can also stop setting the BSSID filters in the association event. Signed-off-by: Bruno Randolf Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 56 +++++++++++++++++++----- 1 file changed, 45 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ac4c211184df..b58a60f8ceb1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4199,7 +4199,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * Configure initial WMAC settings */ val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST | - /* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */ RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL | RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC; rtl8xxxu_write32(priv, REG_RCR, val32); @@ -4522,10 +4521,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_update_rate_mask(priv, ramask, sgi); - val32 = rtl8xxxu_read32(priv, REG_RCR); - val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON; - rtl8xxxu_write32(priv, REG_RCR, val32); - /* Enable RX of data frames */ rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff); @@ -4539,11 +4534,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, h2c.joinbss.data = H2C_JOIN_BSS_CONNECT; } else { - val32 = rtl8xxxu_read32(priv, REG_RCR); - val32 &= ~(RCR_CHECK_BSSID_MATCH | - RCR_CHECK_BSSID_BEACON); - rtl8xxxu_write32(priv, REG_RCR, val32); - val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); val8 |= BEACON_DISABLE_TSF_UPDATE; rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); @@ -5318,11 +5308,55 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { struct rtl8xxxu_priv *priv = hw->priv; + u32 rcr = rtl8xxxu_read32(priv, REG_RCR); dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n", __func__, changed_flags, *total_flags); - *total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC); + /* + * FIF_ALLMULTI ignored as all multicast frames are accepted (REG_MAR) + */ + + if (*total_flags & FIF_FCSFAIL) + rcr |= RCR_ACCEPT_CRC32; + else + rcr &= ~RCR_ACCEPT_CRC32; + + /* + * FIF_PLCPFAIL not supported? + */ + + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + rcr &= ~RCR_CHECK_BSSID_BEACON; + else + rcr |= RCR_CHECK_BSSID_BEACON; + + if (*total_flags & FIF_CONTROL) + rcr |= RCR_ACCEPT_CTRL_FRAME; + else + rcr &= ~RCR_ACCEPT_CTRL_FRAME; + + if (*total_flags & FIF_OTHER_BSS) { + rcr |= RCR_ACCEPT_AP; + rcr &= ~RCR_CHECK_BSSID_MATCH; + } else { + rcr &= ~RCR_ACCEPT_AP; + rcr |= RCR_CHECK_BSSID_MATCH; + } + + if (*total_flags & FIF_PSPOLL) + rcr |= RCR_ACCEPT_PM; + else + rcr &= ~RCR_ACCEPT_PM; + + /* + * FIF_PROBE_REQ ignored as probe requests always seem to be accepted + */ + + rtl8xxxu_write32(priv, REG_RCR, rcr); + + *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | FIF_OTHER_BSS | FIF_PSPOLL | FIF_PROBE_REQ); } static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) -- cgit v1.2.3 From b40027ba8db1b2fe022bf42505cbf64cb0114eba Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 3 Feb 2016 13:39:52 -0500 Subject: rtl8xxxu: Document REG_RXFLTMAP registers Add comments describing how REG_RXFLTMAP0, REG_RXFLTMAP1 and REG_RXFLTMAP2 work. Signed-off-by: Bruno Randolf Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index d2995f8a3311..d089eddc920e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -569,9 +569,12 @@ (Rx beacon, probe rsp) */ #define RCR_ACCEPT_CRC32 BIT(8) /* Accept CRC32 error packet */ #define RCR_ACCEPT_ICV BIT(9) /* Accept ICV error packet */ -#define RCR_ACCEPT_DATA_FRAME BIT(11) -#define RCR_ACCEPT_CTRL_FRAME BIT(12) -#define RCR_ACCEPT_MGMT_FRAME BIT(13) +#define RCR_ACCEPT_DATA_FRAME BIT(11) /* Accept all data pkt or use + REG_RXFLTMAP2 */ +#define RCR_ACCEPT_CTRL_FRAME BIT(12) /* Accept all control pkt or use + REG_RXFLTMAP1 */ +#define RCR_ACCEPT_MGMT_FRAME BIT(13) /* Accept all mgmt pkt or use + REG_RXFLTMAP0 */ #define RCR_HTC_LOC_CTRL BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */ #define RCR_UC_DATA_PKT_INT_ENABLE BIT(16) /* Enable unicast data packet interrupt */ @@ -651,9 +654,20 @@ #define REG_LPNAV_CTRL 0x0694 #define REG_WKFMCAM_CMD 0x0698 #define REG_WKFMCAM_RWD 0x069c -#define REG_RXFLTMAP0 0x06a0 -#define REG_RXFLTMAP1 0x06a2 -#define REG_RXFLTMAP2 0x06a4 + +/* + * RX Filters: each bit corresponds to the numerical value of the subtype. + * If it is set the subtype frame type is passed. The filter is only used when + * the RCR_ACCEPT_DATA_FRAME, RCR_ACCEPT_CTRL_FRAME, RCR_ACCEPT_MGMT_FRAME bit + * in the RCR are low. + * + * Example: Beacon subtype is binary 1000 which is decimal 8 so we have to set + * bit 8 (0x100) in REG_RXFLTMAP0 to enable reception. + */ +#define REG_RXFLTMAP0 0x06a0 /* Management frames */ +#define REG_RXFLTMAP1 0x06a2 /* Control frames */ +#define REG_RXFLTMAP2 0x06a4 /* Data frames */ + #define REG_BCN_PSR_RPT 0x06a8 #define REG_CALB32K_CTRL 0x06ac #define REG_PKT_MON_CTRL 0x06b4 -- cgit v1.2.3 From 124bc63c995d32b647560ca1951006f5954a53bb Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:53 -0500 Subject: rtl8xxxu: Remove duplicate USB ID Reported-by: Xose Vazquez Perez Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index b58a60f8ceb1..78683b56ae2c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5959,8 +5959,6 @@ static struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, -{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff), - .driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */ {USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff), -- cgit v1.2.3 From 755bda116e8a724f0e6b6514fbeb6d761b091b1e Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:54 -0500 Subject: rtl8xxxu: Fix 80 character per line issue Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 78683b56ae2c..9f89f62a9f0a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5355,8 +5355,9 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, rtl8xxxu_write32(priv, REG_RCR, rcr); - *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | FIF_OTHER_BSS | FIF_PSPOLL | FIF_PROBE_REQ); + *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_BCN_PRBRESP_PROMISC | + FIF_CONTROL | FIF_OTHER_BSS | FIF_PSPOLL | + FIF_PROBE_REQ); } static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) -- cgit v1.2.3 From c85ea1156d787ef52bbb835bcf2d5117d16282e1 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 3 Feb 2016 13:39:55 -0500 Subject: rtl8xxxu: Enable data frame reception in rtl8xxxu_start mac80211 documentation says, the ieee80211_ops.start callback "must turn on frame reception (for possibly enabled monitor interfaces.)". If not a single monitor interface does not receive data frames. Similarly we should not change the data reception based on the association state. Signed-off-by: Bruno Randolf Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 9f89f62a9f0a..1b7ff74fe9b3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4521,9 +4521,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_update_rate_mask(priv, ramask, sgi); - /* Enable RX of data frames */ - rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff); - rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); rtl8723a_stop_tx_beacon(priv); @@ -4538,8 +4535,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, val8 |= BEACON_DISABLE_TSF_UPDATE; rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); - /* Disable RX of data frames */ - rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000); h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT; } h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT; @@ -5542,12 +5537,9 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) } exit: /* - * Disable all data frames - */ - rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000); - /* - * Accept all mgmt frames + * Accept all data and mgmt frames */ + rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff); rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff); rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e); -- cgit v1.2.3 From a26703f39d2fe8f06ca2327d1a3f011d85b56c7f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:56 -0500 Subject: rtl8xxxu: rtl8xxxu_set_linktype(): Be consistent aboutregister size REG_MSR Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 1b7ff74fe9b3..c8ba698badfe 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1599,9 +1599,9 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, enum nl80211_iftype linktype) { - u16 val8; + u8 val8; - val8 = rtl8xxxu_read16(priv, REG_MSR); + val8 = rtl8xxxu_read8(priv, REG_MSR); val8 &= ~MSR_LINKTYPE_MASK; switch (linktype) { -- cgit v1.2.3 From 53b381c4d72a58ca7df75074d75df9355b77fc99 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:57 -0500 Subject: rtl8xxxu: Set correct bit to reset MCU IO wrapper All chips, except for 8812 require BIT(0) for resetting the MCU IO wrapper. 8723b requires a more complicated reset sequence, so it will need a custom reset function. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index c8ba698badfe..460145cca205 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2052,13 +2052,13 @@ static void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv) u16 sys_func; val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); - val8 &= ~BIT(3); + val8 &= ~BIT(0); rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); sys_func &= ~SYS_FUNC_CPU_ENABLE; rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); - val8 |= BIT(3); + val8 |= BIT(0); rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); sys_func |= SYS_FUNC_CPU_ENABLE; rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); -- cgit v1.2.3 From 796c554257b1a8a61b1112ac03bbbf3221c5a65f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:58 -0500 Subject: rtl8xxxu: Remove unused mgmt variable from rtl8xxxu_rx_complete() Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 460145cca205..12018362f2b1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5031,7 +5031,6 @@ static void rtl8xxxu_rx_complete(struct urb *urb) struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data; struct rtl8723au_phy_stats *phy_stats; struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_mgmt *mgmt; struct device *dev = &priv->udev->dev; __le32 *_rx_desc_le = (__le32 *)skb->data; u32 *_rx_desc = (u32 *)skb->data; @@ -5052,8 +5051,6 @@ static void rtl8xxxu_rx_complete(struct urb *urb) skb_pull(skb, drvinfo_sz + desc_shift); - mgmt = (struct ieee80211_mgmt *)skb->data; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); if (rx_desc->phy_stats) -- cgit v1.2.3 From a9ffa615aa4c661ce905f73f1b2d43e17ee55194 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:39:59 -0500 Subject: rtl8xxxu: Remove unused len/cnt variables from rtl8xxxu_rx_complete() Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 12018362f2b1..a6c8dabc87ba 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5034,13 +5034,11 @@ static void rtl8xxxu_rx_complete(struct urb *urb) struct device *dev = &priv->udev->dev; __le32 *_rx_desc_le = (__le32 *)skb->data; u32 *_rx_desc = (u32 *)skb->data; - int cnt, len, drvinfo_sz, desc_shift, i; + int drvinfo_sz, desc_shift, i; for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++) _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); - cnt = rx_desc->frag; - len = rx_desc->pktlen; drvinfo_sz = rx_desc->drvinfo_sz * 8; desc_shift = rx_desc->shift; skb_put(skb, urb->actual_length); -- cgit v1.2.3 From dc254ca41134d9bbc6227d133ef5e220f14529b5 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:40:00 -0500 Subject: rtl8xxxu: Do not mask RF registers to 6 bits Newer chips have RF registers beyond the original 0x3f address. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index a6c8dabc87ba..af17ae7e6cdd 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2536,8 +2536,6 @@ static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv, continue; } - reg &= 0x3f; - ret = rtl8xxxu_write_rfreg(priv, path, reg, val); if (ret) { dev_warn(&priv->udev->dev, -- cgit v1.2.3 From 4042e61735ce79c227a67a893d5738f297a96b9c Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:40:01 -0500 Subject: rtl8xxxu: Make device_init kludge 8723au only Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index af17ae7e6cdd..fdeae3bada4d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4343,14 +4343,17 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT); rtl8xxxu_write8(priv, REG_NAV_UPPER, val8); - /* - * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test, - * but we need to fin root cause. - */ - val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); - if ((val32 & 0xff000000) != 0x83000000) { - val32 |= FPGA_RF_MODE_CCK; - rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + if (priv->rtlchip == 0x8723a) { + /* + * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test, + * but we need to find root cause. + * This is 8723au only. + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + if ((val32 & 0xff000000) != 0x83000000) { + val32 |= FPGA_RF_MODE_CCK; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + } } val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL); -- cgit v1.2.3 From 5b22a111aa15bb8a010a0bec1da6a4b6690dd561 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 3 Feb 2016 13:40:02 -0500 Subject: rtl8xxxu: Add missing bit define for REG_APS_FSMCO Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index d089eddc920e..8f6c9c6c7c09 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -45,6 +45,7 @@ #define APS_FSMCO_ENABLE_POWERDOWN BIT(4) #define APS_FSMCO_MAC_ENABLE BIT(8) #define APS_FSMCO_MAC_OFF BIT(9) +#define APS_FSMCO_SW_LPS BIT(10) #define APS_FSMCO_HW_SUSPEND BIT(11) #define APS_FSMCO_PCIE BIT(12) #define APS_FSMCO_HW_POWERDOWN BIT(15) -- cgit v1.2.3 From 19c8f421a61947116898c9f8a28823b9d988df74 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Mon, 8 Feb 2016 00:00:30 +0100 Subject: brcmfmac: Increase nr of supported flowrings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New generation devices have firmware which has more than 256 flowrings. E.g. following debugging message comes from 14e4:4365 BCM4366: [ 194.606245] brcmfmac: brcmf_pcie_init_ringbuffers Nr of flowrings is 264 At various code places (related to flowrings) we were using u8 which could lead to storing wrong number or infinite loops when indexing with this type. This issue was quite easy to spot in brcmf_flowring_detach where it led to infinite loop e.g. on failed initialization. This patch switches code to proper types and increases the maximum number of supported flowrings to 512. Originally this change was sent in September 2015, but back it was causing a regression on BCM43602 resulting in: Unable to handle kernel NULL pointer dereference at virtual address ... The reason for this regression was missing update (s/u8/u16) of struct brcmf_flowring_ring. This problem was handled in 9f64df9 ("brcmfmac: Fix bug in flowring management."). Starting with that it's safe to apply this original patch as it doesn't cause a regression anymore. This patch fixes an infinite loop on BCM4366 which is supported since 4.4 so it makes sense to apply it to stable 4.4+. Cc: # 4.4+ Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/flowring.c | 38 ++++++++++++---------- .../broadcom/brcm80211/brcmfmac/flowring.h | 20 ++++++------ .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 11 +++++-- .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.h | 2 +- 4 files changed, 41 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c index 2ca783fa50cf..7e269f9aa607 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c @@ -32,7 +32,7 @@ #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256) #define BRCMF_FLOWRING_INVALID_IFIDX 0xff -#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) +#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16) #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) static const u8 brcmf_flowring_prio2fifo[] = { @@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], u8 prio, u8 ifidx) { struct brcmf_flowring_hash *hash; - u8 hash_idx; + u16 hash_idx; u32 i; bool found; bool sta; @@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], } hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); + hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); found = false; hash = flow->hash; for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { @@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], break; } hash_idx++; + hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); } if (found) return hash[hash_idx].flowid; @@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], { struct brcmf_flowring_ring *ring; struct brcmf_flowring_hash *hash; - u8 hash_idx; + u16 hash_idx; u32 i; bool found; u8 fifo; @@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], } hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); + hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); found = false; hash = flow->hash; for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { @@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], break; } hash_idx++; + hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); } if (found) { for (i = 0; i < flow->nrofrings; i++) { @@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], } -u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) +u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid) { struct brcmf_flowring_ring *ring; @@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) } -static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, +static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid, bool blocked) { struct brcmf_flowring_ring *ring; @@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, } -void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) +void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid) { struct brcmf_flowring_ring *ring; - u8 hash_idx; + u16 hash_idx; struct sk_buff *skb; ring = flow->rings[flowid]; @@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) } -u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, +u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, struct sk_buff *skb) { struct brcmf_flowring_ring *ring; @@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, } -struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) +struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid) { struct brcmf_flowring_ring *ring; struct sk_buff *skb; @@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) } -void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, +void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, struct sk_buff *skb) { struct brcmf_flowring_ring *ring; @@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, } -u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid) +u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid) { struct brcmf_flowring_ring *ring; @@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid) } -void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid) +void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid) { struct brcmf_flowring_ring *ring; @@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid) } -u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid) +u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid) { struct brcmf_flowring_ring *ring; - u8 hash_idx; + u16 hash_idx; ring = flow->rings[flowid]; hash_idx = ring->hash_id; @@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_flowring *flow) struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_flowring_tdls_entry *search; struct brcmf_flowring_tdls_entry *remove; - u8 flowid; + u16 flowid; for (flowid = 0; flowid < flow->nrofrings; flowid++) { if (flow->rings[flowid]) @@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); struct brcmf_pub *drvr = bus_if->drvr; u32 i; - u8 flowid; + u16 flowid; if (flow->addr_mode[ifidx] != addr_mode) { for (i = 0; i < ARRAY_SIZE(flow->hash); i++) { @@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, struct brcmf_flowring_tdls_entry *prev; struct brcmf_flowring_tdls_entry *search; u32 i; - u8 flowid; + u16 flowid; bool sta; sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h index 95fd1c9675d1..068e68d94999 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h @@ -16,7 +16,7 @@ #define BRCMFMAC_FLOWRING_H -#define BRCMF_FLOWRING_HASHSIZE 256 +#define BRCMF_FLOWRING_HASHSIZE 512 /* has to be 2^x */ #define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF @@ -24,7 +24,7 @@ struct brcmf_flowring_hash { u8 mac[ETH_ALEN]; u8 fifo; u8 ifidx; - u8 flowid; + u16 flowid; }; enum ring_status { @@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], u8 prio, u8 ifidx); u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], u8 prio, u8 ifidx); -void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid); -void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid); -u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid); -u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, +void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid); +void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid); +u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid); +u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, struct sk_buff *skb); -struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid); -void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, +struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid); +void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, struct sk_buff *skb); -u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid); -u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid); +u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid); +u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid); struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings); void brcmf_flowring_detach(struct brcmf_flowring *flow); void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index c2bdb91746cf..922966734a7f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx, } -static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) +static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid) { struct brcmf_flowring *flow = msgbuf->flow; struct brcmf_commonring *commonring; @@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) } -void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) +void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) { struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; struct msgbuf_tx_flowring_delete_req *delete; @@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) u32 count; if_msgbuf = drvr->bus_if->msgbuf; + + if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) { + brcmf_err("driver not configured for this many flowrings %d\n", + if_msgbuf->nrof_flowrings); + if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; + } + msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL); if (!msgbuf) goto fail; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h index 3d513e407e3d..ee6906a3c3f6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h @@ -33,7 +33,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev); -void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid); +void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid); int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr); void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr); #else -- cgit v1.2.3 From 10fbc7cf031d7253770331417a4adc4179c979c5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 8 Feb 2016 21:41:12 +0100 Subject: b43: Remove unnecessary synchronize_irq() before free_irq() Calling synchronize_irq() right before free_irq() is quite useless. On one hand the IRQ can easily fire again before free_irq() is entered, on the other hand free_irq() itself calls synchronize_irq() internally (in a race condition free way), before any state associated with the IRQ is freed. Patch was generated using the following semantic patch: // @@ expression irq; @@ -synchronize_irq(irq); free_irq(irq, ...); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index c279211e49f9..72380af9dc52 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -4375,12 +4375,10 @@ redo: /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */ orig_dev = dev; mutex_unlock(&wl->mutex); - if (b43_bus_host_is_sdio(dev->dev)) { + if (b43_bus_host_is_sdio(dev->dev)) b43_sdio_free_irq(dev); - } else { - synchronize_irq(dev->dev->irq); + else free_irq(dev->dev->irq, dev); - } mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev) -- cgit v1.2.3 From 400b43c5826964598e06bd3373ea4523ce749c5e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 8 Feb 2016 21:41:13 +0100 Subject: rtlwifi: Remove unnecessary synchronize_irq() before free_irq() Calling synchronize_irq() right before free_irq() is quite useless. On one hand the IRQ can easily fire again before free_irq() is entered, on the other hand free_irq() itself calls synchronize_irq() internally (in a race condition free way), before any state associated with the IRQ is freed. Patch was generated using the following semantic patch: // @@ expression irq; @@ -synchronize_irq(irq); free_irq(irq, ...); // Signed-off-by: Lars-Peter Clausen Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/pci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 7f471bff435c..140d2541562d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2392,7 +2392,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev) rtlpriv->cfg->ops->deinit_sw_vars(hw); if (rtlpci->irq_alloc) { - synchronize_irq(rtlpci->pdev->irq); free_irq(rtlpci->pdev->irq, hw); rtlpci->irq_alloc = 0; } -- cgit v1.2.3 From ccf5fa4f33ba6488579775fd3193739e70378b90 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Feb 2016 14:15:36 +0300 Subject: mwifiex: fix an indenting mistake We recently added an indent level here but missed this line. It needs another tab. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index cc072142411a..efb19e2e1169 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2452,7 +2452,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) for (i = 0; i < 4; i++) { mwifiex_read_reg_byte(adapter, reg, &read_reg); memory_size |= (read_reg << (i * 8)); - reg++; + reg++; } } else { memory_size = MWIFIEX_FW_DUMP_MAX_MEMSIZE; -- cgit v1.2.3 From 9696a159c3989e34aa9a6e658dcb89c8fcda0a80 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 11 Feb 2016 10:53:09 -0600 Subject: rtlwifi: Prepare for reworking 5G channels There are 3 drivers in this family that have 5G radios. Each of them defines local copies of the available channels. This patch adds the two arrays to the core driver. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/core.c | 16 ++++++++++++++++ drivers/net/wireless/realtek/rtlwifi/wifi.h | 9 ++++----- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 4ae421ef30d9..02eba0e2afaa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -35,6 +35,22 @@ #include #include +u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { + 36, 38, 40, 42, 44, 46, 48, /* Band 1 */ + 52, 54, 56, 58, 60, 62, 64, /* Band 2 */ + 100, 102, 104, 106, 108, 110, 112, /* Band 3 */ + 116, 118, 120, 122, 124, 126, 128, /* Band 3 */ + 132, 134, 136, 138, 140, 142, 144, /* Band 3 */ + 149, 151, 153, 155, 157, 159, 161, /* Band 4 */ + 165, 167, 169, 171, 173, 175, 177 /* Band 4 */ +}; +EXPORT_SYMBOL(channel5g); + +u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = { + 42, 58, 106, 122, 138, 155, 171 +}; +EXPORT_SYMBOL(channel5g_80m); + void rtl_addr_delay(u32 addr) { if (addr == 0xfe) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 4544752a2ba8..e603819b2953 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -122,11 +122,6 @@ */ #define CHANNEL_MAX_NUMBER_5G_80M 7 #define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, 4~9, 10~14 = three groups */ -#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to - *"phy_GetChnlGroup8812A" and - * "Hal_ReadTxPowerInfo8812A" - */ -#define CHANNEL_MAX_NUMBER_5G_80M 7 #define MAX_PG_GROUP 13 #define CHANNEL_GROUP_MAX_2G 3 #define CHANNEL_GROUP_IDX_5GL 3 @@ -2904,6 +2899,10 @@ value to host byte ordering.*/ #define STBC_VHT_TEST_TX_ENABLE BIT(2) #define STBC_VHT_CAP_TX BIT(3) +extern u8 channel5g[CHANNEL_MAX_NUMBER_5G]; + +extern u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M]; + static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) { return rtlpriv->io.read8_sync(rtlpriv, addr); -- cgit v1.2.3 From bb6fa826ba308ea4db55629ae383e66ded01bfdd Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 11 Feb 2016 10:53:10 -0600 Subject: rtlwifi: rtl8192de: Convert driver to use common 5G channels This driver defines its owh copy of the 5G channels. Change it to use the common definitions. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8192de/phy.c | 23 ++++------------------ 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index bb06fe836fe7..7810fe87dca7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -924,19 +924,11 @@ static void _rtl92d_ccxpower_index_check(struct ieee80211_hw *hw, static u8 _rtl92c_phy_get_rightchnlplace(u8 chnl) { - u8 channel_5g[59] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, - 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, - 114, 116, 118, 120, 122, 124, 126, 128, - 130, 132, 134, 136, 138, 140, 149, 151, - 153, 155, 157, 159, 161, 163, 165 - }; u8 place = chnl; if (chnl > 14) { - for (place = 14; place < sizeof(channel_5g); place++) { - if (channel_5g[place] == chnl) { + for (place = 14; place < sizeof(channel5g); place++) { + if (channel5g[place] == chnl) { place++; break; } @@ -2471,16 +2463,9 @@ static bool _rtl92d_is_legal_5g_channel(struct ieee80211_hw *hw, u8 channel) { int i; - u8 channel_5g[45] = { - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, - 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, - 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, - 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, - 161, 163, 165 - }; - for (i = 0; i < sizeof(channel_5g); i++) - if (channel == channel_5g[i]) + for (i = 0; i < sizeof(channel5g); i++) + if (channel == channel5g[i]) return true; return false; } -- cgit v1.2.3 From 2784b00aa316b430e9440087dd15c94557a27c4a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 11 Feb 2016 10:53:11 -0600 Subject: rtlwifi: rtl8192ee: Convert driver to use new 5G channel tables The driver defines its own set of channel tables for the 5G band. With this change, it will use those of the core. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 5f14308e8eb3..9fd3f1b6e4a8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -2018,18 +2018,6 @@ static void _rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw)); struct txpower_info_2g pwr2g; struct txpower_info_5g pwr5g; - u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, - 56, 58, 60, 62, 64, 100, 102, 104, 106, - 108, 110, 112, 114, 116, 118, 120, 122, - 124, 126, 128, 130, 132, 134, 136, 138, - 140, 142, 144, 149, 151, 153, 155, 157, - 159, 161, 163, 165, 167, 168, 169, 171, - 173, 175, 177 - }; - u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = { - 42, 58, 106, 122, 138, 155, 171 - }; u8 rf, idx; u8 i; -- cgit v1.2.3 From 0a44b22009d52f93b10f14bb4765915e8bafb6a5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 11 Feb 2016 10:53:12 -0600 Subject: rtlwifi: rtl8821ae: Convert driver to use common 5G channel table There are several copies of the 5G channel tables in this driver. These are removed so that the tables in the core will be used. This change also removes a useless message of "Channel 163 in Group not found". The number of possible 5G channels was reduced from 54 to a better value of 49 during the conversion. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 18 --------------- .../net/wireless/realtek/rtlwifi/rtl8821ae/phy.c | 27 +++++----------------- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 +- 3 files changed, 7 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index bbb789f8990b..5da9bd0e5002 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2786,14 +2786,6 @@ static void _rtl8812ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct txpower_info_2g pwrinfo24g; struct txpower_info_5g pwrinfo5g; - u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, - 56, 58, 60, 62, 64, 100, 102, 104, 106, - 108, 110, 112, 114, 116, 118, 120, 122, - 124, 126, 128, 130, 132, 134, 136, 138, - 140, 142, 144, 149, 151, 153, 155, 157, - 159, 161, 163, 165, 167, 168, 169, 171, 173, 175, 177}; - u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171}; u8 rf_path, index; u8 i; @@ -2872,16 +2864,6 @@ static void _rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct txpower_info_2g pwrinfo24g; struct txpower_info_5g pwrinfo5g; - u8 channel5g[CHANNEL_MAX_NUMBER_5G] = { - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, - 56, 58, 60, 62, 64, 100, 102, 104, 106, - 108, 110, 112, 114, 116, 118, 120, 122, - 124, 126, 128, 130, 132, 134, 136, 138, - 140, 142, 144, 149, 151, 153, 155, 157, - 159, 161, 163, 165, 167, 168, 169, 171, - 173, 175, 177}; - u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = { - 42, 58, 106, 122, 138, 155, 171}; u8 rf_path, index; u8 i; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index 9b4d8a637915..74165b3eb362 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -1472,18 +1472,13 @@ static char _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); char channel_index = -1; - u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = { - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, - 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, - 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 149, - 151, 153, 155, 157, 159, 161, 163, 165, 167, 168, 169, 171, - 173, 175, 177}; u8 i = 0; + if (band == BAND_ON_2_4G) channel_index = channel - 1; else if (band == BAND_ON_5G) { - for (i = 0; i < sizeof(channel_5g)/sizeof(u8); ++i) { - if (channel_5g[i] == channel) + for (i = 0; i < sizeof(channel5g)/sizeof(u8); ++i) { + if (channel5g[i] == channel) channel_index = i; } } else @@ -2240,13 +2235,6 @@ void rtl8821ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index) { - u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = { - 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, - 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, - 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, - 142, 144, 149, 151, 153, 155, 157, 159, 161, 163, 165, - 167, 168, 169, 171, 173, 175, 177 - }; u8 i = 0; bool in_24g = true; @@ -2257,7 +2245,7 @@ static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index) in_24g = false; for (i = 0; i < CHANNEL_MAX_NUMBER_5G; ++i) { - if (channel_5g[i] == channel) { + if (channel5g[i] == channel) { *chnl_index = i; return in_24g; } @@ -2728,13 +2716,10 @@ static u8 _rtl8821ae_get_txpower_index(struct ieee80211_hw *hw, u8 path, rate <= DESC_RATEVHT2SS_MCS9)) txpower += rtlefuse->txpwr_5g_bw40diff[path][TX_2S]; } else if (bandwidth == HT_CHANNEL_WIDTH_80) { - u8 channel_5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = { - 42, 58, 106, 122, 138, 155, 171 - }; u8 i; - for (i = 0; i < sizeof(channel_5g_80m) / sizeof(u8); ++i) - if (channel_5g_80m[i] == channel) + for (i = 0; i < sizeof(channel5g_80m) / sizeof(u8); ++i) + if (channel5g_80m[i] == channel) index = i; if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) || diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index e603819b2953..9e3cdd732eca 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -116,7 +116,7 @@ #define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel no */ #define CHANNEL_MAX_NUMBER_2G 14 -#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to +#define CHANNEL_MAX_NUMBER_5G 49 /* Please refer to *"phy_GetChnlGroup8812A" and * "Hal_ReadTxPowerInfo8812A" */ -- cgit v1.2.3 From 4fb37186f3b2b1f5d1a8f3e6b26b719bf2df6ee3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 2 Feb 2016 12:44:40 +0530 Subject: ath10k: remove impossible code len has been initialized with a value of 0 and buf_len with 4096. There is no way that this condition (len > buf_len) can be true now. Signed-off-by: Sudip Mukherjee Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8d4148a96af8..3dd75a2daf08 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2182,9 +2182,6 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file, mutex_lock(&ar->conf_mutex); - if (len > buf_len) - len = buf_len; - len += scnprintf(buf + len, buf_len - len, "firmware-N.bin\t\t%08x\n", crc32_le(0, ar->firmware->data, ar->firmware->size)); -- cgit v1.2.3 From 74135f599f9a2d0c54674640aa7d2423ab8ca98c Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 3 Feb 2016 21:07:42 +0530 Subject: ath10k: fix updating peer stats rx duration We are not updating peer stats rx_duration periodically unless the user one polls for fw_stats, this is because we discard the update event since pdev list is empty. Fix this by updating rx duration periodically irrepective of checks for pdev list (irrespective of ping-pong response) Fixes: 856e7c3 ("ath10k: add debugfs support for Per STA total rx duration") Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3dd75a2daf08..848a0ddca722 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -348,6 +348,9 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) */ peer_stats_svc = test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map); + if (peer_stats_svc) + ath10k_sta_update_rx_duration(ar, &stats.peers); + if (ar->debug.fw_stats_done && !peer_stats_svc) { ath10k_warn(ar, "received unsolicited stats update event\n"); goto free; @@ -384,9 +387,6 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) goto free; } - if (peer_stats_svc) - ath10k_sta_update_rx_duration(ar, &stats.peers); - list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); } -- cgit v1.2.3 From 0a3b7119000d706dfbc7e0c5b66e192a646d365f Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Wed, 16 Dec 2015 16:34:55 +0200 Subject: iwlwifi: mvm: add CT-KILL notification Up to today the driver was notified of the temperature from the FW and decided whether to enter CT-kill or not. From now on, the FW will decide when to enter CT-kill and will notify the driver. Add support for this notification. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 12 +++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 15 +++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 27 +++++++++++++++++++++++- 5 files changed, 61 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index e2dbc67a367b..724a3eef78b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -318,6 +318,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon * from AP and will send it upon d0i3 exit. * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 + * @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill + * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature + * thresholds reporting * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -351,6 +354,8 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, + IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74, + IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75, NUM_IWL_UCODE_TLV_CAPA #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index f332497e29d1..ecbf7cb600ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -279,6 +279,7 @@ enum { */ enum iwl_phy_ops_subcmd_ids { CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, + CT_KILL_NOTIFICATION = 0xFE, DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; @@ -1685,6 +1686,17 @@ struct iwl_dts_measurement_notif { __le32 voltage; } __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ +/** + * struct ct_kill_notif - CT-kill entry notification + * + * @temperature: the current temperature in celsius + * @reserved: reserved + */ +struct ct_kill_notif { + __le16 temperature; + __le16 reserved; +} __packed; /* GRP_PHY_CT_KILL_NTF */ + /*********************************** * TDLS API ***********************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ebe37bb0ce4c..200bbb76ff0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1028,6 +1030,18 @@ static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT); } +static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) +{ + /* these two TLV are redundant since the responsibility to CT-kill by + * FW happens only after we send at least one command of + * temperature THs report. + */ + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW) && + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT); +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { @@ -1502,6 +1516,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); void iwl_mvm_tt_exit(struct iwl_mvm *mvm); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp); +void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); /* Location Aware Regulatory */ struct iwl_mcc_update_resp * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 09a94a5efb61..ecc371e1f3f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -263,6 +263,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true), RX_HANDLER_GRP(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE, iwl_mvm_temp_notif, true), + RX_HANDLER_GRP(PHY_OPS_GROUP, CT_KILL_NOTIFICATION, + iwl_mvm_ct_kill_notif, false), RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, true), @@ -387,6 +389,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE), + HCMD_NAME(CT_KILL_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 758d05a8c6aa..6ba391099d7e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -7,6 +7,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -171,6 +172,24 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) iwl_mvm_tt_temp_changed(mvm, temp); } +void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct ct_kill_notif *notif; + int len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON_ONCE(len != sizeof(*notif))) { + IWL_ERR(mvm, "Invalid CT_KILL_NOTIFICATION\n"); + return; + } + + notif = (struct ct_kill_notif *)pkt->data; + IWL_DEBUG_TEMP(mvm, "CT Kill notification temperature = %d\n", + notif->temperature); + + iwl_mvm_enter_ctkill(mvm); +} + static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) { struct iwl_dts_measurement_cmd cmd = { @@ -236,6 +255,12 @@ static void check_exit_ctkill(struct work_struct *work) tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work); mvm = container_of(tt, struct iwl_mvm, thermal_throttle); + if (iwl_mvm_is_tt_in_fw(mvm)) { + iwl_mvm_exit_ctkill(mvm); + + return; + } + duration = tt->params.ct_kill_duration; mutex_lock(&mvm->mutex); -- cgit v1.2.3 From c221daf219b1cf38e7c4307f0f420ea826678af5 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Tue, 29 Dec 2015 09:54:49 +0200 Subject: iwlwifi: mvm: add registration to thermal zone Register to thermal_zone interface and implement the thermal ops. The thermal handles the device throttling, and sets the the temperature thresholds the Thermal Manager would be notified of crossing. The thermal interface adds a new thermal zone device sensor under /sys/class/thermal/ folder. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 33 ++- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 13 ++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 31 ++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 287 +++++++++++++++++++++++- 5 files changed, 353 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index ecbf7cb600ce..e692098a9f1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -279,6 +279,7 @@ enum { */ enum iwl_phy_ops_subcmd_ids { CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, + TEMP_REPORTING_THRESHOLDS_CMD = 0x04, CT_KILL_NOTIFICATION = 0xFE, DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; @@ -1676,15 +1677,28 @@ struct iwl_ext_dts_measurement_cmd { } __packed; /* XVT_FW_DTS_CONTROL_MEASUREMENT_REQUEST_API_S */ /** - * iwl_dts_measurement_notif - notification received with the measurements + * struct iwl_dts_measurement_notif_v1 - measurements notification * * @temp: the measured temperature * @voltage: the measured voltage */ -struct iwl_dts_measurement_notif { +struct iwl_dts_measurement_notif_v1 { __le32 temp; __le32 voltage; -} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_1*/ + +/** + * struct iwl_dts_measurement_notif_v2 - measurements notification + * + * @temp: the measured temperature + * @voltage: the measured voltage + * @threshold_idx: the trip index that was crossed + */ +struct iwl_dts_measurement_notif_v2 { + __le32 temp; + __le32 voltage; + __le32 threshold_idx; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_2 */ /** * struct ct_kill_notif - CT-kill entry notification @@ -1697,6 +1711,19 @@ struct ct_kill_notif { __le16 reserved; } __packed; /* GRP_PHY_CT_KILL_NTF */ +#define IWL_MAX_DTS_TRIPS 8 + +/** + * struct iwl_temp_report_ths_cmd - set temperature thresholds + * + * @num_temps: number of temperature thresholds passed + * @thresholds: array with the thresholds to be configured + */ +struct temp_report_ths_cmd { + __le32 num_temps; + __le16 thresholds[IWL_MAX_DTS_TRIPS]; +} __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */ + /*********************************** * TDLS API ***********************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 070e2af05ca2..07f2cbd9c8e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -952,8 +952,21 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } +#ifdef CONFIG_THERMAL + if (iwl_mvm_is_tt_in_fw(mvm)) { + /* in order to give the responsibility of ct-kill and + * TX backoff to FW we need to send empty temperature reporting + * cmd during init time + */ + iwl_mvm_send_temp_report_ths_cmd(mvm); + } else { + /* Initialize tx backoffs to the minimal possible */ + iwl_mvm_tt_tx_backoff(mvm, 0); + } +#else /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); +#endif WARN_ON(iwl_mvm_config_ltr(mvm)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 200bbb76ff0a..87d3e2884886 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -73,6 +73,10 @@ #include #include +#ifdef CONFIG_THERMAL +#include +#endif + #include "iwl-op-mode.h" #include "iwl-trans.h" #include "iwl-notif-wait.h" @@ -519,6 +523,20 @@ struct iwl_mvm_tt_mgmt { bool throttle; }; +#ifdef CONFIG_THERMAL +/** + *struct iwl_mvm_thermal_device - thermal zone related data + * @temp_trips: temperature thresholds for report + * @fw_trips_index: keep indexes to original array - temp_trips + * @tzone: thermal zone device data +*/ +struct iwl_mvm_thermal_device { + s16 temp_trips[IWL_MAX_DTS_TRIPS]; + u8 fw_trips_index[IWL_MAX_DTS_TRIPS]; + struct thermal_zone_device *tzone; +}; +#endif + #define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8 struct iwl_mvm_frame_stats { @@ -799,6 +817,10 @@ struct iwl_mvm { /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; +#ifdef CONFIG_THERMAL + struct iwl_mvm_thermal_device tz_device; +#endif + s32 temperature; /* Celsius */ /* * Debug option to set the NIC temperature. This option makes the @@ -1032,6 +1054,7 @@ static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) { +#ifdef CONFIG_THERMAL /* these two TLV are redundant since the responsibility to CT-kill by * FW happens only after we send at least one command of * temperature THs report. @@ -1040,6 +1063,9 @@ static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW) && fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT); +#else /* CONFIG_THERMAL */ + return false; +#endif /* CONFIG_THERMAL */ } extern const u8 iwl_mvm_ac_to_tx_fifo[]; @@ -1512,11 +1538,12 @@ void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_tt_handler(struct iwl_mvm *mvm); -void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); -void iwl_mvm_tt_exit(struct iwl_mvm *mvm); +void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff); +void iwl_mvm_thermal_exit(struct iwl_mvm *mvm); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp); void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm); /* Location Aware Regulatory */ struct iwl_mcc_update_resp * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ecc371e1f3f0..a7acadd446c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -389,6 +389,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE), + HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD), HCMD_NAME(CT_KILL_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), }; @@ -591,7 +592,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->cfg->name, mvm->trans->hw_rev); min_backoff = calc_min_backoff(trans, cfg); - iwl_mvm_tt_initialize(mvm, min_backoff); + iwl_mvm_thermal_initialize(mvm, min_backoff); if (iwlwifi_mod_params.nvm_file) mvm->nvm_file_name = iwlwifi_mod_params.nvm_file; @@ -664,6 +665,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, out_unregister: ieee80211_unregister_hw(mvm->hw); iwl_mvm_leds_exit(mvm); + iwl_mvm_thermal_exit(mvm); out_free: flush_delayed_work(&mvm->fw_dump_wk); iwl_phy_db_free(mvm->phy_db); @@ -681,7 +683,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_mvm_leds_exit(mvm); - iwl_mvm_tt_exit(mvm); + iwl_mvm_thermal_exit(mvm); ieee80211_unregister_hw(mvm->hw); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 6ba391099d7e..466d169b0e62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -65,6 +65,8 @@ * *****************************************************************************/ +#include + #include "mvm.h" #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ @@ -80,8 +82,10 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) IWL_ERR(mvm, "Enter CT Kill\n"); iwl_mvm_set_hw_ctkill_state(mvm, true); - tt->throttle = false; - tt->dynamic_smps = false; + if (!iwl_mvm_is_tt_in_fw(mvm)) { + tt->throttle = false; + tt->dynamic_smps = false; + } /* Don't schedule an exit work if we're in test mode, since * the temperature will not change unless we manually set it @@ -117,18 +121,21 @@ void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp) static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { - struct iwl_dts_measurement_notif *notif; + struct iwl_dts_measurement_notif_v1 *notif_v1; int len = iwl_rx_packet_payload_len(pkt); int temp; - if (WARN_ON_ONCE(len < sizeof(*notif))) { + /* we can use notif_v1 only, because v2 only adds an additional + * parameter, which is not used in this function. + */ + if (WARN_ON_ONCE(len < sizeof(*notif_v1))) { IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); return -EINVAL; } - notif = (void *)pkt->data; + notif_v1 = (void *)pkt->data; - temp = le32_to_cpu(notif->temp); + temp = le32_to_cpu(notif_v1->temp); /* shouldn't be negative, but since it's s32, make sure it isn't */ if (WARN_ON_ONCE(temp < 0)) @@ -159,17 +166,56 @@ static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_dts_measurement_notif_v2 *notif_v2; + int len = iwl_rx_packet_payload_len(pkt); int temp; + u32 ths_crossed; /* the notification is handled synchronously in ctkill, so skip here */ if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) return; temp = iwl_mvm_temp_notif_parse(mvm, pkt); - if (temp < 0) + + if (!iwl_mvm_is_tt_in_fw(mvm)) { + if (temp >= 0) + iwl_mvm_tt_temp_changed(mvm, temp); + return; + } + + if (WARN_ON_ONCE(len < sizeof(*notif_v2))) { + IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); + return; + } + + notif_v2 = (void *)pkt->data; + ths_crossed = le32_to_cpu(notif_v2->threshold_idx); + + /* 0xFF in ths_crossed means the notification is not related + * to a trip, so we can ignore it here. + */ + if (ths_crossed == 0xFF) + return; + + IWL_DEBUG_TEMP(mvm, "Temp = %d Threshold crossed = %d\n", + temp, ths_crossed); + +#ifdef CONFIG_THERMAL + if (WARN_ON(ths_crossed >= IWL_MAX_DTS_TRIPS)) return; - iwl_mvm_tt_temp_changed(mvm, temp); + /* + * We are now handling a temperature notification from the firmware + * in ASYNC and hold the mutex. thermal_notify_framework will call + * us back through get_temp() which ought to send a SYNC command to + * the firmware and hence to take the mutex. + * Avoid the deadlock by unlocking the mutex here. + */ + mutex_unlock(&mvm->mutex); + thermal_notify_framework(mvm->tz_device.tzone, + mvm->tz_device.fw_trips_index[ths_crossed]); + mutex_lock(&mvm->mutex); +#endif /* CONFIG_THERMAL */ } void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) @@ -460,7 +506,220 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = { .support_tx_backoff = true, }; -void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) +#ifdef CONFIG_THERMAL +static int compare_temps(const void *a, const void *b) +{ + return ((s16)le16_to_cpu(*(__le16 *)a) - + (s16)le16_to_cpu(*(__le16 *)b)); +} + +int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm) +{ + struct temp_report_ths_cmd cmd = {0}; + int ret, i, j, idx = 0; + + lockdep_assert_held(&mvm->mutex); + + /* The driver holds array of temperature trips that are unsorted + * and uncompressed, the FW should get it compressed and sorted + */ + + /* compress temp_trips to cmd array, remove uninitialized values*/ + for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) + if (mvm->tz_device.temp_trips[i] != S16_MIN) { + cmd.thresholds[idx++] = + cpu_to_le16(mvm->tz_device.temp_trips[i]); + } + cmd.num_temps = cpu_to_le32(idx); + + if (!idx) + goto send; + + /*sort cmd array*/ + sort(cmd.thresholds, idx, sizeof(s16), compare_temps, NULL); + + /* we should save the indexes of trips because we sort + * and compress the orginal array + */ + for (i = 0; i < idx; i++) { + for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) { + if (le16_to_cpu(cmd.thresholds[i]) == + mvm->tz_device.temp_trips[j]) + mvm->tz_device.fw_trips_index[i] = j; + } + } + +send: + ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP, + TEMP_REPORTING_THRESHOLDS_CMD), + 0, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n", + ret); + + return ret; +} + +static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device, + int *temperature) +{ + struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata; + int ret; + int temp; + + mutex_lock(&mvm->mutex); + + if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + ret = -EIO; + goto out; + } + + ret = iwl_mvm_get_temp(mvm, &temp); + if (ret) + goto out; + + *temperature = temp * 1000; + +out: + mutex_unlock(&mvm->mutex); + return ret; +} + +static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device, + int trip, int *temp) +{ + struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata; + + if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) + return -EINVAL; + + *temp = mvm->tz_device.temp_trips[trip] * 1000; + + return 0; +} + +static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device, + int trip, enum thermal_trip_type *type) +{ + if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) + return -EINVAL; + + *type = THERMAL_TRIP_PASSIVE; + + return 0; +} + +static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, + int trip, int temp) +{ + struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata; + struct iwl_mvm_thermal_device *tzone; + int i, ret; + s16 temperature; + + mutex_lock(&mvm->mutex); + + if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + ret = -EIO; + goto out; + } + + if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) { + ret = -EINVAL; + goto out; + } + + if ((temp / 1000) > S16_MAX) { + ret = -EINVAL; + goto out; + } + + temperature = (s16)(temp / 1000); + tzone = &mvm->tz_device; + + if (!tzone) { + ret = -EIO; + goto out; + } + + /* no updates*/ + if (tzone->temp_trips[trip] == temperature) { + ret = 0; + goto out; + } + + /* already existing temperature */ + for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) { + if (tzone->temp_trips[i] == temperature) { + ret = -EINVAL; + goto out; + } + } + + tzone->temp_trips[trip] = temperature; + + ret = iwl_mvm_send_temp_report_ths_cmd(mvm); +out: + mutex_unlock(&mvm->mutex); + return ret; +} + +static struct thermal_zone_device_ops tzone_ops = { + .get_temp = iwl_mvm_tzone_get_temp, + .get_trip_temp = iwl_mvm_tzone_get_trip_temp, + .get_trip_type = iwl_mvm_tzone_get_trip_type, + .set_trip_temp = iwl_mvm_tzone_set_trip_temp, +}; + +/* make all trips writable */ +#define IWL_WRITABLE_TRIPS_MSK (BIT(IWL_MAX_DTS_TRIPS) - 1) + +static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) +{ + int i; + char name[] = "iwlwifi"; + + if (!iwl_mvm_is_tt_in_fw(mvm)) { + mvm->tz_device.tzone = NULL; + + return; + } + + BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); + + mvm->tz_device.tzone = thermal_zone_device_register(name, + IWL_MAX_DTS_TRIPS, + IWL_WRITABLE_TRIPS_MSK, + mvm, &tzone_ops, + NULL, 0, 0); + if (IS_ERR(mvm->tz_device.tzone)) { + IWL_DEBUG_TEMP(mvm, + "Failed to register to thermal zone (err = %ld)\n", + PTR_ERR(mvm->tz_device.tzone)); + return; + } + + /* 0 is a valid temperature, + * so initialize the array with S16_MIN which invalid temperature + */ + for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) + mvm->tz_device.temp_trips[i] = S16_MIN; +} + +static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm) +{ + if (!iwl_mvm_is_tt_in_fw(mvm)) + return; + + if (mvm->tz_device.tzone) { + IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n"); + thermal_zone_device_unregister(mvm->tz_device.tzone); + mvm->tz_device.tzone = NULL; + } +} +#endif /* CONFIG_THERMAL */ + +void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff) { struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; @@ -475,10 +734,18 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) tt->dynamic_smps = false; tt->min_backoff = min_backoff; INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); + +#ifdef CONFIG_THERMAL + iwl_mvm_thermal_zone_register(mvm); +#endif } -void iwl_mvm_tt_exit(struct iwl_mvm *mvm) +void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) { cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); + +#ifdef CONFIG_THERMAL + iwl_mvm_thermal_zone_unregister(mvm); +#endif } -- cgit v1.2.3 From 5c89e7bc557e1dd5650946a0fe4940166bc62abf Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Tue, 5 Jan 2016 10:34:47 +0200 Subject: iwlwifi: mvm: add registration to cooling device Register cooling device in order to have the Thermal Manager handle the device's power budget according to the sent notifications. The interface adds a new thermal cooling device to /sys/class/thermal/ folder. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 26 ++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 5 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 19 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 147 +++++++++++++++++++++++ 6 files changed, 200 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 724a3eef78b1..63dc109605e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -321,6 +321,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature * thresholds reporting + * @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -356,6 +357,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74, IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75, + IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76, NUM_IWL_UCODE_TLV_CAPA #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index e692098a9f1e..d5f90371054e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -279,6 +279,7 @@ enum { */ enum iwl_phy_ops_subcmd_ids { CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, + CTDP_CONFIG_CMD = 0x03, TEMP_REPORTING_THRESHOLDS_CMD = 0x04, CT_KILL_NOTIFICATION = 0xFE, DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, @@ -1711,6 +1712,31 @@ struct ct_kill_notif { __le16 reserved; } __packed; /* GRP_PHY_CT_KILL_NTF */ +/** +* enum ctdp_cmd_operation - CTDP command operations +* @CTDP_CMD_OPERATION_START: update the current budget +* @CTDP_CMD_OPERATION_STOP: stop ctdp +* @CTDP_CMD_OPERATION_REPORT: get the avgerage budget +*/ +enum iwl_mvm_ctdp_cmd_operation { + CTDP_CMD_OPERATION_START = 0x1, + CTDP_CMD_OPERATION_STOP = 0x2, + CTDP_CMD_OPERATION_REPORT = 0x4, +};/* CTDP_CMD_OPERATION_TYPE_E */ + +/** + * struct iwl_mvm_ctdp_cmd - track and manage the FW power consumption budget + * + * @operation: see &enum iwl_mvm_ctdp_cmd_operation + * @budget: the budget in milliwatt + * @window_size: defined in API but not used + */ +struct iwl_mvm_ctdp_cmd { + __le32 operation; + __le32 budget; + __le32 window_size; +} __packed; + #define IWL_MAX_DTS_TRIPS 8 /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 07f2cbd9c8e7..3e596e4b3999 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -963,6 +963,11 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); } + + /* TODO: read the budget from BIOS / Platform NVM */ + if (iwl_mvm_is_ctdp_supported(mvm) && mvm->cooling_dev.cur_state > 0) + ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, + mvm->cooling_dev.cur_state); #else /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 87d3e2884886..d867cb478681 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -535,6 +535,16 @@ struct iwl_mvm_thermal_device { u8 fw_trips_index[IWL_MAX_DTS_TRIPS]; struct thermal_zone_device *tzone; }; + +/* + * iwl_mvm_cooling_device + * @cur_state: current state in milliwatts + * @cdev: struct thermal cooling device + */ +struct iwl_mvm_cooling_device { + u32 cur_state; + struct thermal_cooling_device *cdev; +}; #endif #define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8 @@ -819,6 +829,7 @@ struct iwl_mvm { struct iwl_mvm_tt_mgmt thermal_throttle; #ifdef CONFIG_THERMAL struct iwl_mvm_thermal_device tz_device; + struct iwl_mvm_cooling_device cooling_dev; #endif s32 temperature; /* Celsius */ @@ -1068,6 +1079,12 @@ static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) #endif /* CONFIG_THERMAL */ } +static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) +{ + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CTDP_SUPPORT); +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { @@ -1544,6 +1561,8 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp); void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm); +int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm); +int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget); /* Location Aware Regulatory */ struct iwl_mcc_update_resp * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index a7acadd446c4..ec3604678a56 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -389,6 +389,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE), + HCMD_NAME(CTDP_CONFIG_CMD), HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD), HCMD_NAME(CT_KILL_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 466d169b0e62..999bcb898be8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -706,6 +706,139 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) mvm->tz_device.temp_trips[i] = S16_MIN; } +static const u32 iwl_mvm_cdev_budgets[] = { + 2000, /* cooling state 0 */ + 1800, /* cooling state 1 */ + 1600, /* cooling state 2 */ + 1400, /* cooling state 3 */ + 1200, /* cooling state 4 */ + 1000, /* cooling state 5 */ + 900, /* cooling state 6 */ + 800, /* cooling state 7 */ + 700, /* cooling state 8 */ + 650, /* cooling state 9 */ + 600, /* cooling state 10 */ + 550, /* cooling state 11 */ + 500, /* cooling state 12 */ + 450, /* cooling state 13 */ + 400, /* cooling state 14 */ + 350, /* cooling state 15 */ + 300, /* cooling state 16 */ + 250, /* cooling state 17 */ + 200, /* cooling state 18 */ + 150, /* cooling state 19 */ +}; + +int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget) +{ + struct iwl_mvm_ctdp_cmd cmd = { + .operation = cpu_to_le32(op), + .budget = cpu_to_le32(budget), + .window_size = 0, + }; + int ret; + u32 status; + + lockdep_assert_held(&mvm->mutex); + + ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP, + CTDP_CONFIG_CMD), + sizeof(cmd), &cmd, &status); + + if (ret) { + IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret); + return ret; + } + + if (op == CTDP_CMD_OPERATION_START) + mvm->cooling_dev.cur_state = budget; + + else if (op == CTDP_CMD_OPERATION_REPORT) + IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status); + + return 0; +} + +static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1; + + return 0; +} + +static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata); + + if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) + return -EBUSY; + + *state = mvm->cooling_dev.cur_state; + return 0; +} + +static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long new_state) +{ + struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata); + int ret; + + if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) + return -EIO; + + if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) + return -EBUSY; + + mutex_lock(&mvm->mutex); + + if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) { + ret = -EINVAL; + goto unlock; + } + + ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, + iwl_mvm_cdev_budgets[new_state]); + +unlock: + mutex_unlock(&mvm->mutex); + return ret; +} + +static struct thermal_cooling_device_ops tcooling_ops = { + .get_max_state = iwl_mvm_tcool_get_max_state, + .get_cur_state = iwl_mvm_tcool_get_cur_state, + .set_cur_state = iwl_mvm_tcool_set_cur_state, +}; + +int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm) +{ + char name[] = "iwlwifi"; + + if (!iwl_mvm_is_ctdp_supported(mvm)) { + mvm->cooling_dev.cdev = NULL; + + return 0; + } + + BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); + + mvm->cooling_dev.cdev = + thermal_cooling_device_register(name, + mvm, + &tcooling_ops); + + if (IS_ERR(mvm->cooling_dev.cdev)) { + IWL_DEBUG_TEMP(mvm, + "Failed to register to cooling device (err = %ld)\n", + PTR_ERR(mvm->cooling_dev.cdev)); + return PTR_ERR(mvm->cooling_dev.cdev); + } + + return 0; +} + static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm) { if (!iwl_mvm_is_tt_in_fw(mvm)) @@ -717,6 +850,18 @@ static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm) mvm->tz_device.tzone = NULL; } } + +static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm) +{ + if (!iwl_mvm_is_ctdp_supported(mvm)) + return; + + if (mvm->cooling_dev.cdev) { + IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n"); + thermal_cooling_device_unregister(mvm->cooling_dev.cdev); + mvm->cooling_dev.cdev = NULL; + } +} #endif /* CONFIG_THERMAL */ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff) @@ -736,6 +881,7 @@ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff) INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); #ifdef CONFIG_THERMAL + iwl_mvm_cooling_device_register(mvm); iwl_mvm_thermal_zone_register(mvm); #endif } @@ -746,6 +892,7 @@ void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); #ifdef CONFIG_THERMAL + iwl_mvm_cooling_device_unregister(mvm); iwl_mvm_thermal_zone_unregister(mvm); #endif } -- cgit v1.2.3 From 25c2b22caceedf015d5852e3abb46d2e9271a3bd Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Feb 2016 13:09:59 +0200 Subject: iwlwifi: mvm: set the correct descriptor size for tracing The 9000 series uses a diffrent sized descriptor. Update the relevant tracing field. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ec3604678a56..3661a9db5a0b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -479,8 +479,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (iwl_mvm_has_new_rx_api(mvm)) { op_mode->ops = &iwl_mvm_ops_mq; + trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc); } else { op_mode->ops = &iwl_mvm_ops; + trans->rx_mpdu_cmd_hdr_size = + sizeof(struct iwl_rx_mpdu_res_start); if (WARN_ON(trans->num_rx_queues > 1)) goto out_free; @@ -572,7 +575,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_trans_configure(mvm->trans, &trans_cfg); trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; - trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv; trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num; memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv, -- cgit v1.2.3 From dd4d3161d0f229031914f403721ced8cb64d4d52 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Feb 2016 12:50:35 +0200 Subject: iwlwifi: mvm: fix RSS key sizing The initialization and copying of the RSS secret key should not use ARRAY_SIZE as we need to initialize a dword array, and not a byte array. Fix also the hook maximum write size to allow writing a longer table - up to full indirection table size. Fixes: 43413a975d06("iwlwifi: mvm: support rss queues configuration command") Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 5 +++-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index c529e5355803..54d0d7d2d0b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -976,7 +976,7 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm, memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table, ARRAY_SIZE(cmd.indirection_table) % nbytes); - memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key)); + memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key)); mutex_lock(&mvm->mutex); ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); @@ -1497,7 +1497,8 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); -MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, 16); +MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, + (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 3e596e4b3999..05475a2bff90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -121,7 +121,7 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) cmd.indirection_table[i] = i % mvm->trans->num_rx_queues; - memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key)); + memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key)); return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3661a9db5a0b..c5b6e8671169 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -661,7 +661,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_tof_init(mvm); /* init RSS hash key */ - get_random_bytes(mvm->secret_key, ARRAY_SIZE(mvm->secret_key)); + get_random_bytes(mvm->secret_key, sizeof(mvm->secret_key)); return op_mode; -- cgit v1.2.3 From a339e918daf281a0eb78783abc954c1e97af16c4 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 2 Feb 2016 22:58:46 +0200 Subject: iwlwifi: mvm: handle pass all scan reporting The firmware doesn't send match found notifications when no matchsets are passed. This makes sense because if there are no matchsets, nothing can be matched. But the nl80211 API should report when there are results available, even if no matchsets were passed. To handle this, we can use the firmware's ITERATION_COMPLETE reporting, which will send us notifications every time it completed a scheduled scan iteration. Then we can set a flag when we received beacons and use that to report that results are available. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 7 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 6 +++++ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 36 +++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index d867cb478681..bb811a29490d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -493,6 +493,12 @@ enum iwl_mvm_scan_type { IWL_SCAN_TYPE_FRAGMENTED, }; +enum iwl_mvm_sched_scan_pass_all_states { + SCHED_SCAN_PASS_ALL_DISABLED, + SCHED_SCAN_PASS_ALL_ENABLED, + SCHED_SCAN_PASS_ALL_FOUND, +}; + /** * struct iwl_nvm_section - describes an NVM section in memory. * @@ -687,6 +693,7 @@ struct iwl_mvm { void *scan_cmd; struct iwl_mcast_filter_cmd *mcast_filter_cmd; enum iwl_mvm_scan_type scan_type; + enum iwl_mvm_sched_scan_pass_all_states sched_scan_pass_all; /* max number of simultaneous scans the FW supports */ unsigned int max_scans; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 145ec68ce6f9..055a8b0f7ad7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -448,6 +448,12 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_update_frame_stats(mvm, rate_n_flags, rx_status->flag & RX_FLAG_AMPDU_DETAILS); #endif + + if (unlikely((ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) && + mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED)) + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND; + iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status, crypt_len, rxb); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index aa6d8074f63a..09eb72c4ae43 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -297,6 +299,12 @@ void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, iwl_mvm_dump_channel_list(notif->results, notif->scanned_channels, buf, sizeof(buf))); + + if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) { + IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n"); + ieee80211_sched_scan_results(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; + } } void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, @@ -380,6 +388,7 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, mvm->scan_status &= ~IWL_MVM_SCAN_SCHED; ieee80211_sched_scan_stopped(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) { IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n", aborted ? "aborted" : "completed", @@ -533,10 +542,13 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm, IWL_DEBUG_SCAN(mvm, "Sending scheduled scan with filtering, n_match_sets %d\n", req->n_match_sets); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; return false; } IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n"); + + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; return true; } @@ -788,6 +800,9 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; #endif + if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) + flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; + if (iwl_mvm_is_regular_scan(params) && vif->type != NL80211_IFTYPE_P2P_DEVICE && params->type != IWL_SCAN_TYPE_FRAGMENTED) @@ -1074,6 +1089,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; #endif + if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; + if (iwl_mvm_is_regular_scan(params) && vif->type != NL80211_IFTYPE_P2P_DEVICE && params->type != IWL_SCAN_TYPE_FRAGMENTED) @@ -1301,10 +1319,6 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, return -EBUSY; } - /* we don't support "match all" in the firmware */ - if (!req->n_match_sets) - return -EOPNOTSUPP; - ret = iwl_mvm_check_running_scans(mvm, type); if (ret) return ret; @@ -1400,6 +1414,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { ieee80211_sched_scan_stopped(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } mvm->scan_status &= ~mvm->scan_uid_status[uid]; @@ -1434,6 +1449,12 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, iwl_mvm_dump_channel_list(notif->results, notif->scanned_channels, buf, sizeof(buf))); + + if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) { + IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n"); + ieee80211_sched_scan_results(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; + } } static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) @@ -1528,6 +1549,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED); if (uid >= 0 && !mvm->restart_fw) { ieee80211_sched_scan_stopped(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->scan_uid_status[uid] = 0; } @@ -1549,8 +1571,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) * restart_hw, so do not report if FW is about to be * restarted. */ - if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && !mvm->restart_fw) + if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && + !mvm->restart_fw) { ieee80211_sched_scan_stopped(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; + } } } @@ -1586,6 +1611,7 @@ out: ieee80211_scan_completed(mvm->hw, true); } else if (notify) { ieee80211_sched_scan_stopped(mvm->hw); + mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } return ret; -- cgit v1.2.3 From 4494541c0c918688dfbbaf760548846a9c1bcf3f Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 1 Feb 2016 09:07:05 +0200 Subject: iwlwifi: mvm: rs: fix a theoretical access to uninitialized array elements Klocwork is unhappy as ht_vht_rates might be accessed with rate->index being set to values between 0 and 3 which will lead to accessing uninitialized array elements. Effectively this doesn't happen as in HT/VHT we're not using these rate indices. Still fix this. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 6e7e78a37879..3dc94d2e8a65 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -556,6 +556,7 @@ static char *rs_pretty_rate(const struct rs_rate *rate) if (is_type_legacy(rate->type) && (rate->index <= IWL_RATE_54M_INDEX)) rate_str = legacy_rates[rate->index]; else if ((is_type_ht(rate->type) || is_type_vht(rate->type)) && + (rate->index >= IWL_RATE_MCS_0_INDEX) && (rate->index <= IWL_RATE_MCS_9_INDEX)) rate_str = ht_vht_rates[rate->index]; else -- cgit v1.2.3 From 5a51c03fa8f61b4c7554bad97426c87a93e4606b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 23 Feb 2016 21:53:12 +0200 Subject: iwlwifi: mvm: bump firmware API to 21 The driver is now ready to handle this firmware. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-7000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c index fa41a5e1c890..fc475ce59b47 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c @@ -73,8 +73,8 @@ /* Highest firmware API version supported */ #define IWL7260_UCODE_API_MAX 17 #define IWL7265_UCODE_API_MAX 17 -#define IWL7265D_UCODE_API_MAX 20 -#define IWL3168_UCODE_API_MAX 20 +#define IWL7265D_UCODE_API_MAX 21 +#define IWL3168_UCODE_API_MAX 21 /* Oldest version we won't warn about */ #define IWL7260_UCODE_API_OK 13 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index bce9b3420a13..ad8c588e3eed 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 20 -#define IWL8265_UCODE_API_MAX 20 +#define IWL8000_UCODE_API_MAX 21 +#define IWL8265_UCODE_API_MAX 21 /* Oldest version we won't warn about */ #define IWL8000_UCODE_API_OK 13 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 4b93404f46a7..083590698e72 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 20 +#define IWL9000_UCODE_API_MAX 21 /* Oldest version we won't warn about */ #define IWL9000_UCODE_API_OK 13 -- cgit v1.2.3 From bac842da5b39f8f9521a8cb8d0b11e533424e90e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 31 Jan 2016 09:29:39 +0200 Subject: iwlwifi: pcie: aggregate Flow Handler configuration writes Instead of waking up the device each time we write a register, wake it up once, and writes the registers at once. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 56 ++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 58591ca051fd..cda678dfad05 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -616,38 +616,38 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, dma_addr_t phy_addr, u32 byte_cnt) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; int ret; trans_pcie->ucode_write_complete = false; - iwl_write_direct32(trans, - FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); - - iwl_write_direct32(trans, - FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), - dst_addr); - - iwl_write_direct32(trans, - FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), - phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - - iwl_write_direct32(trans, - FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), - (iwl_get_dma_hi_addr(phy_addr) - << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); - - iwl_write_direct32(trans, - FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), - 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | - 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | - FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); - - iwl_write_direct32(trans, - FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | - FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + if (!iwl_trans_grab_nic_access(trans, &flags)) + return -EIO; + + iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); + + iwl_write32(trans, FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), + dst_addr); + + iwl_write32(trans, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + + iwl_write32(trans, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), + (iwl_get_dma_hi_addr(phy_addr) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); + + iwl_write32(trans, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), + BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) | + BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) | + FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); + + iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | + FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + + iwl_trans_release_nic_access(trans, &flags); ret = wait_event_timeout(trans_pcie->ucode_write_waitq, trans_pcie->ucode_write_complete, 5 * HZ); -- cgit v1.2.3 From 2e5d4a8f61dcae12996bbe2bcc446d3b47625cac Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 17 Dec 2015 12:17:58 +0200 Subject: iwlwifi: pcie: Add new configuration to enable MSIX Working with MSIX requires prior configuration. This includes requesting interrupt vectors from the OS, registering the vectors and mapping the optional causes to the relevant interrupt. In addition add new interrupt handler to handle MSIX interrupt. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 49 +++++ drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 2 + drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 100 +++++++-- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 177 +++++++++++++++- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 229 ++++++++++++++++++--- 5 files changed, 507 insertions(+), 50 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 163b21bc20cb..a79c4f61a851 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -7,6 +7,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -549,4 +550,52 @@ enum dtd_diode_reg { DTS_DIODE_REG_FLAGS_PASS_ONCE = 0x00000080, /* bits [7:7] */ }; +/***************************************************************************** + * MSIX related registers * + *****************************************************************************/ + +#define CSR_MSIX_BASE (0x2000) +#define CSR_MSIX_FH_INT_CAUSES_AD (CSR_MSIX_BASE + 0x800) +#define CSR_MSIX_FH_INT_MASK_AD (CSR_MSIX_BASE + 0x804) +#define CSR_MSIX_HW_INT_CAUSES_AD (CSR_MSIX_BASE + 0x808) +#define CSR_MSIX_HW_INT_MASK_AD (CSR_MSIX_BASE + 0x80C) +#define CSR_MSIX_AUTOMASK_ST_AD (CSR_MSIX_BASE + 0x810) +#define CSR_MSIX_RX_IVAR_AD_REG (CSR_MSIX_BASE + 0x880) +#define CSR_MSIX_IVAR_AD_REG (CSR_MSIX_BASE + 0x890) +#define CSR_MSIX_PENDING_PBA_AD (CSR_MSIX_BASE + 0x1000) +#define CSR_MSIX_RX_IVAR(cause) (CSR_MSIX_RX_IVAR_AD_REG + (cause)) +#define CSR_MSIX_IVAR(cause) (CSR_MSIX_IVAR_AD_REG + (cause)) + +#define MSIX_FH_INT_CAUSES_Q(q) (q) + +/* + * Causes for the FH register interrupts + */ +enum msix_fh_int_causes { + MSIX_FH_INT_CAUSES_D2S_CH0_NUM = BIT(16), + MSIX_FH_INT_CAUSES_D2S_CH1_NUM = BIT(17), + MSIX_FH_INT_CAUSES_S2D = BIT(19), + MSIX_FH_INT_CAUSES_FH_ERR = BIT(21), +}; + +/* + * Causes for the HW register interrupts + */ +enum msix_hw_int_causes { + MSIX_HW_INT_CAUSES_REG_ALIVE = BIT(0), + MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1), + MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6), + MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7), + MSIX_HW_INT_CAUSES_REG_PERIODIC = BIT(8), + MSIX_HW_INT_CAUSES_REG_SW_ERR = BIT(25), + MSIX_HW_INT_CAUSES_REG_SCD = BIT(26), + MSIX_HW_INT_CAUSES_REG_FH_TX = BIT(27), + MSIX_HW_INT_CAUSES_REG_HW_ERR = BIT(29), + MSIX_HW_INT_CAUSES_REG_HAP = BIT(30), +}; + +#define MSIX_MIN_INTERRUPT_VECTORS 2 +#define MSIX_AUTO_CLEAR_CAUSE 0 +#define MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) + #endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 5bde23a472b4..c46e596e12b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -404,4 +404,6 @@ enum { LMPM_PAGE_PASS_NOTIF_POS = BIT(20), }; +#define UREG_CHICK (0xA05C00) +#define UREG_CHICK_MSIX_ENABLE BIT(25) #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 542bbc5e2b24..6677f3122226 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -336,6 +336,14 @@ struct iwl_tso_hdr_page { * @fw_mon_phys: physical address of the buffer for the firmware monitor * @fw_mon_page: points to the first page of the buffer for the firmware monitor * @fw_mon_size: size of the buffer for the firmware monitor + * @msix_entries: array of MSI-X entries + * @msix_enabled: true if managed to enable MSI-X + * @allocated_vector: the number of interrupt vector allocated by the OS + * @default_irq_num: default irq for non rx interrupt + * @fh_init_mask: initial unmasked fh causes + * @hw_init_mask: initial unmasked hw causes + * @fh_mask: current unmasked fh causes + * @hw_mask: current unmasked hw causes */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -402,6 +410,15 @@ struct iwl_trans_pcie { dma_addr_t fw_mon_phys; struct page *fw_mon_page; u32 fw_mon_size; + + struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES]; + bool msix_enabled; + u32 allocated_vector; + u32 default_irq_num; + u32 fh_init_mask; + u32 hw_init_mask; + u32 fh_mask; + u32 hw_mask; }; static inline struct iwl_trans_pcie * @@ -430,7 +447,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); * RX ******************************************************/ int iwl_pcie_rx_init(struct iwl_trans *trans); +irqreturn_t iwl_pcie_msix_isr(int irq, void *data); irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); +irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id); +irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id); int iwl_pcie_rx_stop(struct iwl_trans *trans); void iwl_pcie_rx_free(struct iwl_trans *trans); @@ -485,15 +505,24 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans); ******************************************************/ static inline void iwl_disable_interrupts(struct iwl_trans *trans) { - clear_bit(STATUS_INT_ENABLED, &trans->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(trans, CSR_INT_MASK, 0x00000000); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(trans, CSR_INT, 0xffffffff); - iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); + clear_bit(STATUS_INT_ENABLED, &trans->status); + if (!trans_pcie->msix_enabled) { + /* disable interrupts from uCode/NIC to host */ + iwl_write32(trans, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(trans, CSR_INT, 0xffffffff); + iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); + } else { + /* disable all the interrupt we might use */ + iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, + trans_pcie->fh_init_mask); + iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, + trans_pcie->hw_init_mask); + } IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } @@ -503,8 +532,37 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &trans->status); - trans_pcie->inta_mask = CSR_INI_SET_MASK; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + if (!trans_pcie->msix_enabled) { + trans_pcie->inta_mask = CSR_INI_SET_MASK; + iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + } else { + /* + * fh/hw_mask keeps all the unmasked causes. + * Unlike msi, in msix cause is enabled when it is unset. + */ + trans_pcie->hw_mask = trans_pcie->hw_init_mask; + trans_pcie->fh_mask = trans_pcie->fh_init_mask; + iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, + ~trans_pcie->fh_mask); + iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, + ~trans_pcie->hw_mask); + } +} + +static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, ~msk); + trans_pcie->hw_mask = msk; +} + +static inline void iwl_enable_fh_int_msk_msix(struct iwl_trans *trans, u32 msk) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~msk); + trans_pcie->fh_mask = msk; } static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) @@ -512,8 +570,15 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n"); - trans_pcie->inta_mask = CSR_INT_BIT_FH_TX; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + if (!trans_pcie->msix_enabled) { + trans_pcie->inta_mask = CSR_INT_BIT_FH_TX; + iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + } else { + iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, + trans_pcie->hw_init_mask); + iwl_enable_fh_int_msk_msix(trans, + MSIX_FH_INT_CAUSES_D2S_CH0_NUM); + } } static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) @@ -521,8 +586,15 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); - trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + if (!trans_pcie->msix_enabled) { + trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL; + iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + } else { + iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, + trans_pcie->fh_init_mask); + iwl_enable_hw_int_msk_msix(trans, + MSIX_HW_INT_CAUSES_REG_RF_KILL); + } } static inline void iwl_wake_queue(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 07973ef826c1..c0db681d66d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1135,10 +1135,10 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, /* * iwl_pcie_rx_handle - Main entry function for receiving responses from fw */ -static void iwl_pcie_rx_handle(struct iwl_trans *trans) +static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq[0]; + struct iwl_rxq *rxq = &trans_pcie->rxq[queue]; u32 r, i, j, count = 0; bool emergency = false; @@ -1259,6 +1259,51 @@ restart: napi_gro_flush(&rxq->napi, false); } +static struct iwl_trans_pcie *iwl_pcie_get_trans_pcie(struct msix_entry *entry) +{ + u8 queue = entry->entry; + struct msix_entry *entries = entry - queue; + + return container_of(entries, struct iwl_trans_pcie, msix_entries[0]); +} + +static inline void iwl_pcie_clear_irq(struct iwl_trans *trans, + struct msix_entry *entry) +{ + /* + * Before sending the interrupt the HW disables it to prevent + * a nested interrupt. This is done by writing 1 to the corresponding + * bit in the mask register. After handling the interrupt, it should be + * re-enabled by clearing this bit. This register is defined as + * write 1 clear (W1C) register, meaning that it's being clear + * by writing 1 to the bit. + */ + iwl_write_direct32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(entry->entry)); +} + +/* + * iwl_pcie_rx_msix_handle - Main entry function for receiving responses from fw + * This interrupt handler should be used with RSS queue only. + */ +irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id) +{ + struct msix_entry *entry = dev_id; + struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry); + struct iwl_trans *trans = trans_pcie->trans; + + lock_map_acquire(&trans->sync_cmd_lockdep_map); + + local_bh_disable(); + iwl_pcie_rx_handle(trans, entry->entry); + local_bh_enable(); + + iwl_pcie_clear_irq(trans, entry); + + lock_map_release(&trans->sync_cmd_lockdep_map); + + return IRQ_HANDLED; +} + /* * iwl_pcie_irq_handle_error - called for HW or SW error interrupt from card */ @@ -1589,7 +1634,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) isr_stats->rx++; local_bh_disable(); - iwl_pcie_rx_handle(trans); + iwl_pcie_rx_handle(trans, 0); local_bh_enable(); } @@ -1732,3 +1777,129 @@ irqreturn_t iwl_pcie_isr(int irq, void *data) return IRQ_WAKE_THREAD; } + +irqreturn_t iwl_pcie_msix_isr(int irq, void *data) +{ + return IRQ_WAKE_THREAD; +} + +irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) +{ + struct msix_entry *entry = dev_id; + struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry); + struct iwl_trans *trans = trans_pcie->trans; + struct isr_statistics *isr_stats = isr_stats = &trans_pcie->isr_stats; + u32 inta_fh, inta_hw; + + lock_map_acquire(&trans->sync_cmd_lockdep_map); + + spin_lock(&trans_pcie->irq_lock); + inta_fh = iwl_read_direct32(trans, CSR_MSIX_FH_INT_CAUSES_AD); + inta_hw = iwl_read_direct32(trans, CSR_MSIX_HW_INT_CAUSES_AD); + /* + * Clear causes registers to avoid being handling the same cause. + */ + iwl_write_direct32(trans, CSR_MSIX_FH_INT_CAUSES_AD, inta_fh); + iwl_write_direct32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); + spin_unlock(&trans_pcie->irq_lock); + + if (unlikely(!(inta_fh | inta_hw))) { + IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); + lock_map_release(&trans->sync_cmd_lockdep_map); + return IRQ_NONE; + } + + if (iwl_have_debug_level(IWL_DL_ISR)) + IWL_DEBUG_ISR(trans, "ISR inta_fh 0x%08x, enabled 0x%08x\n", + inta_fh, + iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD)); + + /* This "Tx" DMA channel is used only for loading uCode */ + if (inta_fh & MSIX_FH_INT_CAUSES_D2S_CH0_NUM) { + IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); + isr_stats->tx++; + /* + * Wake up uCode load routine, + * now that load is complete + */ + trans_pcie->ucode_write_complete = true; + wake_up(&trans_pcie->ucode_write_waitq); + } + + /* Error detected by uCode */ + if ((inta_fh & MSIX_FH_INT_CAUSES_FH_ERR) || + (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR)) { + IWL_ERR(trans, + "Microcode SW error detected. Restarting 0x%X.\n", + inta_fh); + isr_stats->sw++; + iwl_pcie_irq_handle_error(trans); + } + + /* After checking FH register check HW register */ + if (iwl_have_debug_level(IWL_DL_ISR)) + IWL_DEBUG_ISR(trans, + "ISR inta_hw 0x%08x, enabled 0x%08x\n", + inta_hw, + iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD)); + + /* Alive notification via Rx interrupt will do the real work */ + if (inta_hw & MSIX_HW_INT_CAUSES_REG_ALIVE) { + IWL_DEBUG_ISR(trans, "Alive interrupt\n"); + isr_stats->alive++; + } + + /* uCode wakes up after power-down sleep */ + if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP) { + IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); + iwl_pcie_rxq_check_wrptr(trans); + iwl_pcie_txq_check_wrptrs(trans); + + isr_stats->wakeup++; + } + + /* Chip got too hot and stopped itself */ + if (inta_hw & MSIX_HW_INT_CAUSES_REG_CT_KILL) { + IWL_ERR(trans, "Microcode CT kill error detected.\n"); + isr_stats->ctkill++; + } + + /* HW RF KILL switch toggled */ + if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) { + bool hw_rfkill; + + hw_rfkill = iwl_is_rfkill_set(trans); + IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", + hw_rfkill ? "disable radio" : "enable radio"); + + isr_stats->rfkill++; + + mutex_lock(&trans_pcie->mutex); + iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); + if (hw_rfkill) { + set_bit(STATUS_RFKILL, &trans->status); + if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status)) + IWL_DEBUG_RF_KILL(trans, + "Rfkill while SYNC HCMD in flight\n"); + wake_up(&trans_pcie->wait_command_queue); + } else { + clear_bit(STATUS_RFKILL, &trans->status); + } + } + + if (inta_hw & MSIX_HW_INT_CAUSES_REG_HW_ERR) { + IWL_ERR(trans, + "Hardware error detected. Restarting.\n"); + + isr_stats->hw++; + iwl_pcie_irq_handle_error(trans); + } + + iwl_pcie_clear_irq(trans, entry); + + lock_map_release(&trans->sync_cmd_lockdep_map); + + return IRQ_HANDLED; +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index cda678dfad05..102d17564178 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1123,6 +1123,20 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) iwl_pcie_prepare_card_hw(trans); } +static void iwl_pcie_synchronize_irqs(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (trans_pcie->msix_enabled) { + int i; + + for (i = 0; i < trans_pcie->allocated_vector; i++) + synchronize_irq(trans_pcie->msix_entries[i].vector); + } else { + synchronize_irq(trans_pcie->pci_dev->irq); + } +} + static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { @@ -1149,7 +1163,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_disable_interrupts(trans); /* Make sure it finished running */ - synchronize_irq(trans_pcie->pci_dev->irq); + iwl_pcie_synchronize_irqs(trans); mutex_lock(&trans_pcie->mutex); @@ -1252,8 +1266,6 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (!reset) { /* Enable persistence mode to avoid reset */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, @@ -1271,7 +1283,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, iwl_pcie_disable_ict(trans); - synchronize_irq(trans_pcie->pci_dev->irq); + iwl_pcie_synchronize_irqs(trans); iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1350,6 +1362,153 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } +struct iwl_causes_list { + u32 cause_num; + u32 mask_reg; + u8 addr; +}; + +static struct iwl_causes_list causes_list[] = { + {MSIX_FH_INT_CAUSES_D2S_CH0_NUM, CSR_MSIX_FH_INT_MASK_AD, 0}, + {MSIX_FH_INT_CAUSES_D2S_CH1_NUM, CSR_MSIX_FH_INT_MASK_AD, 0x1}, + {MSIX_FH_INT_CAUSES_S2D, CSR_MSIX_FH_INT_MASK_AD, 0x3}, + {MSIX_FH_INT_CAUSES_FH_ERR, CSR_MSIX_FH_INT_MASK_AD, 0x5}, + {MSIX_HW_INT_CAUSES_REG_ALIVE, CSR_MSIX_HW_INT_MASK_AD, 0x10}, + {MSIX_HW_INT_CAUSES_REG_WAKEUP, CSR_MSIX_HW_INT_MASK_AD, 0x11}, + {MSIX_HW_INT_CAUSES_REG_CT_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x16}, + {MSIX_HW_INT_CAUSES_REG_RF_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x17}, + {MSIX_HW_INT_CAUSES_REG_PERIODIC, CSR_MSIX_HW_INT_MASK_AD, 0x18}, + {MSIX_HW_INT_CAUSES_REG_SW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x29}, + {MSIX_HW_INT_CAUSES_REG_SCD, CSR_MSIX_HW_INT_MASK_AD, 0x2A}, + {MSIX_HW_INT_CAUSES_REG_FH_TX, CSR_MSIX_HW_INT_MASK_AD, 0x2B}, + {MSIX_HW_INT_CAUSES_REG_HW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x2D}, + {MSIX_HW_INT_CAUSES_REG_HAP, CSR_MSIX_HW_INT_MASK_AD, 0x2E}, +}; + +static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie) +{ + u32 val, max_rx_vector, i; + struct iwl_trans *trans = trans_pcie->trans; + + max_rx_vector = trans_pcie->allocated_vector - 1; + + if (!trans_pcie->msix_enabled) + return; + + iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE); + + /* + * Each cause from the list above and the RX causes is represented as + * a byte in the IVAR table. We access the first (N - 1) bytes and map + * them to the (N - 1) vectors so these vectors will be used as rx + * vectors. Then access all non rx causes and map them to the + * default queue (N'th queue). + */ + for (i = 0; i < max_rx_vector; i++) { + iwl_write8(trans, CSR_MSIX_RX_IVAR(i), MSIX_FH_INT_CAUSES_Q(i)); + iwl_clear_bit(trans, CSR_MSIX_FH_INT_MASK_AD, + BIT(MSIX_FH_INT_CAUSES_Q(i))); + } + + for (i = 0; i < ARRAY_SIZE(causes_list); i++) { + val = trans_pcie->default_irq_num | + MSIX_NON_AUTO_CLEAR_CAUSE; + iwl_write8(trans, CSR_MSIX_IVAR(causes_list[i].addr), val); + iwl_clear_bit(trans, causes_list[i].mask_reg, + causes_list[i].cause_num); + } + trans_pcie->fh_init_mask = + ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD); + trans_pcie->fh_mask = trans_pcie->fh_init_mask; + trans_pcie->hw_init_mask = + ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD); + trans_pcie->hw_mask = trans_pcie->hw_init_mask; +} + +static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, + struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u16 pci_cmd; + int max_vector; + int ret, i; + + if (trans->cfg->mq_rx_supported) { + max_vector = min_t(u32, (num_possible_cpus() + 1), + IWL_MAX_RX_HW_QUEUES); + for (i = 0; i < max_vector; i++) + trans_pcie->msix_entries[i].entry = i; + + ret = pci_enable_msix_range(pdev, trans_pcie->msix_entries, + MSIX_MIN_INTERRUPT_VECTORS, + max_vector); + if (ret > 1) { + IWL_DEBUG_INFO(trans, + "Enable MSI-X allocate %d interrupt vector\n", + ret); + trans_pcie->allocated_vector = ret; + trans_pcie->default_irq_num = + trans_pcie->allocated_vector - 1; + trans_pcie->trans->num_rx_queues = + trans_pcie->allocated_vector - 1; + trans_pcie->msix_enabled = true; + + return; + } + IWL_DEBUG_INFO(trans, + "ret = %d %s move to msi mode\n", ret, + (ret == 1) ? + "can't allocate more than 1 interrupt vector" : + "failed to enable msi-x mode"); + pci_disable_msix(pdev); + } + + ret = pci_enable_msi(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret); + /* enable rfkill interrupt: hw bug w/a */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); + } + } +} + +static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, + struct iwl_trans_pcie *trans_pcie) +{ + int i, last_vector; + + last_vector = trans_pcie->trans->num_rx_queues; + + for (i = 0; i < trans_pcie->allocated_vector; i++) { + int ret; + + ret = request_threaded_irq(trans_pcie->msix_entries[i].vector, + iwl_pcie_msix_isr, + (i == last_vector) ? + iwl_pcie_irq_msix_handler : + iwl_pcie_irq_rx_msix_handler, + IRQF_SHARED, + DRV_NAME, + &trans_pcie->msix_entries[i]); + if (ret) { + int j; + + IWL_ERR(trans_pcie->trans, + "Error allocating IRQ %d\n", i); + for (j = 0; j < i; j++) + free_irq(trans_pcie->msix_entries[i].vector, + &trans_pcie->msix_entries[i]); + pci_disable_msix(pdev); + return ret; + } + } + + return 0; +} + static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1371,6 +1530,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) iwl_pcie_apm_init(trans); + iwl_pcie_init_msix(trans_pcie); /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); @@ -1425,7 +1585,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) mutex_unlock(&trans_pcie->mutex); - synchronize_irq(trans_pcie->pci_dev->irq); + iwl_pcie_synchronize_irqs(trans); } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) @@ -1506,15 +1666,25 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) /* TODO: check if this is really needed */ pm_runtime_disable(trans->dev); - synchronize_irq(trans_pcie->pci_dev->irq); + iwl_pcie_synchronize_irqs(trans); iwl_pcie_tx_free(trans); iwl_pcie_rx_free(trans); - free_irq(trans_pcie->pci_dev->irq, trans); - iwl_pcie_free_ict(trans); + if (trans_pcie->msix_enabled) { + for (i = 0; i < trans_pcie->allocated_vector; i++) + free_irq(trans_pcie->msix_entries[i].vector, + &trans_pcie->msix_entries[i]); + + pci_disable_msix(trans_pcie->pci_dev); + trans_pcie->msix_enabled = false; + } else { + free_irq(trans_pcie->pci_dev->irq, trans); - pci_disable_msi(trans_pcie->pci_dev); + iwl_pcie_free_ict(trans); + + pci_disable_msi(trans_pcie->pci_dev); + } iounmap(trans_pcie->hw_base); pci_release_regions(trans_pcie->pci_dev); pci_disable_device(trans_pcie->pci_dev); @@ -2615,7 +2785,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, { struct iwl_trans_pcie *trans_pcie; struct iwl_trans *trans; - u16 pci_cmd; int ret, addr_size; trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), @@ -2698,17 +2867,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->pci_dev = pdev; iwl_disable_interrupts(trans); - ret = pci_enable_msi(pdev); - if (ret) { - dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret); - /* enable rfkill interrupt: hw bug w/a */ - pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); - if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { - pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); - } - } - trans->hw_rev = iwl_read32(trans, CSR_HW_REV); /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have @@ -2760,6 +2918,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } + iwl_pcie_set_interrupt_capa(pdev, trans); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); @@ -2769,19 +2928,23 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, init_waitqueue_head(&trans_pcie->d0i3_waitq); - ret = iwl_pcie_alloc_ict(trans); - if (ret) - goto out_pci_disable_msi; - - ret = request_threaded_irq(pdev->irq, iwl_pcie_isr, - iwl_pcie_irq_handler, - IRQF_SHARED, DRV_NAME, trans); - if (ret) { - IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); - goto out_free_ict; - } + if (trans_pcie->msix_enabled) { + if (iwl_pcie_init_msix_handler(pdev, trans_pcie)) + goto out_pci_release_regions; + } else { + ret = iwl_pcie_alloc_ict(trans); + if (ret) + goto out_pci_disable_msi; - trans_pcie->inta_mask = CSR_INI_SET_MASK; + ret = request_threaded_irq(pdev->irq, iwl_pcie_isr, + iwl_pcie_irq_handler, + IRQF_SHARED, DRV_NAME, trans); + if (ret) { + IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); + goto out_free_ict; + } + trans_pcie->inta_mask = CSR_INI_SET_MASK; + } #ifdef CONFIG_IWLWIFI_PCIE_RTPM trans->runtime_pm_mode = IWL_PLAT_PM_MODE_D0I3; -- cgit v1.2.3 From 60c0a88f2ded5947bdfebbd6d5e9b3925b90984e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 7 Feb 2016 10:28:13 +0200 Subject: iwlwifi: pcie: fix identation in trans.c A curly brace was misplaced, fix this. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 102d17564178..e67957d6ac79 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2239,7 +2239,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, } else { pos += scnprintf(buf + pos, bufsz - pos, "\tclosed_rb_num: Not Allocated\n"); - } + } } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); -- cgit v1.2.3 From e48c947f030d1f5c46c684a6cc2db332bc4af33f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 27 Jan 2016 18:59:48 +0200 Subject: iwlwifi: mvm: enable VHT MU-MIMO for supported hardware Incoming hardware will support VHT MU-MIMO. Declare this capability for relevant hardware. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 1 + drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 ++- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index ad8c588e3eed..97be104d1203 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -217,6 +217,7 @@ const struct iwl_cfg iwl8265_2ac_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .vht_mu_mimo_supported = true, }; const struct iwl_cfg iwl4165_2ac_cfg = { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 083590698e72..8e32a57dda0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -139,7 +139,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { .smem_len = IWL9000_SMEM_LEN, \ .thermal_params = &iwl9000_tt_params, \ .apmg_not_supported = true, \ - .mq_rx_supported = true + .mq_rx_supported = true, \ + .vht_mu_mimo_supported = true const struct iwl_cfg iwl9260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9260", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index dad5570d6cc8..4f2b57e8bbc7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -312,6 +312,7 @@ struct iwl_pwr_tx_backoff { * @smem_offset: offset from which the SMEM begins * @smem_len: the length of SMEM * @mq_rx_supported: multi-queue rx support + * @vht_mu_mimo_supported: VHT MU-MIMO support * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -364,6 +365,7 @@ struct iwl_cfg { const struct iwl_tt_params *thermal_params; bool apmg_not_supported; bool mq_rx_supported; + bool vht_mu_mimo_supported; }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 50f4cc60cf3e..e84cb8d638a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -366,6 +366,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, max_ampdu_exponent << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + if (cfg->vht_mu_mimo_supported) + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + if (cfg->ht_params->ldpc) vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; -- cgit v1.2.3 From a07a8f37023acbd7a1c8453ffe4e35a7fb173c28 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 15 Nov 2015 11:11:59 +0200 Subject: iwlwifi: mvm: update firmware of VHT MU-MIMO groups status on restart The firmware handles the VHT MU-MIMO group data on its own. However, on HW restart (and future sniffer mode) the driver shall update the firmware on the VHT MU-MIMO group membership status. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 18 +++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 28 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index d5f90371054e..ca7fec71854f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -285,6 +285,10 @@ enum iwl_phy_ops_subcmd_ids { DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; +enum iwl_data_path_subcmd_ids { + UPDATE_MU_GROUPS_CMD = 0x1, +}; + enum iwl_prot_offload_subcmd_ids { STORED_BEACON_NTF = 0xFF, }; @@ -294,6 +298,7 @@ enum { LEGACY_GROUP = 0x0, LONG_GROUP = 0x1, PHY_OPS_GROUP = 0x4, + DATA_PATH_GROUP = 0x5, PROT_OFFLOAD_GROUP = 0xb, }; @@ -1923,6 +1928,19 @@ struct iwl_shared_mem_cfg { __le32 page_buff_size; } __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ +/** + * VHT MU-MIMO group configuration + * + * @membership_status: a bitmap of MU groups + * @user_position:the position of station in a group. If the station is in the + * group then bits (group * 2) is the position -1 + */ +struct iwl_mu_group_mgmt_cmd { + __le32 reserved; + __le32 membership_status[2]; + __le32 user_position[4]; +} __packed; /* MU_GROUP_ID_MNG_TABLE_API_S_VER_1 */ + #define MAX_STORED_BEACON_SIZE 600 /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 53156810185d..f1ed90bc2740 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1762,6 +1762,22 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm) } #endif +static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mu_group_mgmt_cmd cmd = {}; + + memcpy(cmd.membership_status, vif->bss_conf.mu_group.membership, + WLAN_MEMBERSHIP_LEN); + memcpy(cmd.user_position, vif->bss_conf.mu_group.position, + WLAN_USER_POSITION_LEN); + + return iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(DATA_PATH_GROUP, + UPDATE_MU_GROUPS_CMD), + 0, sizeof(cmd), &cmd); +} + static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1870,6 +1886,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, vif->addr); } + /* + * The firmware tracks the MU-MIMO group on its own. + * However, on HW restart we should restore this data + */ + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && + changes & BSS_CHANGED_MU_GROUPS) { + ret = iwl_mvm_update_mu_groups(mvm, vif); + if (ret) + IWL_ERR(mvm, + "failed to update VHT MU_MIMO groups\n"); + } + iwl_mvm_recalc_multicast(mvm); iwl_mvm_configure_bcast_filter(mvm); -- cgit v1.2.3 From a6d5e32f247cbd3e34c7f86effbf4b426a018c32 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 14 Oct 2015 16:28:52 +0300 Subject: iwlwifi: mvm: send large SKBs to the transport Now that PCIe knows how to create A-MSDUs, use this capability and prepare SKBs that are large enough to build an A-MSDU. Advertise TSO support towards the network stack and segment the packet with gso_size set to be the maximal A-MSDU length (after having taken the headers to be added into account) to make sure that the skb that is passed down to the transport are not longer than the maximal A-MSDU allowed. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 148 ++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 4fbaadda4e99..6f67de5a2858 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "iwl-trans.h" #include "iwl-eeprom-parse.h" @@ -182,7 +183,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd->tx_flags = cpu_to_le32(tx_flags); /* Total # bytes to be transmitted */ - tx_cmd->len = cpu_to_le16((u16)skb->len); + tx_cmd->len = cpu_to_le16((u16)skb->len + + (uintptr_t)info->driver_data[0]); tx_cmd->next_frame_len = 0; tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); tx_cmd->sta_id = sta_id; @@ -372,6 +374,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) info->hw_queue != info->control.vif->cab_queue))) return -1; + /* This holds the amsdu headers length */ + info->driver_data[0] = (void *)(uintptr_t)0; + /* * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel @@ -428,33 +433,156 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) return 0; } -static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb_gso, +#ifdef CONFIG_INET +static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_sta *sta, struct sk_buff_head *mpdus_skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; + unsigned int mss = skb_shinfo(skb)->gso_size; struct sk_buff *tmp, *next; - char cb[sizeof(skb_gso->cb)]; + char cb[sizeof(skb->cb)]; + unsigned int num_subframes, tcp_payload_len, subf_len; + bool ipv4 = (skb->protocol == htons(ETH_P_IP)); + u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; + u16 amsdu_add, snap_ip_tcp, pad, i = 0; + + snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + + tcp_hdrlen(skb); + + if (!sta->max_amsdu_len || + !ieee80211_is_data_qos(hdr->frame_control)) { + num_subframes = 1; + pad = 0; + goto segment; + } + + /* TODO: for now, disable A-MSDU inside AMPDU */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + num_subframes = 1; + pad = 0; + goto segment; + } + + /* Sub frame header + SNAP + IP header + TCP header + MSS */ + subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss; + pad = (4 - subf_len) & 0x3; + + /* + * If we have N subframes in the A-MSDU, then the A-MSDU's size is + * N * subf_len + (N - 1) * pad. + */ + num_subframes = (sta->max_amsdu_len + pad) / (subf_len + pad); + if (num_subframes > 1) { + u8 *qc = ieee80211_get_qos_ctl((void *)skb->data); + + *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; + } + + tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - + tcp_hdrlen(skb) + skb->data_len; + + /* + * Make sure we have enough TBs for the A-MSDU: + * 2 for each subframe + * 1 more for each fragment + * 1 more for the potential data in the header + */ + num_subframes = + min_t(unsigned int, num_subframes, + (mvm->trans->max_skb_frags - 1 - + skb_shinfo(skb)->nr_frags) / 2); + + /* This skb fits in one single A-MSDU */ + if (num_subframes * mss >= tcp_payload_len) { + /* + * Compute the length of all the data added for the A-MSDU. + * This will be used to compute the length to write in the TX + * command. We have: SNAP + IP + TCP for n -1 subframes and + * ETH header for n subframes. Note that the original skb + * already had one set of SNAP / IP / TCP headers. + */ + num_subframes = DIV_ROUND_UP(tcp_payload_len, mss); + info = IEEE80211_SKB_CB(skb); + amsdu_add = num_subframes * sizeof(struct ethhdr) + + (num_subframes - 1) * (snap_ip_tcp + pad); + /* This holds the amsdu headers length */ + info->driver_data[0] = (void *)(uintptr_t)amsdu_add; + + __skb_queue_tail(mpdus_skb, skb); + return 0; + } - memcpy(cb, skb_gso->cb, sizeof(cb)); - next = skb_gso_segment(skb_gso, 0); - if (IS_ERR(next)) + /* + * Trick the segmentation function to make it + * create SKBs that can fit into one A-MSDU. + */ +segment: + skb_shinfo(skb)->gso_size = num_subframes * mss; + memcpy(cb, skb->cb, sizeof(cb)); + + next = skb_gso_segment(skb, NETIF_F_CSUM_MASK | NETIF_F_SG); + skb_shinfo(skb)->gso_size = mss; + if (WARN_ON_ONCE(IS_ERR(next))) return -EINVAL; else if (next) - consume_skb(skb_gso); + consume_skb(skb); while (next) { tmp = next; next = tmp->next; + memcpy(tmp->cb, cb, sizeof(tmp->cb)); + /* + * Compute the length of all the data added for the A-MSDU. + * This will be used to compute the length to write in the TX + * command. We have: SNAP + IP + TCP for n -1 subframes and + * ETH header for n subframes. + */ + tcp_payload_len = skb_tail_pointer(tmp) - + skb_transport_header(tmp) - + tcp_hdrlen(tmp) + tmp->data_len; + + if (ipv4) + ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes); + + if (tcp_payload_len > mss) { + num_subframes = DIV_ROUND_UP(tcp_payload_len, mss); + info = IEEE80211_SKB_CB(tmp); + amsdu_add = num_subframes * sizeof(struct ethhdr) + + (num_subframes - 1) * (snap_ip_tcp + pad); + info->driver_data[0] = (void *)(uintptr_t)amsdu_add; + skb_shinfo(tmp)->gso_size = mss; + } else { + u8 *qc = ieee80211_get_qos_ctl((void *)tmp->data); + + if (ipv4) + ip_send_check(ip_hdr(tmp)); + *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + skb_shinfo(tmp)->gso_size = 0; + } tmp->prev = NULL; tmp->next = NULL; __skb_queue_tail(mpdus_skb, tmp); + i++; } return 0; } +#else /* CONFIG_INET */ +static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_sta *sta, + struct sk_buff_head *mpdus_skb) +{ + /* Impossible to get TSO with CONFIG_INET */ + WARN_ON(1); + + return -1; +} +#endif /* * Sets the fields in the Tx cmd that are crypto related @@ -560,6 +688,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct sk_buff_head mpdus_skbs; unsigned int payload_len; int ret; @@ -570,6 +699,9 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) return -1; + /* This holds the amsdu headers length */ + info->driver_data[0] = (void *)(uintptr_t)0; + if (!skb_is_gso(skb)) return iwl_mvm_tx_mpdu(mvm, skb, sta); @@ -589,7 +721,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, return ret; while (!skb_queue_empty(&mpdus_skbs)) { - struct sk_buff *skb = __skb_dequeue(&mpdus_skbs); + skb = __skb_dequeue(&mpdus_skbs); ret = iwl_mvm_tx_mpdu(mvm, skb, sta); if (ret) { -- cgit v1.2.3 From bb81bb68f472bb0f9afbb483259d91d4efd86bfb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 26 Oct 2015 16:00:29 +0200 Subject: iwlwifi: mvm: add Tx A-MSDU inside A-MPDU If the peer allows, we can have A-MSDU inside A-MDPU. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 ++- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 5 ++- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 37 +++++++++++++++++------ 4 files changed, 38 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f1ed90bc2740..1a4946fc9b27 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -847,6 +847,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, u16 tid = params->tid; u16 *ssn = ¶ms->ssn; u8 buf_size = params->buf_size; + bool amsdu = params->amsdu; IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", sta->addr, tid, action); @@ -907,7 +908,8 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: - ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); + ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, + buf_size, amsdu); break; default: WARN_ON_ONCE(1); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 4854e79cbda8..b2123ce3e3a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1031,7 +1031,8 @@ release_locks: } int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid, u8 buf_size) + struct ieee80211_sta *sta, u16 tid, u8 buf_size, + bool amsdu) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; @@ -1051,6 +1052,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, tid_data->state = IWL_AGG_ON; mvmsta->agg_tids |= BIT(tid); tid_data->ssn = 0xffff; + tid_data->amsdu_in_ampdu_allowed = amsdu; spin_unlock_bh(&mvmsta->lock); fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index e3b9446ee995..b01650ac3598 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -260,6 +260,7 @@ enum iwl_mvm_agg_state { * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). * @reduced_tpc: Reduced tx power. Holds the data between the * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). + * @amsdu_in_ampdu_allowed: true if A-MSDU in A-MPDU is allowed. * @state: state of the BA agreement establishment / tear down. * @txq_id: Tx queue used by the BA session * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or @@ -274,6 +275,7 @@ struct iwl_mvm_tid_data { /* The rest is Tx AGG related */ u32 rate_n_flags; u8 reduced_tpc; + bool amsdu_in_ampdu_allowed; enum iwl_mvm_agg_state state; u16 txq_id; u16 ssn; @@ -405,7 +407,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 tid, u8 buf_size); + struct ieee80211_sta *sta, u16 tid, u8 buf_size, + bool amsdu); int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 6f67de5a2858..ff08b17b76dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -438,19 +438,26 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_sta *sta, struct sk_buff_head *mpdus_skb) { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int mss = skb_shinfo(skb)->gso_size; struct sk_buff *tmp, *next; char cb[sizeof(skb->cb)]; - unsigned int num_subframes, tcp_payload_len, subf_len; + unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len; bool ipv4 = (skb->protocol == htons(ETH_P_IP)); u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; u16 amsdu_add, snap_ip_tcp, pad, i = 0; + u8 *qc, tid; snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + tcp_hdrlen(skb); + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + return -EINVAL; + if (!sta->max_amsdu_len || !ieee80211_is_data_qos(hdr->frame_control)) { num_subframes = 1; @@ -458,13 +465,28 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, goto segment; } - /* TODO: for now, disable A-MSDU inside AMPDU */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* + * No need to lock amsdu_in_ampdu_allowed since it can't be modified + * during an BA session. + */ + if (info->flags & IEEE80211_TX_CTL_AMPDU && + !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) { num_subframes = 1; pad = 0; goto segment; } + max_amsdu_len = sta->max_amsdu_len; + + /* + * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not + * supported. This is a spec requirement (IEEE 802.11-2015 + * section 8.7.3 NOTE 3). + */ + if (info->flags & IEEE80211_TX_CTL_AMPDU && + !sta->vht_cap.vht_supported) + max_amsdu_len = min_t(unsigned int, max_amsdu_len, 4095); + /* Sub frame header + SNAP + IP header + TCP header + MSS */ subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss; pad = (4 - subf_len) & 0x3; @@ -473,12 +495,9 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * If we have N subframes in the A-MSDU, then the A-MSDU's size is * N * subf_len + (N - 1) * pad. */ - num_subframes = (sta->max_amsdu_len + pad) / (subf_len + pad); - if (num_subframes > 1) { - u8 *qc = ieee80211_get_qos_ctl((void *)skb->data); - + num_subframes = (max_amsdu_len + pad) / (subf_len + pad); + if (num_subframes > 1) *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; - } tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - tcp_hdrlen(skb) + skb->data_len; @@ -555,7 +574,7 @@ segment: info->driver_data[0] = (void *)(uintptr_t)amsdu_add; skb_shinfo(tmp)->gso_size = mss; } else { - u8 *qc = ieee80211_get_qos_ctl((void *)tmp->data); + qc = ieee80211_get_qos_ctl((void *)tmp->data); if (ipv4) ip_send_check(ip_hdr(tmp)); -- cgit v1.2.3 From 9e7dce28659531b2741939e5b6f438bca1422720 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 26 Oct 2015 16:14:06 +0200 Subject: iwlwifi: mvm: allow to limit the A-MSDU from debugfs in order to be able to tune the size of the desired A-MSDU based on link condition, add a knob to modify the length of the A-MSDU. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 19 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 5 +++++ 3 files changed, 25 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 54d0d7d2d0b1..56e6b0b8b9cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -64,6 +64,7 @@ * *****************************************************************************/ #include +#include #include "mvm.h" #include "fw-dbg.h" @@ -1080,6 +1081,22 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, return count; } +static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + unsigned int max_amsdu_len; + int ret; + + ret = kstrtouint(buf, 0, &max_amsdu_len); + + if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454) + return -EINVAL; + mvm->max_amsdu_len = max_amsdu_len; + + return count; +} + #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) #ifdef CONFIG_IWLWIFI_BCAST_FILTERING static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, @@ -1497,6 +1514,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8); MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); @@ -1541,6 +1559,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index bb811a29490d..416aedb7c19e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -861,6 +861,7 @@ struct iwl_mvm { /* Indicate if device power save is allowed */ u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */ + unsigned int max_amsdu_len; /* used for debugfs only */ struct ieee80211_vif __rcu *csa_vif; struct ieee80211_vif __rcu *csa_tx_blocked_vif; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ff08b17b76dd..a5a55da142eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -448,6 +448,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, bool ipv4 = (skb->protocol == htons(ETH_P_IP)); u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; u16 amsdu_add, snap_ip_tcp, pad, i = 0; + unsigned int dbg_max_amsdu_len; u8 *qc, tid; snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + @@ -477,6 +478,10 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, } max_amsdu_len = sta->max_amsdu_len; + dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len); + if (dbg_max_amsdu_len) + max_amsdu_len = min_t(unsigned int, max_amsdu_len, + dbg_max_amsdu_len); /* * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not -- cgit v1.2.3 From 04e3a5da6b73d7f01661288ead426986fa5312a1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 28 Oct 2015 09:47:41 +0200 Subject: iwlwifi: mvm: don't enable A-MSDU when the rates are too low Allow A-MSDU only when we are not downscaling and the initial MCS is at least 5. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 24 ++++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 3 ++- 3 files changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 3dc94d2e8a65..61d0a8cd13f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1673,6 +1673,20 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) } } +static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl, + enum rs_action scale_action) +{ + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); + + if ((!is_vht(&tbl->rate) && !is_ht(&tbl->rate)) || + tbl->rate.index < IWL_RATE_MCS_5_INDEX || + scale_action == RS_ACTION_DOWNSCALE) + sta_priv->tlc_amsdu = false; + else + sta_priv->tlc_amsdu = true; +} + /* * setup rate table in uCode */ @@ -2416,6 +2430,7 @@ lq_update: tbl->rate.index = index; if (IWL_MVM_RS_80_20_FAR_RANGE_TWEAK) rs_tweak_rate_tbl(mvm, sta, lq_sta, tbl, scale_action); + rs_set_amsdu_len(mvm, sta, tbl, scale_action); rs_update_rate_tbl(mvm, sta, lq_sta, tbl); } @@ -3099,6 +3114,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, sband = hw->wiphy->bands[band]; lq_sta->lq.sta_id = sta_priv->sta_id; + sta_priv->tlc_amsdu = false; for (j = 0; j < LQ_SIZE; j++) rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]); @@ -3658,10 +3674,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = + container_of(lq_sta, struct iwl_mvm_sta, lq_sta); struct iwl_mvm *mvm; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct rs_rate *rate = &tbl->rate; u32 ss_params; + mvm = lq_sta->pers.drv; buff = kmalloc(2048, GFP_KERNEL); if (!buff) @@ -3687,10 +3706,11 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_ht20(rate)) ? "20MHz" : (is_ht40(rate)) ? "40MHz" : (is_ht80(rate)) ? "80Mhz" : "BAD BW"); - desc += sprintf(buff + desc, " %s %s %s\n", + desc += sprintf(buff + desc, " %s %s %s %s\n", (rate->sgi) ? "SGI" : "NGI", (rate->ldpc) ? "LDPC" : "BCC", - (lq_sta->is_agg) ? "AGG on" : ""); + (lq_sta->is_agg) ? "AGG on" : "", + (mvmsta->tlc_amsdu) ? "AMSDU on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index b01650ac3598..f95f603ad56c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -313,6 +313,7 @@ struct iwl_mvm_key_pn { * @tx_protection: reference counter for controlling the Tx protection. * @tt_tx_protection: is thermal throttling enable Tx protection? * @disable_tx: is tx to this STA disabled? + * @tlc_amsdu: true if A-MSDU is allowed * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) * @sleep_tx_count: the number of frames that we told the firmware to let out * even when that station is asleep. This is useful in case the queue @@ -347,6 +348,7 @@ struct iwl_mvm_sta { bool tt_tx_protection; bool disable_tx; + bool tlc_amsdu; u8 agg_tids; u8 sleep_tx_count; }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index a5a55da142eb..a73ae01f3a48 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -460,7 +460,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, return -EINVAL; if (!sta->max_amsdu_len || - !ieee80211_is_data_qos(hdr->frame_control)) { + !ieee80211_is_data_qos(hdr->frame_control) || + !mvmsta->tlc_amsdu) { num_subframes = 1; pad = 0; goto segment; -- cgit v1.2.3 From 50b0213fdb830e21ed64375230c3271b21bb584a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 11 Nov 2015 11:37:02 +0200 Subject: iwlwifi: mvm: don't send an A-MSDU that is larger than the TXF The A-MSDU must be smaller than the Transmit FIFO in the device. Since the size of the TXF can change depending on the device / firmware compilation mode, take the size of the FIFO dynamically from the what the firmware tells us. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index a73ae01f3a48..dd616c1d59b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -449,7 +449,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; u16 amsdu_add, snap_ip_tcp, pad, i = 0; unsigned int dbg_max_amsdu_len; - u8 *qc, tid; + u8 *qc, tid, txf; snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + tcp_hdrlen(skb); @@ -480,6 +480,19 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, max_amsdu_len = sta->max_amsdu_len; dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len); + + /* the Tx FIFO to which this A-MSDU will be routed */ + txf = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; + + /* + * Don't send an AMSDU that will be longer than the TXF. + * Add a security margin of 256 for the TX command + headers. + * We also want to have the start of the next packet inside the + * fifo to be able to send bursts. + */ + max_amsdu_len = min_t(unsigned int, max_amsdu_len, + mvm->shared_mem_cfg.txfifo_size[txf] - 256); + if (dbg_max_amsdu_len) max_amsdu_len = min_t(unsigned int, max_amsdu_len, dbg_max_amsdu_len); -- cgit v1.2.3 From e0d8fdecf3acf36eb738e42d3caf46371500881c Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 28 Dec 2015 22:37:08 +0200 Subject: iwlwifi: support tracing wide commands Current iwlwifi_trace_dev_rx prints only the cmd without the group, which might be misleading. Change it to print the wide id. While at it add the DATA_PATH group and sub commands to the trace of the command names, sine it is missing due to patches submitted in parallel. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index 22786d7dc00a..2a0703fcec56 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -73,12 +73,12 @@ TRACE_EVENT(iwlwifi_dev_rx, TP_ARGS(dev, trans, pkt, len), TP_STRUCT__entry( DEV_ENTRY - __field(u8, cmd) + __field(u16, cmd) __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len)) ), TP_fast_assign( DEV_ASSIGN; - __entry->cmd = pkt->hdr.cmd; + __entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); memcpy(__get_dynamic_array(rxbuf), pkt, iwl_rx_trace_len(trans, pkt, len)); ), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index c5b6e8671169..bfa6da1bf846 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -395,6 +395,13 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), }; +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { + HCMD_NAME(UPDATE_MU_GROUPS_CMD), +}; + /* Please keep this array *SORTED* by hex value. * Access is done through binary search */ @@ -406,6 +413,7 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = { [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names), + [DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names), [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names), }; -- cgit v1.2.3 From 77fe739554e13d44466e115dbaba3e7aa3aececd Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 10 Jan 2016 14:23:25 +0200 Subject: iwlwifi: mvm: update rx_status with mactime flag When forming IBSS, mac80211 scans in order to find an already existing cell to join. In case the scan does not find any existing cell a new IBSS cell is formed. When receiving the beacons of another IBSS cell we should merge if the other IBSS cell's TSF is higher than ours. However, currently iwlmvm does not set any timestamp flag in rx_status so there is no valid rx timestamp to compare the beacon's TSF to. The reason for that is that TSF as indicated by the firmware is at INA time, but up till now mac80211 expected the TSF at the beginning or end of the MPDU. Set the flag to the newly added RX_FLAG_MACTIME_PLCP_START flag. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 8 +++----- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 535134d639e0..e885db3464b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1484,6 +1484,8 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, /* update rx_status according to the notification's metadata */ memset(&rx_status, 0, sizeof(rx_status)); rx_status.mactime = le64_to_cpu(sb->tsf); + /* TSF as indicated by the firmware is at INA time */ + rx_status.flag |= RX_FLAG_MACTIME_PLCP_START; rx_status.device_timestamp = le32_to_cpu(sb->system_time); rx_status.band = (sb->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 055a8b0f7ad7..ad625f0c79ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -322,11 +322,9 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->freq = ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), rx_status->band); - /* - * TSF as indicated by the fw is at INA time, but mac80211 expects the - * TSF at the beginning of the MPDU. - */ - /*rx_status->flag |= RX_FLAG_MACTIME_MPDU;*/ + + /* TSF as indicated by the firmware is at INA time */ + rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; iwl_mvm_get_signal_strength(mvm, phy_info, rx_status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 615dea143d4e..a9180b06fb52 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -332,6 +332,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->freq = ieee80211_channel_to_frequency(desc->channel, rx_status->band); iwl_mvm_get_signal_strength(mvm, desc, rx_status); + /* TSF as indicated by the firmware is at INA time */ + rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; rcu_read_lock(); -- cgit v1.2.3 From 3af512d6aac7eb6420086f124abb4426f5f4b369 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 22 Jul 2015 11:38:40 +0300 Subject: iwlwifi: mvm: support filtered frames notification During d0i3 frames might be filtered by the FW and this may cause reordering buffer a delay - as the frames will not be received and reorder will time out. Introduce an API function to receive notification of filtered frames and pass the information to the mac80211. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 22 +++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 ++ drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 49 +++++++++++++++++++++++++ 4 files changed, 77 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index ca7fec71854f..e1e11946f7e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -119,6 +119,8 @@ enum { SCAN_ABORT_UMAC = 0xe, SCAN_COMPLETE_UMAC = 0xf, + BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13, + /* station table */ ADD_STA_KEY = 0x17, ADD_STA = 0x18, @@ -1286,6 +1288,26 @@ struct iwl_fw_bcast_filter { struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS]; } __packed; /* BCAST_FILTER_S_VER_1 */ +#define BA_WINDOW_STREAMS_MAX 16 +#define BA_WINDOW_STATUS_TID_MSK 0x000F +#define BA_WINDOW_STATUS_STA_ID_POS 4 +#define BA_WINDOW_STATUS_STA_ID_MSK 0x01F0 +#define BA_WINDOW_STATUS_VALID_MSK BIT(9) + +/** + * struct iwl_ba_window_status_notif - reordering window's status notification + * @bitmap: bitmap of received frames [start_seq_num + 0]..[start_seq_num + 63] + * @ra_tid: bit 3:0 - TID, bit 8:4 - STA_ID, bit 9 - valid + * @start_seq_num: the start sequence number of the bitmap + * @mpdu_rx_count: the number of received MPDUs since entering D0i3 + */ +struct iwl_ba_window_status_notif { + __le64 bitmap[BA_WINDOW_STREAMS_MAX]; + __le16 ra_tid[BA_WINDOW_STREAMS_MAX]; + __le32 start_seq_num[BA_WINDOW_STREAMS_MAX]; + __le16 mpdu_rx_count[BA_WINDOW_STREAMS_MAX]; +} __packed; /* BA_WINDOW_STATUS_NTFY_API_S_VER_1 */ + /** * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. * @default_discard: default action for this mac (discard (1) / pass (0)). diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 416aedb7c19e..fa987bd9da0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1268,6 +1268,8 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_window_status_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index bfa6da1bf846..52c73d0c1be5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -236,6 +236,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, iwl_mvm_rx_ant_coupling_notif, true), + RX_HANDLER(BA_WINDOW_STATUS_NOTIFICATION_ID, + iwl_mvm_window_status_notif, false), + RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true), @@ -294,6 +297,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(SCAN_COMPLETE_UMAC), HCMD_NAME(TOF_CMD), HCMD_NAME(TOF_NOTIFICATION), + HCMD_NAME(BA_WINDOW_STATUS_NOTIFICATION_ID), HCMD_NAME(ADD_STA_KEY), HCMD_NAME(ADD_STA), HCMD_NAME(REMOVE_STA), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index ad625f0c79ed..485cfc1a4daa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -626,3 +627,51 @@ void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb)); } + +void iwl_mvm_window_status_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_ba_window_status_notif *notif = (void *)pkt->data; + int i; + u32 pkt_len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ONCE(pkt_len != sizeof(*notif), + "Received window status notification of wrong size (%u)\n", + pkt_len)) + return; + + rcu_read_lock(); + for (i = 0; i < BA_WINDOW_STREAMS_MAX; i++) { + struct ieee80211_sta *sta; + u8 sta_id, tid; + u64 bitmap; + u32 ssn; + u16 ratid; + u16 received_mpdu; + + ratid = le16_to_cpu(notif->ra_tid[i]); + /* check that this TID is valid */ + if (!(ratid & BA_WINDOW_STATUS_VALID_MSK)) + continue; + + received_mpdu = le16_to_cpu(notif->mpdu_rx_count[i]); + if (received_mpdu == 0) + continue; + + tid = ratid & BA_WINDOW_STATUS_TID_MSK; + /* get the station */ + sta_id = (ratid & BA_WINDOW_STATUS_STA_ID_MSK) + >> BA_WINDOW_STATUS_STA_ID_POS; + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (IS_ERR_OR_NULL(sta)) + continue; + bitmap = le64_to_cpu(notif->bitmap[i]); + ssn = le32_to_cpu(notif->start_seq_num[i]); + + /* update mac80211 with the bitmap for the reordering buffer */ + ieee80211_mark_rx_ba_filtered_frames(sta, tid, ssn, bitmap, + received_mpdu); + } + rcu_read_unlock(); +} -- cgit v1.2.3 From 88076015f80f7645b1eaada6291f4a23ab96bd8f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 15 Feb 2016 17:26:48 +0200 Subject: iwlwifi: pcie: configure more RFH settings Fine tune RFH registers further: * Set default queue explicitly * Set RFH to drop frames exceeding RB size * Set the maximum rx transfer size to DRAM to 128 instead of 64 Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 24 ++++++++++++++---------- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 12 +++++++++++- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 4ab6682ea53e..8af818b10e71 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -368,20 +368,24 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RFH_RXF_DMA_RBDCB_SIZE_512 (0x9 << RFH_RXF_DMA_RBDCB_SIZE_POS) #define RFH_RXF_DMA_RBDCB_SIZE_1024 (0xA << RFH_RXF_DMA_RBDCB_SIZE_POS) #define RFH_RXF_DMA_RBDCB_SIZE_2048 (0xB << RFH_RXF_DMA_RBDCB_SIZE_POS) -#define RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */ +#define RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */ #define RFH_RXF_DMA_MIN_RB_SIZE_POS 24 -#define RFH_RXF_DMA_MIN_RB_4_8 (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS) -#define RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */ -#define RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/ -#define RFH_DMA_EN_ENABLE_VAL BIT(31) +#define RFH_RXF_DMA_MIN_RB_4_8 (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS) +#define RFH_RXF_DMA_DROP_TOO_LARGE_MASK (0x04000000) /* bit 26 */ +#define RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */ +#define RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/ +#define RFH_DMA_EN_ENABLE_VAL BIT(31) #define RFH_RXF_RXQ_ACTIVE 0xA0980C #define RFH_GEN_CFG 0xA09800 +#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0) +#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1) +#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4) /* 0 - 64B, 1- 128B */ #define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00 -#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0) -#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1) -#define DEFAULT_RXQ_NUM 8 +#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8 + +#define DEFAULT_RXQ_NUM 0 /* end of 9000 rx series registers */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index c0db681d66d1..398dd9332345 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -783,16 +783,26 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) * Single frame mode * Rx buffer size 4 or 8k or 12k * Min RB size 4 or 8 + * Drop frames that exceed RB size * 512 RBDs */ iwl_write_prph(trans, RFH_RXF_DMA_CFG, RFH_DMA_EN_ENABLE_VAL | rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK | RFH_RXF_DMA_MIN_RB_4_8 | + RFH_RXF_DMA_DROP_TOO_LARGE_MASK | RFH_RXF_DMA_RBDCB_SIZE_512); + /* + * Activate DMA snooping. + * Set RX DMA chunk size to 128 bit + * Default queue is 0 + */ iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP | - RFH_GEN_CFG_SERVICE_DMA_SNOOP); + RFH_GEN_CFG_RB_CHUNK_SIZE | + (DEFAULT_RXQ_NUM << RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) | + RFH_GEN_CFG_SERVICE_DMA_SNOOP); + /* Enable the relevant rx queues */ iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, enabled); /* Set interrupt coalescing timer to default (2048 usecs) */ -- cgit v1.2.3 From 863eac305a7ba75e7c394b2a24cdee2a636b7dc4 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 1 Dec 2015 20:39:57 +0200 Subject: iwlwifi: pcie: add pm_prepare and pm_complete ops With these ops, we can know when we are about to enter system suspend. This allows us to exit D0i3 state before entering suspend. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 41 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0ca0f13b69b0..91d74b3f666b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -836,6 +836,7 @@ struct iwl_trans { enum iwl_plat_pm_mode system_pm_mode; enum iwl_plat_pm_mode runtime_pm_mode; + bool suspending; /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 753ec6785912..d33b6baf5f98 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -811,6 +811,45 @@ static int iwl_pci_runtime_resume(struct device *device) return 0; } + +static int iwl_pci_system_prepare(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct iwl_trans *trans = pci_get_drvdata(pdev); + + IWL_DEBUG_RPM(trans, "preparing for system suspend\n"); + + /* This is called before entering system suspend and before + * the runtime resume is called. Set the suspending flag to + * prevent the wakelock from being taken. + */ + trans->suspending = true; + + /* Wake the device up from runtime suspend before going to + * platform suspend. This is needed because we don't know + * whether wowlan any is set and, if it's not, mac80211 will + * disconnect (in which case, we can't be in D0i3). + */ + pm_runtime_resume(device); + + return 0; +} + +static void iwl_pci_system_complete(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct iwl_trans *trans = pci_get_drvdata(pdev); + + IWL_DEBUG_RPM(trans, "completing system suspend\n"); + + /* This is called as a counterpart to the prepare op. It is + * called either when suspending fails or when suspend + * completed successfully. Now there's no risk of grabbing + * the wakelock anymore, so we can release the suspending + * flag. + */ + trans->suspending = false; +} #endif /* CONFIG_IWLWIFI_PCIE_RTPM */ static const struct dev_pm_ops iwl_dev_pm_ops = { @@ -820,6 +859,8 @@ static const struct dev_pm_ops iwl_dev_pm_ops = { SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend, iwl_pci_runtime_resume, NULL) + .prepare = iwl_pci_system_prepare, + .complete = iwl_pci_system_complete, #endif /* CONFIG_IWLWIFI_PCIE_RTPM */ }; -- cgit v1.2.3 From 685b346c3af35bcdc1316289ce8c76e28a5a7a7e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 23 Feb 2016 11:34:17 +0200 Subject: iwlwifi: pcie: prevent skbs shadowing in iwl_trans_pcie_reclaim The patch below introduced a variable shadowing. Fix that. Fixes: 3955525d5d17 ("iwlwifi: pcie: buffer packets to avoid overflowing Tx queues") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 837a7d536874..16ad820ca824 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1062,10 +1062,10 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, if (iwl_queue_space(&txq->q) > txq->q.low_mark && test_bit(txq_id, trans_pcie->queue_stopped)) { - struct sk_buff_head skbs; + struct sk_buff_head overflow_skbs; - __skb_queue_head_init(&skbs); - skb_queue_splice_init(&txq->overflow_q, &skbs); + __skb_queue_head_init(&overflow_skbs); + skb_queue_splice_init(&txq->overflow_q, &overflow_skbs); /* * This is tricky: we are in reclaim path which is non @@ -1076,8 +1076,8 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, */ spin_unlock_bh(&txq->lock); - while (!skb_queue_empty(&skbs)) { - struct sk_buff *skb = __skb_dequeue(&skbs); + while (!skb_queue_empty(&overflow_skbs)) { + struct sk_buff *skb = __skb_dequeue(&overflow_skbs); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 dev_cmd_idx = IWL_TRANS_FIRST_DRIVER_DATA + 1; struct iwl_device_cmd *dev_cmd = -- cgit v1.2.3 From a571f5f635ef40ff3a5e85acc7f20daa58bcf06a Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 7 Dec 2015 12:50:58 +0200 Subject: iwlwifi: mvm: add duplicate packet detection per rx queue Next hardware will direct TCP/UDP streams to different cores. Packets belonging to the same stream will be directed to the same core. The result is that duplicates will be always directed to the same rx queue were the first packet was received. This enabled parallelizing the duplicate packet detection across the different cores, without sharing data between the rx queues. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 66 +++++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 14 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 13 +++++- 3 files changed, 92 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index a9180b06fb52..d89194223af3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -285,6 +285,66 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, skb->ip_summed = CHECKSUM_UNNECESSARY; } +/* + * returns true if a packet outside BA session is a duplicate and + * should be dropped + */ +static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, + struct ieee80211_rx_status *rx_status, + struct ieee80211_hdr *hdr, + struct iwl_rx_mpdu_desc *desc) +{ + struct iwl_mvm_sta *mvm_sta; + struct iwl_mvm_rxq_dup_data *dup_data; + u8 baid, tid, sub_frame_idx; + + if (WARN_ON(IS_ERR_OR_NULL(sta))) + return false; + + baid = (le32_to_cpu(desc->reorder_data) & + IWL_RX_MPDU_REORDER_BAID_MASK) >> + IWL_RX_MPDU_REORDER_BAID_SHIFT; + + if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) + return false; + + mvm_sta = iwl_mvm_sta_from_mac80211(sta); + dup_data = &mvm_sta->dup_data[queue]; + + /* + * Drop duplicate 802.11 retransmissions + * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") + */ + if (ieee80211_is_ctl(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) { + rx_status->flag |= RX_FLAG_DUP_VALIDATED; + return false; + } + + if (ieee80211_is_data_qos(hdr->frame_control)) + /* frame has qos control */ + tid = *ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CTL_TID_MASK; + else + tid = IWL_MAX_TID_COUNT; + + /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ + sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; + + if (unlikely(ieee80211_has_retry(hdr->frame_control) && + dup_data->last_seq[tid] == hdr->seq_ctrl && + dup_data->last_sub_frame[tid] >= sub_frame_idx)) + return true; + + dup_data->last_seq[tid] = hdr->seq_ctrl; + dup_data->last_sub_frame[tid] = sub_frame_idx; + + rx_status->flag |= RX_FLAG_DUP_VALIDATED; + + return false; +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { @@ -389,6 +449,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, desc); + + if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { + kfree_skb(skb); + rcu_read_unlock(); + return; + } } /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b2123ce3e3a8..4717b185f5b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -280,6 +280,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_rxq_dup_data *dup_data; int i, ret, sta_id; lockdep_assert_held(&mvm->mutex); @@ -327,6 +328,16 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, } mvm_sta->agg_tids = 0; + if (iwl_mvm_has_new_rx_api(mvm) && + !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + dup_data = kcalloc(mvm->trans->num_rx_queues, + sizeof(*dup_data), + GFP_KERNEL); + if (!dup_data) + return -ENOMEM; + mvm_sta->dup_data = dup_data; + } + ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); if (ret) goto err; @@ -508,6 +519,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + if (iwl_mvm_has_new_rx_api(mvm)) + kfree(mvm_sta->dup_data); + if (vif->type == NL80211_IFTYPE_STATION && mvmvif->ap_sta_id == mvm_sta->sta_id) { ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index f95f603ad56c..db701cad87c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -295,6 +295,16 @@ struct iwl_mvm_key_pn { } ____cacheline_aligned_in_smp q[]; }; +/** + * struct iwl_mvm_rxq_dup_data - per station per rx queue data + * @last_seq: last sequence per tid for duplicate packet detection + * @last_sub_frame: last subframe packet + */ +struct iwl_mvm_rxq_dup_data { + __le16 last_seq[IWL_MAX_TID_COUNT + 1]; + u8 last_sub_frame[IWL_MAX_TID_COUNT + 1]; +} ____cacheline_aligned_in_smp; + /** * struct iwl_mvm_sta - representation of a station in the driver * @sta_id: the index of the station in the fw (will be replaced by id_n_color) @@ -321,6 +331,7 @@ struct iwl_mvm_key_pn { * we are sending frames from an AMPDU queue and there was a hole in * the BA window. To be used for UAPSD only. * @ptk_pn: per-queue PTK PN data structures + * @dup_data: per queue duplicate packet detection data * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -340,8 +351,8 @@ struct iwl_mvm_sta { struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; struct iwl_lq_sta lq_sta; struct ieee80211_vif *vif; - struct iwl_mvm_key_pn __rcu *ptk_pn[4]; + struct iwl_mvm_rxq_dup_data *dup_data; /* Temporary, until the new TLC will control the Tx protection */ s8 tx_protection; -- cgit v1.2.3 From 94bb44813ebe07ff06f869c7612c0c73e04ac4b0 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 16 Dec 2015 18:48:28 +0200 Subject: iwlwifi: mvm: add RSS queues notification infrastructure In multi rx queue HW, without execessive locking, there is no sync between the ctrl path (default queue) and the rest of the rx queues. This might cause issues on certain situations. For example, in case a delBA was processed on a default queue but out of order packets still wait for processing on the other queue. The solution is to introduce internal messaging between the CTRL path and the other rx queues. The driver will send a message to the firmware, which will echo it to all the requested queues. The message will be in order inside the queue. This way we can avoid CTRL path and RSS queues races. Add support for this messaging mechanism. As the firmware is agnostic to the data sent, add internal representation of the data as well. Although currently only delBA flow will use it, the internal representation will enable generic use of this infrastructure for future uses. Next patch will utilize this messaging mechanism for the reorder buffer delBA flow. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 52 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 ++++ drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 48 ++++++++++++++++++++ 5 files changed, 114 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index df939f51d9b9..eb9b87038e1f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -391,4 +391,56 @@ struct iwl_rss_config_cmd { u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE]; } __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */ +#define IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE 128 +#define IWL_MULTI_QUEUE_SYNC_SENDER_POS 0 +#define IWL_MULTI_QUEUE_SYNC_SENDER_MSK 0xf + +/** + * struct iwl_rxq_sync_cmd - RXQ notification trigger + * + * @flags: flags of the notification. bit 0:3 are the sender queue + * @rxq_mask: rx queues to send the notification on + * @count: number of bytes in payload, should be DWORD aligned + * @payload: data to send to rx queues + */ +struct iwl_rxq_sync_cmd { + __le32 flags; + __le32 rxq_mask; + __le32 count; + u8 payload[]; +} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */ + +/** + * struct iwl_rxq_sync_notification - Notification triggered by RXQ + * sync command + * + * @count: number of bytes in payload + * @payload: data to send to rx queues + */ +struct iwl_rxq_sync_notification { + __le32 count; + u8 payload[]; +} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */ + +/** +* Internal message identifier +* +* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA +*/ +enum iwl_mvm_rxq_notif_type { + IWL_MVM_RXQ_NOTIF_DEL_BA, +}; + +/** +* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent +* in &iwl_rxq_sync_cmd. Should be DWORD aligned. +* +* @type: value from &iwl_mvm_rxq_notif_type +* @data: payload +*/ +struct iwl_mvm_internal_rxq_notif { + u32 type; + u8 data[]; +} __packed; + #endif /* __fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index e1e11946f7e9..f432ddd4cde3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -289,6 +289,8 @@ enum iwl_phy_ops_subcmd_ids { enum iwl_data_path_subcmd_ids { UPDATE_MU_GROUPS_CMD = 0x1, + TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, + RX_QUEUES_NOTIFICATION = 0xFF, }; enum iwl_prot_offload_subcmd_ids { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index fa987bd9da0d..f05d2a1f4467 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1225,6 +1225,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, int queue); +int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, + const u8 *data, u32 count); +void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, + int queue); void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 52c73d0c1be5..ac271ffe477b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -404,6 +404,8 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(UPDATE_MU_GROUPS_CMD), + HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), + HCMD_NAME(RX_QUEUES_NOTIFICATION), }; /* Please keep this array *SORTED* by hex value. @@ -876,6 +878,9 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0); else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD) iwl_mvm_rx_phy_cmd_mq(mvm, rxb); + else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP && + pkt->hdr.cmd == RX_QUEUES_NOTIFICATION)) + iwl_mvm_rx_queue_notif(mvm, rxb, 0); else iwl_mvm_rx_common(mvm, rxb, pkt); } @@ -1548,6 +1553,9 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode, if (unlikely(pkt->hdr.cmd == FRAME_RELEASE)) iwl_mvm_rx_frame_release(mvm, rxb, queue); + else if (unlikely(pkt->hdr.cmd == RX_QUEUES_NOTIFICATION && + pkt->hdr.group_id == DATA_PATH_GROUP)) + iwl_mvm_rx_queue_notif(mvm, rxb, queue); else iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index d89194223af3..590fc6faff04 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -345,6 +345,54 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, return false; } +int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, + const u8 *data, u32 count) +{ + struct iwl_rxq_sync_cmd *cmd; + u32 data_size = sizeof(*cmd) + count; + int ret; + + /* should be DWORD aligned */ + if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE)) + return -EINVAL; + + cmd = kzalloc(data_size, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->rxq_mask = cpu_to_le32(rxq_mask); + cmd->count = cpu_to_le32(count); + cmd->flags = 0; + memcpy(cmd->payload, data, count); + + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(DATA_PATH_GROUP, + TRIGGER_RX_QUEUES_NOTIF_CMD), + 0, data_size, cmd); + + kfree(cmd); + return ret; +} + +void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, + int queue) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_rxq_sync_notification *notif; + struct iwl_mvm_internal_rxq_notif *internal_notif; + + notif = (void *)pkt->data; + internal_notif = (void *)notif->payload; + + switch (internal_notif->type) { + case IWL_MVM_RXQ_NOTIF_DEL_BA: + /* TODO */ + break; + default: + WARN_ONCE(1, "Invalid identifier %d", internal_notif->type); + } +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { -- cgit v1.2.3 From 7ed3eec53023deecffb61abbcb7f8408ff6ab064 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 25 Feb 2016 10:12:36 +0200 Subject: iwlwifi: mvm: remove unused field in iwl_mvm_tid_data Commit 69c7fda40921c125eeeef6a827f6270ac6aa1baa removed the users of iwl_mvm_tid_data.reduced_tpc. Due to a conflict, I forgot to commit the hunk that removed the field itself. Do this know. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index db701cad87c1..1a8f69a41405 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -258,8 +258,6 @@ enum iwl_mvm_agg_state { * This is basically (last acked packet++). * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). - * @reduced_tpc: Reduced tx power. Holds the data between the - * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). * @amsdu_in_ampdu_allowed: true if A-MSDU in A-MPDU is allowed. * @state: state of the BA agreement establishment / tear down. * @txq_id: Tx queue used by the BA session @@ -274,7 +272,6 @@ struct iwl_mvm_tid_data { u16 next_reclaimed; /* The rest is Tx AGG related */ u32 rate_n_flags; - u8 reduced_tpc; bool amsdu_in_ampdu_allowed; enum iwl_mvm_agg_state state; u16 txq_id; -- cgit v1.2.3 From f92659a110436cdfdd8d7661188ba059b61404b7 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 3 Feb 2016 15:04:49 +0200 Subject: iwlwifi: mvm: support VHT MU-MIMO notification When the device is in d0i3/d3 we will not receive the VHT MU-MIMO group id management frame. Instead, firmware will notify us upon exit on the current status and we can in turn update mac80211. Support this notification. While at it, also check as a precaution that the vif is indeed the VHT MU-MIMO owner before updating the firmware. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 13 +++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 33 +++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 +++ 4 files changed, 49 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index f432ddd4cde3..4a0fc47c81f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -290,6 +290,7 @@ enum iwl_phy_ops_subcmd_ids { enum iwl_data_path_subcmd_ids { UPDATE_MU_GROUPS_CMD = 0x1, TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, + MU_GROUP_MGMT_NOTIF = 0xFE, RX_QUEUES_NOTIFICATION = 0xFF, }; @@ -1965,6 +1966,18 @@ struct iwl_mu_group_mgmt_cmd { __le32 user_position[4]; } __packed; /* MU_GROUP_ID_MNG_TABLE_API_S_VER_1 */ +/** + * struct iwl_mu_group_mgmt_notif - VHT MU-MIMO group id notification + * + * @membership_status: a bitmap of MU groups + * @user_position: the position of station in a group. If the station is in the + * group then bits (group * 2) is the position -1 + */ +struct iwl_mu_group_mgmt_notif { + __le32 membership_status[2]; + __le32 user_position[4]; +} __packed; /* MU_GROUP_MNG_NTFY_API_S_VER_1 */ + #define MAX_STORED_BEACON_SIZE 600 /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 1a4946fc9b27..b7551610f37e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -1780,6 +1781,34 @@ static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, 0, sizeof(cmd), &cmd); } +static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + if (vif->mu_mimo_owner) { + struct iwl_mu_group_mgmt_notif *notif = _data; + + /* + * MU-MIMO Group Id action frame is little endian. We treat + * the data received from firmware as if it came from the + * action frame, so no conversion is needed. + */ + ieee80211_update_mu_groups(vif, + (u8 *)¬if->membership_status, + (u8 *)¬if->user_position); + } +} + +void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data; + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_mu_mimo_iface_iterator, notif); +} + static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1890,10 +1919,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* * The firmware tracks the MU-MIMO group on its own. - * However, on HW restart we should restore this data + * However, on HW restart we should restore this data. */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - changes & BSS_CHANGED_MU_GROUPS) { + (changes & BSS_CHANGED_MU_GROUPS) && vif->mu_mimo_owner) { ret = iwl_mvm_update_mu_groups(mvm, vif); if (ret) IWL_ERR(mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f05d2a1f4467..21986f63682e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1272,6 +1272,8 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_window_status_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ac271ffe477b..8bdaa7b27ab1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -275,6 +275,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true), RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, iwl_mvm_rx_stored_beacon_notif, false), + RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF, + iwl_mvm_mu_mimo_grp_notif, false), }; #undef RX_HANDLER @@ -405,6 +407,7 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(UPDATE_MU_GROUPS_CMD), HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), + HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), }; -- cgit v1.2.3 From f1704618987b2710760582c87b5f7f600e529a60 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 25 Feb 2016 10:19:59 +0200 Subject: iwlwifi: mvm: various trivial cleanups * Remove uneeded includes: iwl-csr.h and devcoredump aren't used in mac80211.c. * Remove uneeded empty line Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b7551610f37e..85ea5a8b5e3a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -70,7 +70,6 @@ #include #include #include -#include #include #include #include @@ -86,7 +85,6 @@ #include "testmode.h" #include "iwl-fw-error-dump.h" #include "iwl-prph.h" -#include "iwl-csr.h" #include "iwl-nvm-parse.h" #include "fw-dbg.h" @@ -2142,7 +2140,6 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, bss_conf->txpower); iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); } - } static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, -- cgit v1.2.3 From 21daff96a90e8bc2dfa57499c8305dbb9430f661 Mon Sep 17 00:00:00 2001 From: Beni Lev Date: Wed, 23 Dec 2015 17:39:57 +0300 Subject: iwlwifi: mvm: Set global RRM capability Allow to publish RRM capabilities without the need to support a minimal capability set. Since some RRM features(e.g. neighbor report) are fw independent, set this capability unconditionally. Signed-off-by: Beni Lev Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 85ea5a8b5e3a..4c2449b0ba86 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -610,6 +610,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_RRM); + mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From cee5a882d0273aac0d622368885c9aac676cce33 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 3 Feb 2016 16:28:25 +0200 Subject: iwlwifi: mvm: forbid U-APSD for P2P Client if the firmware doesn't support it Older versions of the firmware don't support U-APSD for P2P Client. Forbid U-APSD for P2P Client when an old firmware is being used. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 4c2449b0ba86..86b4b9d81435 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2334,6 +2334,11 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT)) return; + if (vif->p2p && !iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) { + vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; + return; + } + if (iwlwifi_mod_params.uapsd_disable) { vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; return; -- cgit v1.2.3 From 283115fb1dcf6b2162e988db98e156b998a5ebb3 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 24 Jan 2016 22:16:08 +0200 Subject: iwlwifi: mvm: Send power command on BSS_CHANGED_BEACON_INFO if needed Beacon abort (ba) is set while sending power command, but only after at least one beacon_filter command was successfully sent. If we heard a beacon before starting association, this order is maintained and ba is properly set. However, if the first beacon is received after association, we send the power command upon association, configure the beacon filtering when the first beacon arrives, and in that case, beacon abort is not set. So identify this, and send a power command post the beacon_filter command if needed. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 86b4b9d81435..927b0559d42d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1955,7 +1955,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); } - if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { + if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS | + /* + * Send power command on every beacon change, + * because we may have not enabled beacon abort yet. + */ + BSS_CHANGED_BEACON_INFO)) { ret = iwl_mvm_power_update_mac(mvm); if (ret) IWL_ERR(mvm, "failed to update power mode\n"); -- cgit v1.2.3 From e29cc6b9c99639d9502bde0693afd3e49ec1ffd7 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 28 Jan 2016 14:25:33 +0200 Subject: iwlwifi: mvm: take care of padded packets To ensure that the SNAP/TCP/IP headers are DW aligned, the firmware may add 2-byte pad at the end of the mac header - after the IV, before the SNAP. In that case the mpdu descriptor pad bit will be turned on. Driver should take it into consideration, and remove the padding before passing the packet to mac80211. Do that. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 30 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 590fc6faff04..cd6ca374e5d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -156,7 +156,14 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, u16 len, u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { - unsigned int hdrlen, fraglen; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; + unsigned int headlen, fraglen, pad_len = 0; + unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); + + if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) + pad_len = 2; + len -= pad_len; /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and @@ -170,14 +177,23 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023(). */ - hdrlen = (len <= skb_tailroom(skb)) ? len : - sizeof(*hdr) + crypt_len + 8; + headlen = (len <= skb_tailroom(skb)) ? len : + hdrlen + crypt_len + 8; + /* The firmware may align the packet to DWORD. + * The padding is inserted after the IV. + * After copying the header + IV skip the padding if + * present before copying packet data. + */ + hdrlen += crypt_len; memcpy(skb_put(skb, hdrlen), hdr, hdrlen); - fraglen = len - hdrlen; + memcpy(skb_put(skb, headlen - hdrlen), (u8 *)hdr + hdrlen + pad_len, + headlen - hdrlen); + + fraglen = len - headlen; if (fraglen) { - int offset = (void *)hdr + hdrlen - + int offset = (void *)hdr + headlen + pad_len - rxb_addr(rxb) + rxb_offset(rxb); skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, -- cgit v1.2.3 From eea76c364261aa4338f530c09a38afa69af41797 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 21 Feb 2016 16:29:17 +0200 Subject: iwlwifi: mvm: kill iwl_mvm_enable_agg_txq iwl_mvm_enable_agg_txq has only one user. Kill it and adapt the call site. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 16 ---------------- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 16 +++++++++++----- 2 files changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 21986f63682e..b461b909e7af 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1549,22 +1549,6 @@ void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout); } -static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, - int mac80211_queue, int fifo, - int sta_id, int tid, int frame_limit, - u16 ssn, unsigned int wdg_timeout) -{ - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = fifo, - .sta_id = sta_id, - .tid = tid, - .frame_limit = frame_limit, - .aggregate = true, - }; - - iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout); -} - /* Thermal management and CT-kill */ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 4717b185f5b0..ef99942d7169 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1052,9 +1052,16 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false); - int queue, fifo, ret; + int queue, ret; u16 ssn; + struct iwl_trans_txq_scd_cfg cfg = { + .sta_id = mvmsta->sta_id, + .tid = tid, + .frame_limit = buf_size, + .aggregate = true, + }; + BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE) != IWL_MAX_TID_COUNT); @@ -1069,11 +1076,10 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, tid_data->amsdu_in_ampdu_allowed = amsdu; spin_unlock_bh(&mvmsta->lock); - fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; + cfg.fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; - iwl_mvm_enable_agg_txq(mvm, queue, - vif->hw_queue[tid_to_mac80211_ac[tid]], fifo, - mvmsta->sta_id, tid, buf_size, ssn, wdg_timeout); + iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[tid_to_mac80211_ac[tid]], + ssn, &cfg, wdg_timeout); ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); if (ret) -- cgit v1.2.3 From 32795a885ac31ccadd45e7886cc2ae31b2d2ef06 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Thu, 25 Feb 2016 10:18:34 +0200 Subject: iwlwifi: mvm: Disable beacon storing in D3 when WOWLAN configured Currently when entering D3 with WOWLAN configured, we enable in the configuration flags beacon storing, and do not disable beacon filtering, and do not wake up from a magic packet. Having both enabled is wrong (should not have both enabled), and causes problems in the RX queues in the FW, causing the FW not to recognize the magic packet when it comes. Disable beacon storing in wowlan configuration. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 5214482a0403..cf5e6349301e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -856,8 +856,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; wowlan_config_cmd->flags = ENABLE_L3_FILTERING | - ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING | - ENABLE_STORE_BEACON; + ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; /* Query the last used seqno and set it */ ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); -- cgit v1.2.3 From 3d2d442236b3f87cf9ff70c4252488ed7c6d5be8 Mon Sep 17 00:00:00 2001 From: Golan Ben-Ami Date: Tue, 23 Feb 2016 10:34:48 +0200 Subject: iwlwifi: support ucode with d0 unified image - regular and usniffer Till today, the ucode consisted of two d0 images - regular, in which the usniffer wasn't enabled, and usniffer, in which the usniffer logs were enabled. Lately, the two images were unified, so there is only one d0 image, in which the usniffer logs are enabled. Add new TLV capability for supporting the consolidated images (set 2, bit 13). Signed-off-by: Golan Ben-Ami Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 3 ++- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index ab4c2a0470b2..ee4ffa599fd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1033,7 +1033,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, } } - if (usniffer_req && !*usniffer_images) { + if (!fw_has_capa(capa, IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED) && + usniffer_req && !*usniffer_images) { IWL_ERR(drv, "user selected to work with usniffer but usniffer image isn't available in ucode package\n"); return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 63dc109605e3..5f69bf5e04c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -322,6 +322,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature * thresholds reporting * @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command + * @IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in + * regular image. * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -358,6 +360,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74, IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75, IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76, + IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77, NUM_IWL_UCODE_TLV_CAPA #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 05475a2bff90..f075c36a77c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -537,7 +537,9 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, struct iwl_sf_region st_fwrd_space; if (ucode_type == IWL_UCODE_REGULAR && - iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE)) + iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && + !(fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED))) fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER); else fw = iwl_get_ucode_image(mvm, ucode_type); -- cgit v1.2.3 From fcb6b92a682fe5032fdc31af7f8ed86f1dabb1e2 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Mon, 22 Feb 2016 10:21:41 +0200 Subject: iwlwifi: mvm: update ucode status before stopping device Leaving ucode_loaded to true after stop_device() has been called is a recipe for problems. Flows that are not sync'ed with the driver life cycle (like debugfs hooks and thermal hooks) must check that the firmware is loaded before they interact with it. Therefore we need to keep this variable updated with the real status of the firmware. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 +-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 ++---- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index cf5e6349301e..c1a313149eed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -816,8 +816,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) { iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true); - iwl_trans_stop_device(mvm->trans); - + iwl_mvm_stop_device(mvm); /* * Set the HW restart bit -- this is mostly true as we're * going to load new firmware and reprogram that, though diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f075c36a77c5..efec6ec22f58 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1009,7 +1009,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: - iwl_trans_stop_device(mvm->trans); + iwl_mvm_stop_device(mvm); return ret; } @@ -1053,7 +1053,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) return 0; error: - iwl_trans_stop_device(mvm->trans); + iwl_mvm_stop_device(mvm); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 927b0559d42d..ec6b07282e7d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -972,7 +972,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) */ iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); - iwl_trans_stop_device(mvm->trans); + iwl_mvm_stop_device(mvm); mvm->scan_status = 0; mvm->ps_disabled = false; @@ -1141,7 +1141,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) */ flush_work(&mvm->roc_done_wk); - iwl_trans_stop_device(mvm->trans); + iwl_mvm_stop_device(mvm); iwl_mvm_async_handlers_purge(mvm); /* async_handlers_list is empty and will stay empty: HW is stopped */ @@ -1172,8 +1172,6 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) mvm->scan_uid_status[i] = 0; } } - - mvm->ucode_loaded = false; } static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b461b909e7af..6d4e4879357c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1549,6 +1549,12 @@ void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout); } +static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) +{ + mvm->ucode_loaded = false; + iwl_trans_stop_device(mvm->trans); +} + /* Thermal management and CT-kill */ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 8bdaa7b27ab1..4716176cbfe0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -643,7 +643,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE); err = iwl_run_init_mvm_ucode(mvm, true); if (!err || !iwlmvm_mod_params.init_dbg) - iwl_trans_stop_device(trans); + iwl_mvm_stop_device(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); mutex_unlock(&mvm->mutex); /* returns 0 if successful, 1 if success but in rfkill */ -- cgit v1.2.3 From 5eae443eb5e2b3777582ea37c6a002171ec134d5 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 24 Feb 2016 14:56:21 +0200 Subject: iwlwifi: pcie: detect and workaround invalid write ptr behavior In 9000 series A0 step the closed_rb_num is not wrapping around properly. The queue is wrapping around as it should, so we can W/A it by wrapping the closed_rb_num in the driver. While at it, extend RX logging and add error handling of other cases HW values may cause us to access invalid memory locations. Add also a proper masking of vid value read from HW - this should not have actual affect, but better to be on the safe side. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 398dd9332345..489b07a9e471 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1159,9 +1159,12 @@ restart: r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF; i = rxq->read; + /* W/A 9000 device step A0 wrap-around bug */ + r &= (rxq->queue_size - 1); + /* Rx interrupt, but nothing sent from uCode */ if (i == r) - IWL_DEBUG_RX(trans, "HW = SW = %d\n", r); + IWL_DEBUG_RX(trans, "Q %d: HW = SW = %d\n", rxq->id, r); while (i != r) { struct iwl_rx_mem_buffer *rxb; @@ -1174,15 +1177,18 @@ restart: * used_bd is a 32 bit but only 12 are used to retrieve * the vid */ - u16 vid = (u16)le32_to_cpu(rxq->used_bd[i]); + u16 vid = le32_to_cpu(rxq->used_bd[i]) & 0x0FFF; + if (WARN(vid >= ARRAY_SIZE(trans_pcie->global_table), + "Invalid rxb index from HW %u\n", (u32)vid)) + goto out; rxb = trans_pcie->global_table[vid]; } else { rxb = rxq->queue[i]; rxq->queue[i] = NULL; } - IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d\n", r, i); + IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i); iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency); i = (i + 1) & (rxq->queue_size - 1); @@ -1245,7 +1251,7 @@ restart: goto restart; } } - +out: /* Backtrack one entry */ rxq->read = i; spin_unlock(&rxq->lock); @@ -1301,6 +1307,9 @@ irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id) struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry); struct iwl_trans *trans = trans_pcie->trans; + if (WARN_ON(entry->entry >= trans->num_rx_queues)) + return IRQ_NONE; + lock_map_acquire(&trans->sync_cmd_lockdep_map); local_bh_disable(); -- cgit v1.2.3 From 280452c9056421364111930b6336e27d85240438 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Tue, 23 Feb 2016 16:23:38 +0200 Subject: iwlwifi: mvm: disable DQA support Do not allow entrance into DQA flows until feature is completely ready and merged. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6d4e4879357c..7ea2baae0489 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -986,8 +986,9 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm) { - return fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_DQA_SUPPORT); + /* Make sure DQA isn't allowed in driver until feature is complete */ + return false && fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_DQA_SUPPORT); } static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) -- cgit v1.2.3 From 33c85ead7115ad0a1c3c47d5d1d8f8474775d644 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 22 Feb 2016 15:44:13 +0200 Subject: iwlwifi: mvm: only release the trans ref if d0i3 is supported in fw If d0i3 is not supported by the firmware (or if it's disabled via module parameters) we shouldn't release the initial transport reference, so that we won't enter runtime suspend. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4716176cbfe0..f3283f4ea3df 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -672,8 +672,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); - /* rpm starts with a taken reference, we can release it now */ - iwl_trans_unref(mvm->trans); + /* The transport always starts with a taken reference, we can + * release it now if d0i3 is supported */ + if (iwl_mvm_is_d0i3_supported(mvm)) + iwl_trans_unref(mvm->trans); iwl_mvm_tof_init(mvm); -- cgit v1.2.3 From 0d0985adf6519952e0d51b5272abc3ef28d833bc Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Mon, 29 Feb 2016 13:25:48 +0200 Subject: iwlwifi: add disable_11ac module param Add module parameter that disables VHT capabilities. Signed-off-by: Andrei Otcheretianski Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 2 ++ drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index ee4ffa599fd8..184c0fef37c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1719,3 +1719,7 @@ MODULE_PARM_DESC(fw_monitor, module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_entry_delay, uint, S_IRUGO); MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)"); + +module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool, + S_IRUGO); +MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index b88ecc7892a9..d1a5dd1602f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -115,6 +115,7 @@ enum iwl_amsdu_size { * entering D0i3 (in msecs) * @lar_disable: disable LAR (regulatory), default = 0 * @fw_monitor: allow to use firmware monitor + * @disable_11ac: disable VHT capabilities, default = false. */ struct iwl_mod_params { int sw_crypto; @@ -135,6 +136,7 @@ struct iwl_mod_params { unsigned int d0i3_entry_delay; bool lar_disable; bool fw_monitor; + bool disable_11ac; }; #endif /* #__iwl_modparams_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index e84cb8d638a1..348135792f3e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -452,7 +452,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, IEEE80211_BAND_5GHZ); iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, tx_chains, rx_chains); - if (data->sku_cap_11ac_enable) + if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac) iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, tx_chains, rx_chains); -- cgit v1.2.3 From e27deb4583642d6c5b3cf18060e8239db1be9e59 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 1 Mar 2016 10:30:48 +0200 Subject: iwlwifi: mvm: take the transport ref back when leaving If d0i3 is supported, we have released the initial transport reference in iwl_op_mode_mvm_start(), so we should take it back in iwl_op_mode_mvm_stop() to keep it balanced. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index f3283f4ea3df..3760a094b932 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -703,6 +703,13 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); int i; + /* If d0i3 is supported, we have released the reference that + * the transport started with, so we should take it back now + * that we are leaving. + */ + if (iwl_mvm_is_d0i3_supported(mvm)) + iwl_trans_ref(mvm->trans); + iwl_mvm_leds_exit(mvm); iwl_mvm_thermal_exit(mvm); -- cgit v1.2.3 From b4f7a9d168d9f8204abf06d244a7938dd62b87b0 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 3 Feb 2016 11:05:41 +0200 Subject: iwlwifi: mvm: support sw queue start/stop from mvm Add a wrapper function to allow stopping SW queues from MVM as well. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 38 ++++++++++++++++++---------- 2 files changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7ea2baae0489..f9019c4a5c0e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1556,6 +1556,10 @@ static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) iwl_trans_stop_device(mvm->trans); } +/* Stop/start all mac queues in a given bitmap */ +void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq); +void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq); + /* Thermal management and CT-kill */ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3760a094b932..e6d0adc07029 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -897,24 +897,17 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, iwl_mvm_rx_common(mvm, rxb, pkt); } -static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) +void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq) { - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - unsigned long mq; int q; - spin_lock_bh(&mvm->queue_info_lock); - mq = mvm->queue_info[queue].hw_queue_to_mac80211; - spin_unlock_bh(&mvm->queue_info_lock); - if (WARN_ON_ONCE(!mq)) return; for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) { if (atomic_inc_return(&mvm->mac80211_queue_stop_count[q]) > 1) { IWL_DEBUG_TX_QUEUES(mvm, - "queue %d (mac80211 %d) already stopped\n", - queue, q); + "mac80211 %d already stopped\n", q); continue; } @@ -934,24 +927,29 @@ static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode, iwl_trans_block_txq_ptrs(mvm->trans, false); } -static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) +static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); unsigned long mq; - int q; spin_lock_bh(&mvm->queue_info_lock); - mq = mvm->queue_info[queue].hw_queue_to_mac80211; + mq = mvm->queue_info[hw_queue].hw_queue_to_mac80211; spin_unlock_bh(&mvm->queue_info_lock); + iwl_mvm_stop_mac_queues(mvm, mq); +} + +void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq) +{ + int q; + if (WARN_ON_ONCE(!mq)) return; for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) { if (atomic_dec_return(&mvm->mac80211_queue_stop_count[q]) > 0) { IWL_DEBUG_TX_QUEUES(mvm, - "queue %d (mac80211 %d) still stopped\n", - queue, q); + "mac80211 %d still stopped\n", q); continue; } @@ -959,6 +957,18 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) } } +static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + unsigned long mq; + + spin_lock_bh(&mvm->queue_info_lock); + mq = mvm->queue_info[hw_queue].hw_queue_to_mac80211; + spin_unlock_bh(&mvm->queue_info_lock); + + iwl_mvm_start_mac_queues(mvm, mq); +} + void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) { if (state) -- cgit v1.2.3 From e0b6ce00b1ec0434e96629ab64f3e16dcb4f33b7 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 3 Feb 2016 21:07:43 +0530 Subject: ath10k: fix pointless update of peer stats list We periodically receive f/w stats event for updating the rx duration and there is no reason to keep on appending the f/w stats peer list, as this gets completely cleaned up when the user polls for f/w stats {pdev, vdev, peer stats}. Only don't print the warning message in the case PEER_STATS service is enabled Fixes: 856e7c3 ("ath10k: add debugfs support for Per STA total rx duration") Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 848a0ddca722..a633152787e0 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -351,8 +351,10 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) if (peer_stats_svc) ath10k_sta_update_rx_duration(ar, &stats.peers); - if (ar->debug.fw_stats_done && !peer_stats_svc) { - ath10k_warn(ar, "received unsolicited stats update event\n"); + if (ar->debug.fw_stats_done) { + if (!peer_stats_svc) + ath10k_warn(ar, "received unsolicited stats update event\n"); + goto free; } -- cgit v1.2.3 From 53a5c9bc53ce51f65699a43c67ab167436d28083 Mon Sep 17 00:00:00 2001 From: Ashok Raj Nagarajan Date: Fri, 5 Feb 2016 21:12:48 +0530 Subject: ath10k: fix pktlog in QCA99X0 Currently, we are providing wrong payload data of pktlog to trace points. Data we receive from FW through copy engine 8 contains pktlog data alone. We don't need to parse anything in driver before handing it to trace points. Fixes: afb0bf7f530b ("ath10k: add support for pktlog in QCA99X0") Signed-off-by: Ashok Raj Nagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index cc957a625605..bf778f291133 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2145,11 +2145,7 @@ EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler); void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar, struct sk_buff *skb) { - struct ath10k_pktlog_10_4_hdr *hdr = - (struct ath10k_pktlog_10_4_hdr *)skb->data; - - trace_ath10k_htt_pktlog(ar, hdr->payload, - sizeof(*hdr) + __le16_to_cpu(hdr->size)); + trace_ath10k_htt_pktlog(ar, skb->data, skb->len); dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler); -- cgit v1.2.3 From 18353749170033405790ed62a3ae2aa2d3d8a82a Mon Sep 17 00:00:00 2001 From: Ashok Raj Nagarajan Date: Fri, 5 Feb 2016 21:12:49 +0530 Subject: ath10k: add hw_rev to trace events to support pktlog pktlog data is different between firmware variants (eg. 10.2 vs 10.4). To have a unified user space script to decode pktlog trace events generated, it is desirable to know which firmware variant has provided the events and thereby decode the pktlogs appropriately. Hardware revision (hw_rev) helps to determine the firmware variant sending these trace events. So add hw_rev to trace events. Signed-off-by: Ashok Raj Nagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/trace.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 71bdb368813d..e0d00cef0bd8 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -250,6 +250,7 @@ TRACE_EVENT(ath10k_wmi_dbglog, TP_STRUCT__entry( __string(device, dev_name(ar->dev)) __string(driver, dev_driver_string(ar->dev)) + __field(u8, hw_type); __field(size_t, buf_len) __dynamic_array(u8, buf, buf_len) ), @@ -257,14 +258,16 @@ TRACE_EVENT(ath10k_wmi_dbglog, TP_fast_assign( __assign_str(device, dev_name(ar->dev)); __assign_str(driver, dev_driver_string(ar->dev)); + __entry->hw_type = ar->hw_rev; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), TP_printk( - "%s %s len %zu", + "%s %s %d len %zu", __get_str(driver), __get_str(device), + __entry->hw_type, __entry->buf_len ) ); @@ -277,6 +280,7 @@ TRACE_EVENT(ath10k_htt_pktlog, TP_STRUCT__entry( __string(device, dev_name(ar->dev)) __string(driver, dev_driver_string(ar->dev)) + __field(u8, hw_type); __field(u16, buf_len) __dynamic_array(u8, pktlog, buf_len) ), @@ -284,14 +288,16 @@ TRACE_EVENT(ath10k_htt_pktlog, TP_fast_assign( __assign_str(device, dev_name(ar->dev)); __assign_str(driver, dev_driver_string(ar->dev)); + __entry->hw_type = ar->hw_rev; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(pktlog), buf, buf_len); ), TP_printk( - "%s %s size %hu", + "%s %s %d size %hu", __get_str(driver), __get_str(device), + __entry->hw_type, __entry->buf_len ) ); @@ -440,6 +446,7 @@ TRACE_EVENT(ath10k_htt_rx_desc, TP_STRUCT__entry( __string(device, dev_name(ar->dev)) __string(driver, dev_driver_string(ar->dev)) + __field(u8, hw_type); __field(u16, len) __dynamic_array(u8, rxdesc, len) ), @@ -447,14 +454,16 @@ TRACE_EVENT(ath10k_htt_rx_desc, TP_fast_assign( __assign_str(device, dev_name(ar->dev)); __assign_str(driver, dev_driver_string(ar->dev)); + __entry->hw_type = ar->hw_rev; __entry->len = len; memcpy(__get_dynamic_array(rxdesc), data, len); ), TP_printk( - "%s %s rxdesc len %d", + "%s %s %d rxdesc len %d", __get_str(driver), __get_str(device), + __entry->hw_type, __entry->len ) ); -- cgit v1.2.3 From 22baa98097df3eb92a51e8661fda5dd7c0f1eb93 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Wed, 10 Feb 2016 11:58:55 -0500 Subject: ath10k: fix erroneous return value The ath10k_pci_hif_exchange_bmi_msg() function may return the positive value EIO instead of -EIO in case of error. Signed-off-by: Anton Protopopov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0e338b657210..b3cff1d3364a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1772,7 +1772,7 @@ int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, DMA_FROM_DEVICE); ret = dma_mapping_error(ar->dev, resp_paddr); if (ret) { - ret = EIO; + ret = -EIO; goto err_req; } -- cgit v1.2.3 From e7827e512af01c6220e2f1cc53853f11cd742eef Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 12 Feb 2016 11:40:58 +0530 Subject: ath10k: reduce rx_lock contention for htt rx indication Received frame indications are queued into a skb list and latest processed by txrx tasklet. This skb queue is protected by htt rx lock. Since the entire rx processing till delivering frame to mac80211 and replenish tasks are processed under rx_lock protection, there might be some delay in queuing newly received rx frame into that list on multicore systems. Optimize this by using skb list lock while accessing rx completion queue instead of htt rx lock. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index bf778f291133..a31de7b82da2 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2011,9 +2011,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } case HTT_T2H_MSG_TYPE_RX_IND: - spin_lock_bh(&htt->rx_ring.lock); - __skb_queue_tail(&htt->rx_compl_q, skb); - spin_unlock_bh(&htt->rx_ring.lock); + skb_queue_tail(&htt->rx_compl_q, skb); tasklet_schedule(&htt->txrx_compl_task); return; case HTT_T2H_MSG_TYPE_PEER_MAP: { @@ -2111,9 +2109,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: { - spin_lock_bh(&htt->rx_ring.lock); - __skb_queue_tail(&htt->rx_in_ord_compl_q, skb); - spin_unlock_bh(&htt->rx_ring.lock); + skb_queue_tail(&htt->rx_in_ord_compl_q, skb); tasklet_schedule(&htt->txrx_compl_task); return; } @@ -2170,16 +2166,18 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) dev_kfree_skb_any(skb); } - spin_lock_bh(&htt->rx_ring.lock); - while ((skb = __skb_dequeue(&htt->rx_compl_q))) { + while ((skb = skb_dequeue(&htt->rx_compl_q))) { resp = (struct htt_resp *)skb->data; + spin_lock_bh(&htt->rx_ring.lock); ath10k_htt_rx_handler(htt, &resp->rx_ind); + spin_unlock_bh(&htt->rx_ring.lock); dev_kfree_skb_any(skb); } - while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) { + while ((skb = skb_dequeue(&htt->rx_in_ord_compl_q))) { + spin_lock_bh(&htt->rx_ring.lock); ath10k_htt_rx_in_ord_ind(ar, skb); + spin_unlock_bh(&htt->rx_ring.lock); dev_kfree_skb_any(skb); } - spin_unlock_bh(&htt->rx_ring.lock); } -- cgit v1.2.3 From da6416cac6b9439167964cae1302d9cfe764bf1d Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 12 Feb 2016 11:40:59 +0530 Subject: ath10k: process htt rx indication as batch mode On multicore systems, it is possible that txrx tasket can run in parallel with pci tasklet (i.e smp affinity of ath10k irq is assigned to multiple CPUs). Feeding and consuming from the same rx completion list leads to txrx tasklet runs for longer period. Prevent this by processing a snapshot of rx queue by moving list into temporary list. Consecutive received frames will be processed in next batch. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index a31de7b82da2..ae9b686a4e91 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2151,22 +2151,34 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) struct ath10k_htt *htt = (struct ath10k_htt *)ptr; struct ath10k *ar = htt->ar; struct sk_buff_head tx_q; + struct sk_buff_head rx_q; + struct sk_buff_head rx_ind_q; struct htt_resp *resp; struct sk_buff *skb; unsigned long flags; __skb_queue_head_init(&tx_q); + __skb_queue_head_init(&rx_q); + __skb_queue_head_init(&rx_ind_q); spin_lock_irqsave(&htt->tx_compl_q.lock, flags); skb_queue_splice_init(&htt->tx_compl_q, &tx_q); spin_unlock_irqrestore(&htt->tx_compl_q.lock, flags); + spin_lock_irqsave(&htt->rx_compl_q.lock, flags); + skb_queue_splice_init(&htt->rx_compl_q, &rx_q); + spin_unlock_irqrestore(&htt->rx_compl_q.lock, flags); + + spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags); + skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q); + spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags); + while ((skb = __skb_dequeue(&tx_q))) { ath10k_htt_rx_frm_tx_compl(htt->ar, skb); dev_kfree_skb_any(skb); } - while ((skb = skb_dequeue(&htt->rx_compl_q))) { + while ((skb = __skb_dequeue(&rx_q))) { resp = (struct htt_resp *)skb->data; spin_lock_bh(&htt->rx_ring.lock); ath10k_htt_rx_handler(htt, &resp->rx_ind); @@ -2174,7 +2186,7 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) dev_kfree_skb_any(skb); } - while ((skb = skb_dequeue(&htt->rx_in_ord_compl_q))) { + while ((skb = __skb_dequeue(&rx_ind_q))) { spin_lock_bh(&htt->rx_ring.lock); ath10k_htt_rx_in_ord_ind(ar, skb); spin_unlock_bh(&htt->rx_ring.lock); -- cgit v1.2.3 From af9a6a3ad04cb042fe1b723335c411c1ab9b7959 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 23 Feb 2016 12:19:57 +0530 Subject: ath10k: reduce number of peers to support peer stats feature To enable per peer stats feature we are reducing the number of peers. Firmware has introduced tx stats feature. We have memory limitation in firmware to add these additional bytes. These are the new variables introduced in the firmware. ======== ======================= Variable Bytes required/per rate ======== ======================= TX success packets 1 TX failed packets 1 Retry packets 1 Success bytes 2 TX failed bytes 2 Retry bytes 2 Tx duration 4 Rate 1 Bw and AMPDU flags 1 Total 16 (because of allocation in word pattern) Firmware sends these tx_stats in pktlog. If we consider 4 feedbacks at a time, Frimware need about ~1K memory for coding and 8192 bytes required / per rate [ 4*16*128(peers)]. To accommodate this firmware needs to reduce 10 peers. This fixes a firmware crash with firmware-5.bin_10.2.4.70.22-2. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 9 +++++++-- drivers/net/wireless/ath/ath10k/hw.h | 5 +++++ drivers/net/wireless/ath/ath10k/wmi.c | 10 ++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 4d3176492ae7..c84c2d30ef1f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1509,8 +1509,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: case ATH10K_FW_WMI_OP_VERSION_10_2_4: - ar->max_num_peers = TARGET_10X_NUM_PEERS; - ar->max_num_stations = TARGET_10X_NUM_STATIONS; + if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { + ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS; + ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS; + } else { + ar->max_num_peers = TARGET_10X_NUM_PEERS; + ar->max_num_stations = TARGET_10X_NUM_STATIONS; + } ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 2dece8db83f8..f0cfbc745c97 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -375,14 +375,19 @@ enum ath10k_hw_4addr_pad { #define TARGET_10X_MAC_AGGR_DELIM 0 #define TARGET_10X_AST_SKID_LIMIT 128 #define TARGET_10X_NUM_STATIONS 128 +#define TARGET_10X_TX_STATS_NUM_STATIONS 118 #define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \ (TARGET_10X_NUM_VDEVS)) +#define TARGET_10X_TX_STATS_NUM_PEERS ((TARGET_10X_TX_STATS_NUM_STATIONS) + \ + (TARGET_10X_NUM_VDEVS)) #define TARGET_10X_NUM_OFFLOAD_PEERS 0 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_10X_NUM_PEER_KEYS 2 #define TARGET_10X_NUM_TIDS_MAX 256 #define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \ (TARGET_10X_NUM_PEERS) * 2) +#define TARGET_10X_TX_STATS_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \ + (TARGET_10X_TX_STATS_NUM_PEERS) * 2) #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1ce67423224a..70261387d1a5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5516,9 +5516,15 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) u32 len, val, features; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); - config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS); - config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); + if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { + config.num_peers = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_PEERS); + config.num_tids = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_TIDS); + } else { + config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); + config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); + } + config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT); config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK); config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK); -- cgit v1.2.3 From c28e6f06ff401ce8f37d58ff6d8123664cd65a51 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Tue, 23 Feb 2016 12:58:36 +0530 Subject: ath10k: fix sanity check on enabling btcoex via debugfs First check for the device state before enabling / disabling btcoex, also return a proper error value. Enabling / disabling btcoex ideally does a f/w + ath10k_core_restart so the checks that are applicable for 'simulate_fw_crash' shall be applicable for this as well Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index a633152787e0..076d29b53ddf 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2114,6 +2114,7 @@ static ssize_t ath10k_write_btcoex(struct file *file, struct ath10k *ar = file->private_data; char buf[32]; size_t buf_size; + int ret = 0; bool val; buf_size = min(count, (sizeof(buf) - 1)); @@ -2127,6 +2128,12 @@ static ssize_t ath10k_write_btcoex(struct file *file, mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_RESTARTED) { + ret = -ENETDOWN; + goto exit; + } + if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) goto exit; @@ -2135,17 +2142,15 @@ static ssize_t ath10k_write_btcoex(struct file *file, else clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); - if (ar->state != ATH10K_STATE_ON) - goto exit; - ath10k_info(ar, "restarting firmware due to btcoex change"); queue_work(ar->workqueue, &ar->restart_work); + ret = count; exit: mutex_unlock(&ar->conf_mutex); - return count; + return ret; } static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf, -- cgit v1.2.3 From 82def495d118c6d36300c1cf2448c276273be603 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Fri, 5 Feb 2016 09:45:50 +0800 Subject: ath9k: make NF load complete quickly and reliably Make NF load complete quickly and reliably. NF load execution is delayed by HW to end of frame if frame Rx or Tx is ongoing. Increasing timeout to max frame duration. If NF cal is ongoing before NF load, stop it before load, and restart it afterwards. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/calib.c | 38 ++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 3e2e24e4843f..37f6d66d1671 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; struct ath_common *common = ath9k_hw_common(ah); s16 default_nf = ath9k_hw_get_default_nf(ah, chan); + u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL); if (ah->caldata) h = ah->caldata->nfCalHist; @@ -263,6 +264,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) } } + /* + * stop NF cal if ongoing to ensure NF load completes immediately + * (or after end rx/tx frame if ongoing) + */ + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + REG_RMW_BUFFER_FLUSH(ah); + ENABLE_REG_RMW_BUFFER(ah); + } + /* * Load software filtered NF value into baseband internal minCCApwr * variable. @@ -276,17 +287,32 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) /* * Wait for load to complete, should be fast, a few 10s of us. - * The max delay was changed from an original 250us to 10000us - * since 250us often results in NF load timeout and causes deaf - * condition during stress testing 12/12/2009 + * The max delay was changed from an original 250us to 22.2 msec. + * This would increase timeout to the longest possible frame + * (11n max length 22.1 msec) */ - for (j = 0; j < 10000; j++) { + for (j = 0; j < 22200; j++) { if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) + AR_PHY_AGC_CONTROL_NF) == 0) break; udelay(10); } + /* + * Restart NF so it can continue. + */ + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { + ENABLE_REG_RMW_BUFFER(ah); + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF) + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF) + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + REG_RMW_BUFFER_FLUSH(ah); + } + /* * We timed out waiting for the noisefloor to load, probably due to an * in-progress rx. Simply return here and allow the load plenty of time @@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) * here, the baseband nf cal will just be capped by our present * noisefloor until the next calibration timer. */ - if (j == 10000) { + if (j == 22200) { ath_dbg(common, ANY, "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", REG_READ(ah, AR_PHY_AGC_CONTROL)); -- cgit v1.2.3 From e9a26010f607621597f25e55d94faf85a2d0d5a4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 12 Feb 2016 12:55:21 +0100 Subject: ath9k: reduce stack usage in ar9003_aic_cal_post_process In some configurations, this function uses more than the warning limit of 1024 bytes: drivers/net/wireless/ath/ath9k/ar9003_aic.c: In function 'ar9003_aic_cal_post_process': drivers/net/wireless/ath/ath9k/ar9003_aic.c:434:1: error: the frame size of 1040 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] It turns out that there are two large arrays on the stack here, but almost all the data in them is never used outside of the loop in which it gets written, so we can replace the array with a single instance. The .valid flag is used later, so I'm replacing the array of structures with an array of bools. An obvious follow-up optimization would be to replace it with a bitmask and set_bit()/find_first_bit()/ find_last_bit()/... operations. However, I have not tested this patch, so I sticked to the simpler transformation that does the job of reducing the stack usage to a harmless level. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 79 +++++++++++++++-------------- drivers/net/wireless/ath/ath9k/ar9003_aic.h | 1 - 2 files changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 1db119d77783..547cd46da260 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -53,19 +53,19 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) return true; } -static int16_t ar9003_aic_find_valid(struct ath_aic_sram_info *cal_sram, +static int16_t ar9003_aic_find_valid(bool *cal_sram_valid, bool dir, u8 index) { int16_t i; if (dir) { for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) { - if (cal_sram[i].valid) + if (cal_sram_valid[i]) break; } } else { for (i = index - 1; i >= 0; i--) { - if (cal_sram[i].valid) + if (cal_sram_valid[i]) break; } } @@ -264,7 +264,7 @@ static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) static bool ar9003_aic_cal_post_process(struct ath_hw *ah) { struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; - struct ath_aic_sram_info cal_sram[ATH_AIC_MAX_BT_CHANNEL]; + bool cal_sram_valid[ATH_AIC_MAX_BT_CHANNEL]; struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL]; u32 dir_path_gain_idx, quad_path_gain_idx, value; u32 fixed_com_att_db; @@ -272,33 +272,34 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) int16_t i; bool ret = true; - memset(&cal_sram, 0, sizeof(cal_sram)); + memset(&cal_sram_valid, 0, sizeof(cal_sram_valid)); memset(&aic_sram, 0, sizeof(aic_sram)); for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + struct ath_aic_sram_info sram; value = aic->aic_sram[i]; - cal_sram[i].valid = + cal_sram_valid[i] = sram.valid = MS(value, AR_PHY_AIC_SRAM_VALID); - cal_sram[i].rot_quad_att_db = + sram.rot_quad_att_db = MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB); - cal_sram[i].vga_quad_sign = + sram.vga_quad_sign = MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN); - cal_sram[i].rot_dir_att_db = + sram.rot_dir_att_db = MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB); - cal_sram[i].vga_dir_sign = + sram.vga_dir_sign = MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN); - cal_sram[i].com_att_6db = + sram.com_att_6db = MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB); - if (cal_sram[i].valid) { - dir_path_gain_idx = cal_sram[i].rot_dir_att_db + - com_att_db_table[cal_sram[i].com_att_6db]; - quad_path_gain_idx = cal_sram[i].rot_quad_att_db + - com_att_db_table[cal_sram[i].com_att_6db]; + if (sram.valid) { + dir_path_gain_idx = sram.rot_dir_att_db + + com_att_db_table[sram.com_att_6db]; + quad_path_gain_idx = sram.rot_quad_att_db + + com_att_db_table[sram.com_att_6db]; - dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1; - quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1; + dir_path_sign = (sram.vga_dir_sign) ? 1 : -1; + quad_path_sign = (sram.vga_quad_sign) ? 1 : -1; aic_sram[i].dir_path_gain_lin = dir_path_sign * aic_lin_table[dir_path_gain_idx]; @@ -310,16 +311,16 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { int16_t start_idx, end_idx; - if (cal_sram[i].valid) + if (cal_sram_valid[i]) continue; - start_idx = ar9003_aic_find_valid(cal_sram, 0, i); - end_idx = ar9003_aic_find_valid(cal_sram, 1, i); + start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i); + end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i); if (start_idx < 0) { /* extrapolation */ start_idx = end_idx; - end_idx = ar9003_aic_find_valid(cal_sram, 1, start_idx); + end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, start_idx); if (end_idx < 0) { ret = false; @@ -342,7 +343,7 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) if (end_idx < 0) { /* extrapolation */ - end_idx = ar9003_aic_find_valid(cal_sram, 0, start_idx); + end_idx = ar9003_aic_find_valid(cal_sram_valid, 0, start_idx); if (end_idx < 0) { ret = false; @@ -378,19 +379,21 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) } /* From dir/quad_path_gain_lin to sram. */ - i = ar9003_aic_find_valid(cal_sram, 1, 0); + i = ar9003_aic_find_valid(cal_sram_valid, 1, 0); if (i < 0) { i = 0; ret = false; } - fixed_com_att_db = com_att_db_table[cal_sram[i].com_att_6db]; + fixed_com_att_db = com_att_db_table[MS(aic->aic_sram[i], + AR_PHY_AIC_SRAM_COM_ATT_6DB)]; for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { int16_t rot_dir_path_att_db, rot_quad_path_att_db; + struct ath_aic_sram_info sram; - aic_sram[i].sram.vga_dir_sign = + sram.vga_dir_sign = (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0; - aic_sram[i].sram.vga_quad_sign= + sram.vga_quad_sign = (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0; rot_dir_path_att_db = @@ -400,33 +403,31 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) - fixed_com_att_db; - aic_sram[i].sram.com_att_6db = + sram.com_att_6db = ar9003_aic_find_index(1, fixed_com_att_db); - aic_sram[i].sram.valid = 1; + sram.valid = 1; - aic_sram[i].sram.rot_dir_att_db = + sram.rot_dir_att_db = min(max(rot_dir_path_att_db, (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB), ATH_AIC_MAX_ROT_DIR_ATT_DB); - aic_sram[i].sram.rot_quad_att_db = + sram.rot_quad_att_db = min(max(rot_quad_path_att_db, (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB), ATH_AIC_MAX_ROT_QUAD_ATT_DB); - } - for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { - aic->aic_sram[i] = (SM(aic_sram[i].sram.vga_dir_sign, + aic->aic_sram[i] = (SM(sram.vga_dir_sign, AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | - SM(aic_sram[i].sram.vga_quad_sign, + SM(sram.vga_quad_sign, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) | - SM(aic_sram[i].sram.com_att_6db, + SM(sram.com_att_6db, AR_PHY_AIC_SRAM_COM_ATT_6DB) | - SM(aic_sram[i].sram.valid, + SM(sram.valid, AR_PHY_AIC_SRAM_VALID) | - SM(aic_sram[i].sram.rot_dir_att_db, + SM(sram.rot_dir_att_db, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) | - SM(aic_sram[i].sram.rot_quad_att_db, + SM(sram.rot_quad_att_db, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB)); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h index 86f40644be43..9512c63799f2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -50,7 +50,6 @@ struct ath_aic_sram_info { struct ath_aic_out_info { int16_t dir_path_gain_lin; int16_t quad_path_gain_lin; - struct ath_aic_sram_info sram; }; u8 ar9003_aic_calibration(struct ath_hw *ah); -- cgit v1.2.3 From 25c0f301425cecdc51d7cc6eb4fb163d464236bc Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Thu, 18 Feb 2016 17:20:02 +0800 Subject: ath9k: clear bb filter calibration power threshold JP WiFi certification for bandwidth of channel 14 failed, the OBW is lower than the requirement. Clear the bb filter calibration power threshold to increase OBW(+2). The fix only for qca9531 chip now. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 7 ++++++- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index abd964691d8c..06c1ca6e8290 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -976,9 +976,14 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, /* * JAPAN regulatory. */ - if (chan->channel == 2484) + if (chan->channel == 2484) { ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); + if (AR_SREV_9531(ah)) + REG_RMW_FIELD(ah, AR_PHY_FCAL_2_0, + AR_PHY_FLC_PWR_THRESH, 0); + } + ah->modes_index = modesIndex; ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index c5f8bc4b5595..566da789f97e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -487,6 +487,9 @@ #define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150) #define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158) +#define AR_PHY_FLC_PWR_THRESH 7 +#define AR_PHY_FLC_PWR_THRESH_S 0 + #define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3 #define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0 -- cgit v1.2.3 From 6b163a85478b27748bad219fe3ead7ac87217265 Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Thu, 3 Mar 2016 01:16:55 +0000 Subject: mac80211_hwsim: use reset to set mac header Since offset is zero, it's not necessary to use set function. Reset function is straightforward, and will remove the unnecessary add operation in set function. Signed-off-by: Zhang Shengju Signed-off-by: David S. Miller --- drivers/net/wireless/mac80211_hwsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a723a85f5635..e85e0737771c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -844,7 +844,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, hdr->rt_chbitmask = cpu_to_le16(flags); skb->dev = hwsim_mon; - skb_set_mac_header(skb, 0); + skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); @@ -887,7 +887,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, memcpy(hdr11->addr1, addr, ETH_ALEN); skb->dev = hwsim_mon; - skb_set_mac_header(skb, 0); + skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); -- cgit v1.2.3 From 4479a899f75cdbd0406d29701d459be5cadaf00b Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 8 Feb 2016 11:18:46 +0200 Subject: iwlwifi: pcie: forbid RTPM on device removal The pci driver keeps any unbound device in active state and forbids runtime PM. When our driver gets probed, we take control of the state. When the device is released (i.e. during unbind or module removal), we should return the state to what it was before. To do so, we need to forbid RTPM in the driver remove op. Additionally, remove an unnecessary pm_runtime_disable() call, move the initial ref_count setting to a better place and add some comments explaining what is going on. Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 28 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ------ 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index d33b6baf5f98..05b968506836 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -631,13 +631,31 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* if RTPM is in use, enable it in our device */ if (iwl_trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) { + /* We explicitly set the device to active here to + * clear contingent errors. + */ pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, iwlwifi_mod_params.d0i3_entry_delay); pm_runtime_use_autosuspend(&pdev->dev); + + /* We are not supposed to call pm_runtime_allow() by + * ourselves, but let userspace enable runtime PM via + * sysfs. However, since we don't enable this from + * userspace yet, we need to allow/forbid() ourselves. + */ pm_runtime_allow(&pdev->dev); } + /* The PCI device starts with a reference taken and we are + * supposed to release it here. But to simplify the + * interaction with the opmode, we don't do it now, but let + * the opmode release it when it's ready. To account for this + * reference, we start with ref_count set to 1. + */ + trans_pcie->ref_count = 1; + return 0; out_free_drv: @@ -652,7 +670,17 @@ static void iwl_pci_remove(struct pci_dev *pdev) struct iwl_trans *trans = pci_get_drvdata(pdev); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + /* if RTPM was in use, restore it to the state before probe */ + if (trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) { + /* We should not call forbid here, but we do for now. + * Check the comment to pm_runtime_allow() in + * iwl_pci_probe(). + */ + pm_runtime_forbid(trans->dev); + } + iwl_drv_stop(trans_pcie->drv); + iwl_trans_pcie_free(trans); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index e67957d6ac79..eb39c7e09781 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1646,9 +1646,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans->command_groups = trans_cfg->command_groups; trans->command_groups_size = trans_cfg->command_groups_size; - /* init ref_count to 1 (should be cleared when ucode is loaded) */ - trans_pcie->ref_count = 1; - /* Initialize NAPI here - it should be before registering to mac80211 * in the opmode but after the HW struct is allocated. * As this function may be called again in some corner cases don't @@ -1663,9 +1660,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; - /* TODO: check if this is really needed */ - pm_runtime_disable(trans->dev); - iwl_pcie_synchronize_irqs(trans); iwl_pcie_tx_free(trans); -- cgit v1.2.3 From d56daea43c5a5d72e67ac60d97734d5823b457d6 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 15 Feb 2016 19:30:49 +0200 Subject: iwlwifi: pcie: refactor RXBs reclaiming code Change the code to move rxbs directly from the allocator's list to the queue's free list. This makes the code more readable, saves the interim array and the double loop over the free RBs. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 75 ++++++++++++---------------- 1 file changed, 33 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 489b07a9e471..a310fd265e24 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -539,40 +539,46 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) } /* - * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages + * iwl_pcie_rx_allocator_get - returns the pre-allocated pages .* .* Called by queue when the queue posted allocation request and * has freed 8 RBDs in order to restock itself. + * This function directly moves the allocated RBs to the queue's ownership + * and updates the relevant counters. */ -static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans, - struct iwl_rx_mem_buffer - *out[RX_CLAIM_REQ_ALLOC]) +static void iwl_pcie_rx_allocator_get(struct iwl_trans *trans, + struct iwl_rxq *rxq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; int i; + lockdep_assert_held(&rxq->lock); + /* * atomic_dec_if_positive returns req_ready - 1 for any scenario. * If req_ready is 0 atomic_dec_if_positive will return -1 and this - * function will return -ENOMEM, as there are no ready requests. + * function will return early, as there are no ready requests. * atomic_dec_if_positive will perofrm the *actual* decrement only if * req_ready > 0, i.e. - there are ready requests and the function * hands one request to the caller. */ if (atomic_dec_if_positive(&rba->req_ready) < 0) - return -ENOMEM; + return; spin_lock(&rba->lock); for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) { /* Get next free Rx buffer, remove it from free list */ - out[i] = list_first_entry(&rba->rbd_allocated, - struct iwl_rx_mem_buffer, list); - list_del(&out[i]->list); + struct iwl_rx_mem_buffer *rxb = + list_first_entry(&rba->rbd_allocated, + struct iwl_rx_mem_buffer, list); + + list_move(&rxb->list, &rxq->rx_free); } spin_unlock(&rba->lock); - return 0; + rxq->used_count -= RX_CLAIM_REQ_ALLOC; + rxq->free_count += RX_CLAIM_REQ_ALLOC; } static void iwl_pcie_rx_allocator_work(struct work_struct *data) @@ -1149,7 +1155,7 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq[queue]; - u32 r, i, j, count = 0; + u32 r, i, count = 0; bool emergency = false; restart: @@ -1193,39 +1199,24 @@ restart: i = (i + 1) & (rxq->queue_size - 1); - /* If we have RX_CLAIM_REQ_ALLOC released rx buffers - - * try to claim the pre-allocated buffers from the allocator */ - if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) { + /* + * If we have RX_CLAIM_REQ_ALLOC released rx buffers - + * try to claim the pre-allocated buffers from the allocator. + * If not ready - will try to reclaim next time. + * There is no need to reschedule work - allocator exits only + * on success + */ + if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) + iwl_pcie_rx_allocator_get(trans, rxq); + + if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && !emergency) { struct iwl_rb_allocator *rba = &trans_pcie->rba; - struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC]; - - if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && - !emergency) { - /* Add the remaining 6 empty RBDs - * for allocator use - */ - spin_lock(&rba->lock); - list_splice_tail_init(&rxq->rx_used, - &rba->rbd_empty); - spin_unlock(&rba->lock); - } - /* If not ready - continue, will try to reclaim later. - * No need to reschedule work - allocator exits only on - * success */ - if (!iwl_pcie_rx_allocator_get(trans, out)) { - /* If success - then RX_CLAIM_REQ_ALLOC - * buffers were retrieved and should be added - * to free list */ - rxq->used_count -= RX_CLAIM_REQ_ALLOC; - for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) { - list_add_tail(&out[j]->list, - &rxq->rx_free); - rxq->free_count++; - } - } - } - if (emergency) { + /* Add the remaining empty RBDs for allocator use */ + spin_lock(&rba->lock); + list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); + spin_unlock(&rba->lock); + } else if (emergency) { count++; if (count == 8) { count = 0; -- cgit v1.2.3 From e5f91d91ac2e09f93f58ab8f6813d12f2b3afa03 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 2 Mar 2016 15:17:28 +0200 Subject: iwlwifi: pcie: set RB chunk size back to 64 128 byte chunk size is supported only on PCIe and not on IOSF. For now, change it back to 64 byte. Reported-by: Oren Givon Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a310fd265e24..509f79003241 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -801,11 +801,10 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) /* * Activate DMA snooping. - * Set RX DMA chunk size to 128 bit + * Set RX DMA chunk size to 64B * Default queue is 0 */ iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP | - RFH_GEN_CFG_RB_CHUNK_SIZE | (DEFAULT_RXQ_NUM << RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) | RFH_GEN_CFG_SERVICE_DMA_SNOOP); /* Enable the relevant rx queues */ -- cgit v1.2.3 From 91f66a3c672065a3aca387ca7e0028504bb8f457 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 28 Feb 2016 10:15:08 +0200 Subject: iwlwifi: mvm: avoid panics with thermal device usage Thermal zone device registration can fail, and in this case we don't want to remove WiFi functionality. This is why the thermal zone registration function is void, and the flows continue even if the thermal zone device registration failed. Same applies for the cooling device. This means that we at least need to remember that the thermal zone device didn't register properly and take the minimal precautions to avoid panic'ing when we access it. This was missing. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 57 +++++++++++++++------------- 2 files changed, 31 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ab410b4659f3..b869db9afc52 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1575,7 +1575,6 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp); void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm); -int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm); int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget); /* Location Aware Regulatory */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 999bcb898be8..0a02e9835d6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -211,10 +211,14 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) * the firmware and hence to take the mutex. * Avoid the deadlock by unlocking the mutex here. */ - mutex_unlock(&mvm->mutex); - thermal_notify_framework(mvm->tz_device.tzone, - mvm->tz_device.fw_trips_index[ths_crossed]); - mutex_lock(&mvm->mutex); + if (mvm->tz_device.tzone) { + struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device; + + mutex_unlock(&mvm->mutex); + thermal_notify_framework(tz_dev->tzone, + tz_dev->fw_trips_index[ths_crossed]); + mutex_lock(&mvm->mutex); + } #endif /* CONFIG_THERMAL */ } @@ -520,16 +524,20 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); + if (!mvm->tz_device.tzone) + return -EINVAL; + /* The driver holds array of temperature trips that are unsorted * and uncompressed, the FW should get it compressed and sorted */ /* compress temp_trips to cmd array, remove uninitialized values*/ - for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) + for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) { if (mvm->tz_device.temp_trips[i] != S16_MIN) { cmd.thresholds[idx++] = cpu_to_le16(mvm->tz_device.temp_trips[i]); } + } cmd.num_temps = cpu_to_le32(idx); if (!idx) @@ -696,6 +704,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) IWL_DEBUG_TEMP(mvm, "Failed to register to thermal zone (err = %ld)\n", PTR_ERR(mvm->tz_device.tzone)); + mvm->tz_device.tzone = NULL; return; } @@ -750,6 +759,10 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget) return ret; } + /* can happen if the registration failed */ + if (!mvm->cooling_dev.cdev) + return -EINVAL; + if (op == CTDP_CMD_OPERATION_START) mvm->cooling_dev.cur_state = budget; @@ -812,15 +825,12 @@ static struct thermal_cooling_device_ops tcooling_ops = { .set_cur_state = iwl_mvm_tcool_set_cur_state, }; -int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm) +static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm) { char name[] = "iwlwifi"; - if (!iwl_mvm_is_ctdp_supported(mvm)) { - mvm->cooling_dev.cdev = NULL; - - return 0; - } + if (!iwl_mvm_is_ctdp_supported(mvm)) + return; BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); @@ -833,34 +843,29 @@ int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm) IWL_DEBUG_TEMP(mvm, "Failed to register to cooling device (err = %ld)\n", PTR_ERR(mvm->cooling_dev.cdev)); - return PTR_ERR(mvm->cooling_dev.cdev); + mvm->cooling_dev.cdev = NULL; + return; } - - return 0; } static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm) { - if (!iwl_mvm_is_tt_in_fw(mvm)) + if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone) return; - if (mvm->tz_device.tzone) { - IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n"); - thermal_zone_device_unregister(mvm->tz_device.tzone); - mvm->tz_device.tzone = NULL; - } + IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n"); + thermal_zone_device_unregister(mvm->tz_device.tzone); + mvm->tz_device.tzone = NULL; } static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm) { - if (!iwl_mvm_is_ctdp_supported(mvm)) + if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev) return; - if (mvm->cooling_dev.cdev) { - IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n"); - thermal_cooling_device_unregister(mvm->cooling_dev.cdev); - mvm->cooling_dev.cdev = NULL; - } + IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n"); + thermal_cooling_device_unregister(mvm->cooling_dev.cdev); + mvm->cooling_dev.cdev = NULL; } #endif /* CONFIG_THERMAL */ -- cgit v1.2.3 From afd5b1704cb15eabc4358b7b0dd7f33099408eaa Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 1 Mar 2016 12:18:22 +0200 Subject: iwlwifi: refactor the code that reads the MAC address from the NVM It makes it slightly easier to follow. Pass the pointer to the transport which allows to read WFMP_MAC_ADDR_X register only when needed and to use IWL_ERR instead of the less commonly used IWL_ERR_DEV logger macro. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 97 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 5 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 11 +-- 3 files changed, 55 insertions(+), 58 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 348135792f3e..5e6b90da3179 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -7,6 +7,7 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -69,6 +70,7 @@ #include "iwl-drv.h" #include "iwl-modparams.h" #include "iwl-nvm-parse.h" +#include "iwl-prph.h" /* NVM offsets (in words) definitions */ enum wkp_nvm_offsets { @@ -522,27 +524,11 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); } -static void iwl_set_hw_address(const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, - const __le16 *nvm_sec) -{ - const u8 *hw_addr = (const u8 *)(nvm_sec + HW_ADDR); - - /* The byte order is little endian 16 bit, meaning 214365 */ - data->hw_addr[0] = hw_addr[1]; - data->hw_addr[1] = hw_addr[0]; - data->hw_addr[2] = hw_addr[3]; - data->hw_addr[3] = hw_addr[2]; - data->hw_addr[4] = hw_addr[5]; - data->hw_addr[5] = hw_addr[4]; -} - -static void iwl_set_hw_address_family_8000(struct device *dev, +static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *mac_override, - const __le16 *nvm_hw, - __le32 mac_addr0, __le32 mac_addr1) + const __le16 *nvm_hw) { const u8 *hw_addr; @@ -568,11 +554,16 @@ static void iwl_set_hw_address_family_8000(struct device *dev, memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0) return; - IWL_ERR_DEV(dev, - "mac address from nvm override section is not valid\n"); + IWL_ERR(trans, + "mac address from nvm override section is not valid\n"); } if (nvm_hw) { + /* read the mac address from WFMP registers */ + __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans, + WFMP_MAC_ADDR_0)); + __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans, + WFMP_MAC_ADDR_1)); /* read the MAC address from HW resisters */ hw_addr = (const u8 *)&mac_addr0; data->hw_addr[0] = hw_addr[3]; @@ -585,28 +576,50 @@ static void iwl_set_hw_address_family_8000(struct device *dev, data->hw_addr[5] = hw_addr[0]; if (!is_valid_ether_addr(data->hw_addr)) - IWL_ERR_DEV(dev, - "mac address (%pM) from hw section is not valid\n", - data->hw_addr); + IWL_ERR(trans, + "mac address (%pM) from hw section is not valid\n", + data->hw_addr); return; } - IWL_ERR_DEV(dev, "mac address is not found\n"); + IWL_ERR(trans, "mac address is not found\n"); +} + +static void iwl_set_hw_address(struct iwl_trans *trans, + const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, const __le16 *nvm_hw, + const __le16 *mac_override) +{ + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR); + + /* The byte order is little endian 16 bit, meaning 214365 */ + data->hw_addr[0] = hw_addr[1]; + data->hw_addr[1] = hw_addr[0]; + data->hw_addr[2] = hw_addr[3]; + data->hw_addr[3] = hw_addr[2]; + data->hw_addr[4] = hw_addr[5]; + data->hw_addr[5] = hw_addr[4]; + } else { + iwl_set_hw_address_family_8000(trans, cfg, data, + mac_override, nvm_hw); + } } struct iwl_nvm_data * -iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, +iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, - u8 tx_chains, u8 rx_chains, bool lar_fw_supported, - __le32 mac_addr0, __le32 mac_addr1) + u8 tx_chains, u8 rx_chains, bool lar_fw_supported) { + struct device *dev = trans->dev; struct iwl_nvm_data *data; - u32 sku; - u32 radio_cfg; + bool lar_enabled; + u32 sku, radio_cfg; u16 lar_config; + const __le16 *ch_section; if (cfg->device_family != IWL_DEVICE_FAMILY_8000) data = kzalloc(sizeof(*data) + @@ -645,21 +658,16 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { /* Checking for required sections */ if (!nvm_calib) { - IWL_ERR_DEV(dev, - "Can't parse empty Calib NVM sections\n"); + IWL_ERR(trans, + "Can't parse empty Calib NVM sections\n"); kfree(data); return NULL; } /* in family 8000 Xtal calibration values moved to OTP */ data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); - } - - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { - iwl_set_hw_address(cfg, data, nvm_hw); - - iwl_init_sbands(dev, cfg, data, nvm_sw, - tx_chains, rx_chains, lar_fw_supported); + lar_enabled = true; + ch_section = nvm_sw; } else { u16 lar_offset = data->nvm_version < 0xE39 ? NVM_LAR_OFFSET_FAMILY_8000_OLD : @@ -668,16 +676,13 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, lar_config = le16_to_cpup(regulatory + lar_offset); data->lar_enabled = !!(lar_config & NVM_LAR_ENABLED_FAMILY_8000); - - /* MAC address in family 8000 */ - iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, - nvm_hw, mac_addr0, mac_addr1); - - iwl_init_sbands(dev, cfg, data, regulatory, - tx_chains, rx_chains, - lar_fw_supported && data->lar_enabled); + lar_enabled = data->lar_enabled; + ch_section = regulatory; } + iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override); + iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains, + lar_fw_supported && lar_enabled); data->calib_version = 255; return data; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 4e8e0dc474d4..d704d52aa7ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -74,12 +74,11 @@ * later with iwl_free_nvm_data(). */ struct iwl_nvm_data * -iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, +iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, - u8 tx_chains, u8 rx_chains, bool lar_fw_supported, - __le32 mac_addr0, __le32 mac_addr1); + u8 tx_chains, u8 rx_chains, bool lar_fw_supported); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index c446e0da9789..25a98401a64f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -300,7 +300,6 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) struct iwl_nvm_section *sections = mvm->nvm_sections; const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; bool lar_enabled; - __le32 mac_addr0, mac_addr1; /* Checking for required sections */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { @@ -336,12 +335,6 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) if (WARN_ON(!mvm->cfg)) return NULL; - /* read the mac address from WFMP registers */ - mac_addr0 = cpu_to_le32(iwl_trans_read_prph(mvm->trans, - WFMP_MAC_ADDR_0)); - mac_addr1 = cpu_to_le32(iwl_trans_read_prph(mvm->trans, - WFMP_MAC_ADDR_1)); - hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; @@ -354,10 +347,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT); - return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, + return iwl_parse_nvm_data(mvm->trans, mvm->cfg, hw, sw, calib, regulatory, mac_override, phy_sku, mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, - lar_enabled, mac_addr0, mac_addr1); + lar_enabled); } #define MAX_NVM_FILE_LEN 16384 -- cgit v1.2.3 From 04ddc2aacc1c52793c1e30db5073bef6fbc08942 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Thu, 3 Mar 2016 13:31:39 +0200 Subject: iwlwifi: mvm: fix unregistration of thermal in some error flows The call to iwl_mvm_thermal_initialize() was too early in the function. Unregister will be performed when goto out_unregister is called, but as the code was - out_free may be called and leave without unregistering from thermal. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 699a80863e86..4322e8ed1159 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -611,9 +611,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, IWL_INFO(mvm, "Detected %s, REV=0x%X\n", mvm->cfg->name, mvm->trans->hw_rev); - min_backoff = calc_min_backoff(trans, cfg); - iwl_mvm_thermal_initialize(mvm, min_backoff); - if (iwlwifi_mod_params.nvm_file) mvm->nvm_file_name = iwlwifi_mod_params.nvm_file; else @@ -666,6 +663,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (err) goto out_free; + min_backoff = calc_min_backoff(trans, cfg); + iwl_mvm_thermal_initialize(mvm, min_backoff); + err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir); if (err) goto out_unregister; -- cgit v1.2.3 From 30d915c2ecbb60d222f49e8f249d04e208d11ebc Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 3 Mar 2016 16:49:05 +0200 Subject: iwlwifi: mvm: set the correct amsdu enum values The amsdu enum values are off by 1 bit. Fix it. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index eb9b87038e1f..7a16e55df012 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -264,9 +264,8 @@ enum iwl_rx_mpdu_mac_flags2 { }; enum iwl_rx_mpdu_amsdu_info { - IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK = 0x3f, - IWL_RX_MPDU_AMSDU_LAST_SUBFRAME = 0x40, - /* 0x80 bit reserved for now */ + IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK = 0x7f, + IWL_RX_MPDU_AMSDU_LAST_SUBFRAME = 0x80, }; enum iwl_rx_l3l4_flags { -- cgit v1.2.3 From 7c70fee5ae5c4fb542e432599cb85c8031b952a0 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 2 Feb 2016 11:55:53 +0200 Subject: iwlwifi: mvm: extend time event duration Before authentication, we start a time event during which we wait for a beacon in order to sync our timers. If we didn't hear the beacon during this time - we abandon the connection. However, in congested environment, it was observed we might not hear beacons in that time slot. Extend the time event to give the connection a better chance. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 ++---- drivers/net/wireless/intel/iwlwifi/mvm/time-event.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ec6b07282e7d..3590835a308f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2556,10 +2556,8 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS, - 200 + vif->bss_conf.beacon_int); - u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS, - 100 + vif->bss_conf.beacon_int); + u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; + u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS; if (WARN_ON_ONCE(vif->bss_conf.assoc)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 99d9a35ad5b1..3d2e8b6159bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -115,7 +115,7 @@ * needed by the driver. */ -#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500 +#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 600 #define IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400 /** -- cgit v1.2.3 From 7b5acd11a3ffec027abf4df2b30690a974873174 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 11 Feb 2016 10:56:22 -0600 Subject: rtlwifi: rtl8821ae: Silence useless log output When driver rtl8821ae is loaded but not connected to any AP, it logs a "firmware not ready to run" message roughly once a minute. To eliminate logging this massage under normal debug conditions, the degug level needed to print this message is increased. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 525eb234627c..a4fc70e8c9c0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -271,7 +271,7 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) err = _rtl8821ae_fw_free_to_go(hw); if (err) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, "Firmware is not ready to run!\n"); } else { RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, -- cgit v1.2.3 From 9cc3fdc86c6006bae878da6d2d14c1633064a12f Mon Sep 17 00:00:00 2001 From: One Thousand Gnomes Date: Mon, 15 Feb 2016 19:04:56 +0000 Subject: rt2x00: unterminated strlen of user data The buffer needs to be zero terminated in case the user data is not. Otherwise we run off the end of the buffer. Signed-off-by: Alan Cox Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2x00debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 25ee3cb8e982..72ae530e4a3b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -478,7 +478,7 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ { \ struct rt2x00debug_intf *intf = file->private_data; \ const struct rt2x00debug *debug = intf->debug; \ - char line[16]; \ + char line[17]; \ size_t size; \ unsigned int index = intf->offset_##__name; \ __type value; \ @@ -494,7 +494,8 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ \ if (copy_from_user(line, buf, length)) \ return -EFAULT; \ - \ + line[16] = 0; \ + \ size = strlen(line); \ value = simple_strtoul(line, NULL, 0); \ \ -- cgit v1.2.3 From 2f10e50e3d284ba2a4e787bfe19e89770f87a8b3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 15 Feb 2016 21:16:06 +0100 Subject: carl9170: import 1.9.9 firmware headers Import new headers from my firmware branch: Signed-off-by: Christian Lamparter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/carl9170/fwcmd.h | 8 ++++ drivers/net/wireless/ath/carl9170/fwdesc.h | 6 +++ drivers/net/wireless/ath/carl9170/hw.h | 73 +++++++++++++++++++++++++++-- drivers/net/wireless/ath/carl9170/version.h | 6 +-- 4 files changed, 87 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index 9111d4ffc1b3..ea1d80f9a50e 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -56,6 +56,7 @@ enum carl9170_cmd_oids { CARL9170_CMD_RX_FILTER = 0x07, CARL9170_CMD_WOL = 0x08, CARL9170_CMD_TALLY = 0x09, + CARL9170_CMD_WREGB = 0x0a, /* CAM */ CARL9170_CMD_EKEY = 0x10, @@ -123,6 +124,12 @@ struct carl9170_write_reg { } regs[0] __packed; } __packed; +struct carl9170_write_reg_byte { + __le32 addr; + __le32 count; + u8 val[0]; +} __packed; + #define CARL9170FW_PHY_HT_ENABLE 0x4 #define CARL9170FW_PHY_HT_DYN2040 0x8 #define CARL9170FW_PHY_HT_EXT_CHAN_OFF 0x3 @@ -226,6 +233,7 @@ struct carl9170_cmd { struct carl9170_u32_list echo; struct carl9170_reg_list rreg; struct carl9170_write_reg wreg; + struct carl9170_write_reg_byte wregb; struct carl9170_rf_init rf_init; struct carl9170_psm psm; struct carl9170_wol_cmd wol; diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 66848d47c88e..0533f79cb998 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h @@ -81,6 +81,12 @@ enum carl9170fw_feature_list { /* Firmware will pass BA when BARs are queued */ CARL9170FW_RX_BA_FILTER, + /* Firmware has support to write a byte at a time */ + CARL9170FW_HAS_WREGB_CMD, + + /* Pattern generator */ + CARL9170FW_PATTERN_GENERATOR, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index 0db874abde50..08e0ae9c5836 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -453,9 +453,74 @@ #define AR9170_MC_REG_BASE 0x1d1000 #define AR9170_MC_REG_FLASH_WAIT_STATE (AR9170_MC_REG_BASE + 0x000) -#define AR9170_MC_REG_SEEPROM_WP0 (AR9170_MC_REG_BASE + 0x400) -#define AR9170_MC_REG_SEEPROM_WP1 (AR9170_MC_REG_BASE + 0x404) -#define AR9170_MC_REG_SEEPROM_WP2 (AR9170_MC_REG_BASE + 0x408) + +#define AR9170_SPI_REG_BASE (AR9170_MC_REG_BASE + 0x200) +#define AR9170_SPI_REG_CONTROL0 (AR9170_SPI_REG_BASE + 0x000) +#define AR9170_SPI_CONTROL0_BUSY BIT(0) +#define AR9170_SPI_CONTROL0_CMD_GO BIT(1) +#define AR9170_SPI_CONTROL0_PAGE_WR BIT(2) +#define AR9170_SPI_CONTROL0_SEQ_RD BIT(3) +#define AR9170_SPI_CONTROL0_CMD_ABORT BIT(4) +#define AR9170_SPI_CONTROL0_CMD_LEN_S 8 +#define AR9170_SPI_CONTROL0_CMD_LEN 0x00000f00 +#define AR9170_SPI_CONTROL0_RD_LEN_S 12 +#define AR9170_SPI_CONTROL0_RD_LEN 0x00007000 + +#define AR9170_SPI_REG_CONTROL1 (AR9170_SPI_REG_BASE + 0x004) +#define AR9170_SPI_CONTROL1_SCK_RATE BIT(0) +#define AR9170_SPI_CONTROL1_DRIVE_SDO BIT(1) +#define AR9170_SPI_CONTROL1_MODE_SEL_S 2 +#define AR9170_SPI_CONTROL1_MODE_SEL 0x000000c0 +#define AR9170_SPI_CONTROL1_WRITE_PROTECT BIT(4) + +#define AR9170_SPI_REG_COMMAND_PORT0 (AR9170_SPI_REG_BASE + 0x008) +#define AR9170_SPI_COMMAND_PORT0_CMD0_S 0 +#define AR9170_SPI_COMMAND_PORT0_CMD0 0x000000ff +#define AR9170_SPI_COMMAND_PORT0_CMD1_S 8 +#define AR9170_SPI_COMMAND_PORT0_CMD1 0x0000ff00 +#define AR9170_SPI_COMMAND_PORT0_CMD2_S 16 +#define AR9170_SPI_COMMAND_PORT0_CMD2 0x00ff0000 +#define AR9170_SPI_COMMAND_PORT0_CMD3_S 24 +#define AR9170_SPI_COMMAND_PORT0_CMD3 0xff000000 + +#define AR9170_SPI_REG_COMMAND_PORT1 (AR9170_SPI_REG_BASE + 0x00C) +#define AR9170_SPI_COMMAND_PORT1_CMD4_S 0 +#define AR9170_SPI_COMMAND_PORT1_CMD4 0x000000ff +#define AR9170_SPI_COMMAND_PORT1_CMD5_S 8 +#define AR9170_SPI_COMMAND_PORT1_CMD5 0x0000ff00 +#define AR9170_SPI_COMMAND_PORT1_CMD6_S 16 +#define AR9170_SPI_COMMAND_PORT1_CMD6 0x00ff0000 +#define AR9170_SPI_COMMAND_PORT1_CMD7_S 24 +#define AR9170_SPI_COMMAND_PORT1_CMD7 0xff000000 + +#define AR9170_SPI_REG_DATA_PORT (AR9170_SPI_REG_BASE + 0x010) +#define AR9170_SPI_REG_PAGE_WRITE_LEN (AR9170_SPI_REG_BASE + 0x014) + +#define AR9170_EEPROM_REG_BASE (AR9170_MC_REG_BASE + 0x400) +#define AR9170_EEPROM_REG_WP_MAGIC1 (AR9170_EEPROM_REG_BASE + 0x000) +#define AR9170_EEPROM_WP_MAGIC1 0x12345678 + +#define AR9170_EEPROM_REG_WP_MAGIC2 (AR9170_EEPROM_REG_BASE + 0x004) +#define AR9170_EEPROM_WP_MAGIC2 0x55aa00ff + +#define AR9170_EEPROM_REG_WP_MAGIC3 (AR9170_EEPROM_REG_BASE + 0x008) +#define AR9170_EEPROM_WP_MAGIC3 0x13579ace + +#define AR9170_EEPROM_REG_CLOCK_DIV (AR9170_EEPROM_REG_BASE + 0x00C) +#define AR9170_EEPROM_CLOCK_DIV_FAC_S 0 +#define AR9170_EEPROM_CLOCK_DIV_FAC 0x000001ff +#define AR9170_EEPROM_CLOCK_DIV_FAC_39KHZ 0xff +#define AR9170_EEPROM_CLOCK_DIV_FAC_78KHZ 0x7f +#define AR9170_EEPROM_CLOCK_DIV_FAC_312KHZ 0x1f +#define AR9170_EEPROM_CLOCK_DIV_FAC_10MHZ 0x0 +#define AR9170_EEPROM_CLOCK_DIV_SOFT_RST BIT(9) + +#define AR9170_EEPROM_REG_MODE (AR9170_EEPROM_REG_BASE + 0x010) +#define AR9170_EEPROM_MODE_EEPROM_SIZE_16K_PLUS BIT(31) + +#define AR9170_EEPROM_REG_WRITE_PROTECT (AR9170_EEPROM_REG_BASE + 0x014) +#define AR9170_EEPROM_WRITE_PROTECT_WP_STATUS BIT(0) +#define AR9170_EEPROM_WRITE_PROTECT_WP_SET BIT(8) /* Interrupt Controller */ #define AR9170_MAX_INT_SRC 9 @@ -589,11 +654,13 @@ #define AR9170_USB_REG_EP10_MAP (AR9170_USB_REG_BASE + 0x039) #define AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x03f) +#define AR9170_USB_EP_IN_STALL 0x8 #define AR9170_USB_EP_IN_TOGGLE 0x10 #define AR9170_USB_REG_EP_IN_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x03e) #define AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x05f) +#define AR9170_USB_EP_OUT_STALL 0x8 #define AR9170_USB_EP_OUT_TOGGLE 0x10 #define AR9170_USB_REG_EP_OUT_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x05e) diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index 2282847d4bb8..a0410fe8c03a 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H -#define CARL9170FW_VERSION_YEAR 12 -#define CARL9170FW_VERSION_MONTH 12 +#define CARL9170FW_VERSION_YEAR 16 +#define CARL9170FW_VERSION_MONTH 2 #define CARL9170FW_VERSION_DAY 15 -#define CARL9170FW_VERSION_GIT "1.9.7" +#define CARL9170FW_VERSION_GIT "1.9.9" #endif /* __CARL9170_SHARED_VERSION_H */ -- cgit v1.2.3 From 49f86ec21c01b654f6ec47f2f4567f4f9ebaa26b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 15 Feb 2016 16:12:07 -0600 Subject: rtlwifi: Change long delays to sleeps Routine rtl_addr_delay() uses delay statements in code that can sleep. To improve system responsiveness, the various delay statements are changed. In addition, routines rtl_rfreg_delay() and rtl_bb_delay() are rewritten to use the code in rtl_addr_delay() for most of their input values. Suggested-by: Byeoungwook Kim Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/core.c | 44 ++++++++--------------------- 1 file changed, 12 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 16bb57ccf90e..0f48048b8654 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -54,59 +54,39 @@ EXPORT_SYMBOL(channel5g_80m); void rtl_addr_delay(u32 addr) { if (addr == 0xfe) - mdelay(50); + msleep(50); else if (addr == 0xfd) - mdelay(5); + msleep(5); else if (addr == 0xfc) - mdelay(1); + msleep(1); else if (addr == 0xfb) - udelay(50); + usleep_range(50, 100); else if (addr == 0xfa) - udelay(5); + usleep_range(5, 10); else if (addr == 0xf9) - udelay(1); + usleep_range(1, 2); } EXPORT_SYMBOL(rtl_addr_delay); void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, u32 mask, u32 data) { - if (addr == 0xfe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); + if (addr >= 0xf9 && addr <= 0xfe) { + rtl_addr_delay(addr); } else { rtl_set_rfreg(hw, rfpath, addr, mask, data); - udelay(1); + usleep_range(1, 2); } } EXPORT_SYMBOL(rtl_rfreg_delay); void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) { - if (addr == 0xfe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); + if (addr >= 0xf9 && addr <= 0xfe) { + rtl_addr_delay(addr); } else { rtl_set_bbreg(hw, addr, MASKDWORD, data); - udelay(1); + usleep_range(1, 2); } } EXPORT_SYMBOL(rtl_bb_delay); -- cgit v1.2.3 From a9eb0c4b73e7287074dfabd84337ea1a49976a3d Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 17 Feb 2016 11:26:50 +0100 Subject: brcmfmac: change function name for brcmf_cfg80211_wait_vif_event_timeout() Dropping the '_timeout' from the function name as the fact that a timeout value is passed makes it obvious a timeout is used. Also helps to keep code lines a bit shorter and easier to stick to 80 char boundary. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 9 +++++---- .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h | 4 ++-- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 16 ++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index d00c5c1d58bf..5a4a0c49f933 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -564,8 +564,8 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, } /* wait for firmware event */ - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, - BRCMF_VIF_EVENT_TIMEOUT); + err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD, + BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (!err) { brcmf_err("timeout occurred\n"); @@ -6395,8 +6395,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) return armed; } -int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, - u8 action, ulong timeout) + +int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg, + u8 action, ulong timeout) { struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 40efb539ac26..97c327d6d3bb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -402,8 +402,8 @@ bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_vif *vif); bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); -int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, - u8 action, ulong timeout); +int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg, + u8 action, ulong timeout); s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, bool aborted, bool fw_abort); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 821b6494f9d1..de5892a67c22 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1988,8 +1988,8 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, brcmf_cfg80211_arm_vif_event(cfg, NULL); return err; } - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE, - BRCMF_VIF_EVENT_TIMEOUT); + err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE, + BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (!err) { brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); @@ -2090,8 +2090,8 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, } /* wait for firmware event */ - err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD, - BRCMF_VIF_EVENT_TIMEOUT); + err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD, + BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL); brcmf_fweh_p2pdev_setup(pri_ifp, false); if (!err) { @@ -2180,8 +2180,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, } /* wait for firmware event */ - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, - BRCMF_VIF_EVENT_TIMEOUT); + err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD, + BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (!err) { brcmf_err("timeout occurred\n"); @@ -2272,8 +2272,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) } if (!err) { /* wait for firmware event */ - err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, - BRCMF_VIF_EVENT_TIMEOUT); + err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL, + BRCMF_VIF_EVENT_TIMEOUT); if (!err) err = -EIO; else -- cgit v1.2.3 From d536733442d14664437dc9c3ec993d97b5a4f1b1 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:26:51 +0100 Subject: brcmfmac: Limit memory allocs to <64K Some systems have problems with allocating memory allocation larger then 64K. Often on unload/load or suspend/resume a failure is reported: Could not allocate wiphy device. This patch makes the escan intermediate storage buf dynamically allocated, and smaller than 64K. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 18 +++++++++--------- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.h | 11 ++++++----- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5a4a0c49f933..5478128af02b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1125,7 +1125,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, /* Arm scan timeout timer */ mod_timer(&cfg->escan_timeout, jiffies + - WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); + BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); return 0; @@ -3020,7 +3020,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, list = (struct brcmf_scan_results *) cfg->escan_info.escan_buf; - if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) { + if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) { brcmf_err("Buffer is too small: ignoring\n"); goto exit; } @@ -3033,8 +3033,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, bss_info_le)) goto exit; } - memcpy(&(cfg->escan_info.escan_buf[list->buflen]), - bss_info_le, bi_length); + memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le, + bi_length); list->version = le32_to_cpu(bss_info_le->version); list->buflen += bi_length; list->count++; @@ -5402,14 +5402,14 @@ static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) { kfree(cfg->conf); cfg->conf = NULL; - kfree(cfg->escan_ioctl_buf); - cfg->escan_ioctl_buf = NULL; kfree(cfg->extra_buf); cfg->extra_buf = NULL; kfree(cfg->wowl.nd); cfg->wowl.nd = NULL; kfree(cfg->wowl.nd_info); cfg->wowl.nd_info = NULL; + kfree(cfg->escan_info.escan_buf); + cfg->escan_info.escan_buf = NULL; } static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) @@ -5417,9 +5417,6 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL); if (!cfg->conf) goto init_priv_mem_out; - cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); - if (!cfg->escan_ioctl_buf) - goto init_priv_mem_out; cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!cfg->extra_buf) goto init_priv_mem_out; @@ -5431,6 +5428,9 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) GFP_KERNEL); if (!cfg->wowl.nd_info) goto init_priv_mem_out; + cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL); + if (!cfg->escan_info.escan_buf) + goto init_priv_mem_out; return 0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 97c327d6d3bb..01f096f7a089 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -28,8 +28,11 @@ #define WL_ROAM_TRIGGER_LEVEL -75 #define WL_ROAM_DELTA 20 -#define WL_ESCAN_BUF_SIZE (1024 * 64) -#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */ +/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be + * problematic on some systems and should be avoided. + */ +#define BRCMF_ESCAN_BUF_SIZE 65000 +#define BRCMF_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */ #define WL_ESCAN_ACTION_START 1 #define WL_ESCAN_ACTION_CONTINUE 2 @@ -205,7 +208,7 @@ enum wl_escan_state { struct escan_info { u32 escan_state; - u8 escan_buf[WL_ESCAN_BUF_SIZE]; + u8 *escan_buf; struct wiphy *wiphy; struct brcmf_if *ifp; s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, @@ -278,7 +281,6 @@ struct brcmf_cfg80211_wowl { * @escan_info: escan information. * @escan_timeout: Timer for catch scan timeout. * @escan_timeout_work: scan timeout worker. - * @escan_ioctl_buf: dongle command buffer for escan commands. * @vif_list: linked list of vif instances. * @vif_cnt: number of vif instances. * @vif_event: vif event signalling. @@ -309,7 +311,6 @@ struct brcmf_cfg80211_info { struct escan_info escan_info; struct timer_list escan_timeout; struct work_struct escan_timeout_work; - u8 *escan_ioctl_buf; struct list_head vif_list; struct brcmf_cfg80211_vif_event vif_event; struct completion vif_disabled; -- cgit v1.2.3 From 6ea09153b6ccbee79869537ce61f5c16f736d72b Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 17 Feb 2016 11:26:52 +0100 Subject: brcmfmac: check for wowl support before enumerating feature flag In some cases wiphy->wowlan could be NULL if firmware doesn't have the support. Driver should check for support before walking down the feature flags. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5478128af02b..d66f08fa408c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6594,7 +6594,8 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) { wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; #ifdef CONFIG_PM - if (wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT) + if (wiphy->wowlan && + wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT) wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR; #endif } -- cgit v1.2.3 From 73345fd212980d2e28a5c6d83801c903bd773680 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:26:53 +0100 Subject: brcmfmac: Configure country code using device specific settings Country code configuration in a device is a device specific operation. For this the country code as specified by reg notifier (iso3166 alpha2) needs to be translated to a device specific country locale and revision number. This patch adds this translation and puts a placeholder in the device specific settings where the translation table can be stored. Additional patches will be needed to read these tables from for example device platform data. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 75 +++++++++++++++++++--- .../wireless/broadcom/brcm80211/brcmfmac/common.c | 4 +- .../wireless/broadcom/brcm80211/brcmfmac/common.h | 31 +++++++++ .../broadcom/brcm80211/brcmfmac/fwil_types.h | 4 +- 4 files changed, 101 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index d66f08fa408c..2fd18d04b61e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6405,28 +6405,85 @@ int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg, vif_event_equals(event, action), timeout); } +static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2], + struct brcmf_fil_country_le *ccreq) +{ + struct cc_translate *country_codes; + struct cc_entry *cc; + s32 found_index; + int i; + + country_codes = drvr->settings->country_codes; + if (!country_codes) { + brcmf_dbg(TRACE, "No country codes configured for device\n"); + return -EINVAL; + } + + if ((alpha2[0] == ccreq->country_abbrev[0]) && + (alpha2[1] == ccreq->country_abbrev[1])) { + brcmf_dbg(TRACE, "Country code already set\n"); + return -EAGAIN; + } + + found_index = -1; + for (i = 0; i < country_codes->table_size; i++) { + cc = &country_codes->table[i]; + if ((cc->iso3166[0] == '\0') && (found_index == -1)) + found_index = i; + if ((cc->iso3166[0] == alpha2[0]) && + (cc->iso3166[1] == alpha2[1])) { + found_index = i; + break; + } + } + if (found_index == -1) { + brcmf_dbg(TRACE, "No country code match found\n"); + return -EINVAL; + } + memset(ccreq, 0, sizeof(*ccreq)); + ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev); + memcpy(ccreq->ccode, country_codes->table[found_index].cc, + BRCMF_COUNTRY_BUF_SZ); + ccreq->country_abbrev[0] = alpha2[0]; + ccreq->country_abbrev[1] = alpha2[1]; + ccreq->country_abbrev[2] = 0; + + return 0; +} + static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *req) { struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct brcmf_fil_country_le ccreq; + s32 err; int i; - brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator, - req->alpha2[0], req->alpha2[1]); - /* ignore non-ISO3166 country codes */ for (i = 0; i < sizeof(req->alpha2); i++) if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { - brcmf_err("not a ISO3166 code\n"); + brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", + req->alpha2[0], req->alpha2[1]); return; } - memset(&ccreq, 0, sizeof(ccreq)); - ccreq.rev = cpu_to_le32(-1); - memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2)); - if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) { - brcmf_err("firmware rejected country setting\n"); + + brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator, + req->alpha2[0], req->alpha2[1]); + + err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq)); + if (err) { + brcmf_err("Country code iovar returned err = %d\n", err); + return; + } + + err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq); + if (err) + return; + + err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq)); + if (err) { + brcmf_err("Firmware rejected country setting\n"); return; } brcmf_setup_wiphybands(wiphy); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index cfee477a6eb1..8199862c7cdb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -230,10 +230,8 @@ void brcmf_mp_attach(void) int brcmf_mp_device_attach(struct brcmf_pub *drvr) { drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC); - if (!drvr->settings) { - brcmf_err("Failed to alloca storage space for settings\n"); + if (!drvr->settings) return -ENOMEM; - } drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz; drvr->settings->p2p_enable = !!brcmf_p2p_enable; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 3b0a63b98e99..b678b2d60749 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -15,6 +15,8 @@ #ifndef BRCMFMAC_COMMON_H #define BRCMFMAC_COMMON_H +#include "fwil_types.h" + extern const u8 ALLFFMAC[ETH_ALEN]; #define BRCMF_FW_ALTPATH_LEN 256 @@ -38,6 +40,33 @@ struct brcmf_mp_global_t { extern struct brcmf_mp_global_t brcmf_mp_global; +/** + * struct cc_entry - Struct for translating user space country code (iso3166) to + * firmware country code and revision. + * + * @iso3166: iso3166 alpha 2 country code string. + * @cc: firmware country code string. + * @rev: firmware country code revision. + */ +struct cc_entry { + char iso3166[BRCMF_COUNTRY_BUF_SZ]; + char cc[BRCMF_COUNTRY_BUF_SZ]; + s32 rev; +}; + +/** + * struct cc_translate - Struct for translating country codes as set by user + * space to a country code and rev which can be used by + * firmware. + * + * @table_size: number of entries in table (> 0) + * @table: dynamic array of 1 or more elements with translation information. + */ +struct cc_translate { + int table_size; + struct cc_entry table[0]; +}; + /** * struct brcmf_mp_device - Device module paramaters. * @@ -47,6 +76,7 @@ extern struct brcmf_mp_global_t brcmf_mp_global; * @feature_disable: Feature_disable bitmask. * @fcmode: FWS flow control. * @roamoff: Firmware roaming off? + * @country_codes: If available, pointer to struct for translating country codes */ struct brcmf_mp_device { int sdiod_txglomsz; @@ -56,6 +86,7 @@ struct brcmf_mp_device { int fcmode; bool roamoff; bool ignore_probe_fail; + struct cc_translate *country_codes; }; void brcmf_mp_attach(void); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 1afc2ad83b6c..e9e177dad1a6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -134,6 +134,8 @@ #define BRCMF_PFN_MAC_OUI_ONLY BIT(0) #define BRCMF_PFN_SET_MAC_UNASSOC BIT(1) +#define BRCMF_MCSSET_LEN 16 + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { BRCMF_JOIN_PREF_RSSI = 1, @@ -279,7 +281,7 @@ struct brcmf_bss_info_le { __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ u8 flags; /* flags */ u8 reserved[3]; /* Reserved for expansion of BSS properties */ - u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + u8 basic_mcs[BRCMF_MCSSET_LEN]; /* 802.11N BSS required MCS set */ __le16 ie_offset; /* offset at which IEs start, from beginning */ __le32 ie_length; /* byte length of Information Elements */ -- cgit v1.2.3 From 0aedbcaf6f182690790d98d90d5fe1e64c846c34 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:26:54 +0100 Subject: brcmfmac: Add length checks on firmware events Add additional length checks on firmware events to create more robust code. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Lei Zhang Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 10 ++++ .../wireless/broadcom/brcm80211/brcmfmac/fweh.c | 57 ++++-------------- .../wireless/broadcom/brcm80211/brcmfmac/fweh.h | 68 +++++++++++++++++----- .../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 10 ++++ 4 files changed, 87 insertions(+), 58 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 2fd18d04b61e..6cc8fdc9fcc8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3092,6 +3092,11 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, brcmf_dbg(SCAN, "Enter\n"); + if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { + brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + return 0; + } + if (e->event_code == BRCMF_E_PFN_NET_LOST) { brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n"); return 0; @@ -3415,6 +3420,11 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, brcmf_dbg(SCAN, "Enter\n"); + if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { + brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + return 0; + } + pfn_result = (struct brcmf_pno_scanresults_le *)data; if (e->event_code == BRCMF_E_PFN_NET_LOST) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index 7b26fb1b437c..d414fbbcc814 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -25,50 +25,6 @@ #include "fweh.h" #include "fwil.h" -/** - * struct brcm_ethhdr - broadcom specific ether header. - * - * @subtype: subtype for this packet. - * @length: TODO: length of appended data. - * @version: version indication. - * @oui: OUI of this packet. - * @usr_subtype: subtype for this OUI. - */ -struct brcm_ethhdr { - __be16 subtype; - __be16 length; - u8 version; - u8 oui[3]; - __be16 usr_subtype; -} __packed; - -struct brcmf_event_msg_be { - __be16 version; - __be16 flags; - __be32 event_type; - __be32 status; - __be32 reason; - __be32 auth_type; - __be32 datalen; - u8 addr[ETH_ALEN]; - char ifname[IFNAMSIZ]; - u8 ifidx; - u8 bsscfgidx; -} __packed; - -/** - * struct brcmf_event - contents of broadcom event packet. - * - * @eth: standard ether header. - * @hdr: broadcom specific ether header. - * @msg: common part of the actual event message. - */ -struct brcmf_event { - struct ethhdr eth; - struct brcm_ethhdr hdr; - struct brcmf_event_msg_be msg; -} __packed; - /** * struct brcmf_fweh_queue_item - event item on event queue. * @@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item { u8 ifidx; u8 ifaddr[ETH_ALEN]; struct brcmf_event_msg_be emsg; + u32 datalen; u8 data[0]; }; @@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work) brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, min_t(u32, emsg.datalen, 64), "event payload, len=%d\n", emsg.datalen); + if (emsg.datalen > event->datalen) { + brcmf_err("event invalid length header=%d, msg=%d\n", + event->datalen, emsg.datalen); + goto event_free; + } /* special handling of interface event */ if (event->code == BRCMF_E_IF) { @@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp) * dispatch the event to a registered handler (using worker). */ void brcmf_fweh_process_event(struct brcmf_pub *drvr, - struct brcmf_event *event_packet) + struct brcmf_event *event_packet, + u32 packet_len) { enum brcmf_fweh_event_code code; struct brcmf_fweh_info *fweh = &drvr->fweh; @@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, if (code != BRCMF_E_IF && !fweh->evt_handler[code]) return; + if (datalen > BRCMF_DCMD_MAXLEN) + return; + if (in_interrupt()) alloc_flag = GFP_ATOMIC; @@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, /* use memcpy to get aligned event message */ memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(event->data, data, datalen); + event->datalen = datalen; memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); brcmf_fweh_queue_event(fweh, event); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 5e39e2a9e388..26ff5a9648f3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -27,7 +27,6 @@ struct brcmf_pub; struct brcmf_if; struct brcmf_cfg80211_info; -struct brcmf_event; /* list of firmware events */ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ @@ -180,12 +179,54 @@ enum brcmf_fweh_event_code { /** * definitions for event packet validation. */ -#define BRCMF_EVENT_OUI_OFFSET 19 -#define BRCM_OUI "\x00\x10\x18" -#define DOT11_OUI_LEN 3 -#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define BRCM_OUI "\x00\x10\x18" +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +/** + * struct brcm_ethhdr - broadcom specific ether header. + * + * @subtype: subtype for this packet. + * @length: TODO: length of appended data. + * @version: version indication. + * @oui: OUI of this packet. + * @usr_subtype: subtype for this OUI. + */ +struct brcm_ethhdr { + __be16 subtype; + __be16 length; + u8 version; + u8 oui[3]; + __be16 usr_subtype; +} __packed; + +struct brcmf_event_msg_be { + __be16 version; + __be16 flags; + __be32 event_type; + __be32 status; + __be32 reason; + __be32 auth_type; + __be32 datalen; + u8 addr[ETH_ALEN]; + char ifname[IFNAMSIZ]; + u8 ifidx; + u8 bsscfgidx; +} __packed; + +/** + * struct brcmf_event - contents of broadcom event packet. + * + * @eth: standard ether header. + * @hdr: broadcom specific ether header. + * @msg: common part of the actual event message. + */ +struct brcmf_event { + struct ethhdr eth; + struct brcm_ethhdr hdr; + struct brcmf_event_msg_be msg; +} __packed; + /** * struct brcmf_event_msg - firmware event message. * @@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code); int brcmf_fweh_activate_events(struct brcmf_if *ifp); void brcmf_fweh_process_event(struct brcmf_pub *drvr, - struct brcmf_event *event_packet); + struct brcmf_event *event_packet, + u32 packet_len); void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing); static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr, struct sk_buff *skb) { struct brcmf_event *event_packet; - u8 *data; u16 usr_stype; /* only process events when protocol matches */ if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL)) return; + if ((skb->len + ETH_HLEN) < sizeof(*event_packet)) + return; + /* check for BRCM oui match */ event_packet = (struct brcmf_event *)skb_mac_header(skb); - data = (u8 *)event_packet; - data += BRCMF_EVENT_OUI_OFFSET; - if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN)) + if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0], + sizeof(event_packet->hdr.oui))) return; /* final match on usr_subtype */ - data += DOT11_OUI_LEN; - usr_stype = get_unaligned_be16(data); + usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype); if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT) return; - brcmf_fweh_process_event(drvr, event_packet); + brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN); } #endif /* FWEH_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index de5892a67c22..b5a49e564f25 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, u16 mgmt_type; u8 action; + if (e->datalen < sizeof(*rxframe)) { + brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + return 0; + } + ch.chspec = be16_to_cpu(rxframe->chanspec); cfg->d11inf.decchspec(&ch); /* Check if wpa_supplicant has registered for this frame */ @@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, e->reason); + if (e->datalen < sizeof(*rxframe)) { + brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + return 0; + } + ch.chspec = be16_to_cpu(rxframe->chanspec); cfg->d11inf.decchspec(&ch); -- cgit v1.2.3 From 52f22fb21764f083d697b3e35c18f37e471eba76 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 17 Feb 2016 11:26:55 +0100 Subject: brcmfmac: add neighbor discovery offload ip address table configuration Configure ipv6 address for neighbor discovery offload ip table in firmware obtained through ipv6 address notification callback. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 23 ++-- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 138 ++++++++++++++++++--- .../wireless/broadcom/brcm80211/brcmfmac/core.h | 7 ++ 3 files changed, 141 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 6cc8fdc9fcc8..71f1fdf2e7e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -456,7 +456,7 @@ send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key) } static s32 -brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) +brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable) { s32 err; u32 mode; @@ -484,6 +484,15 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) enable, mode); } + err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable); + if (err) { + brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n", + enable, err); + err = 0; + } else + brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n", + enable, mode); + return err; } @@ -3543,7 +3552,7 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) brcmf_report_wowl_wakeind(wiphy, ifp); brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0); brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0); - brcmf_configure_arp_offload(ifp, true); + brcmf_configure_arp_nd_offload(ifp, true); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, cfg->wowl.pre_pmmode); cfg->wowl.active = false; @@ -3567,7 +3576,7 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg, brcmf_dbg(TRACE, "Suspend, wowl config.\n"); - brcmf_configure_arp_offload(ifp, false); + brcmf_configure_arp_nd_offload(ifp, false); brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); @@ -4336,7 +4345,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, if (!mbss) { brcmf_set_mpc(ifp, 0); - brcmf_configure_arp_offload(ifp, false); + brcmf_configure_arp_nd_offload(ifp, false); } /* find the RSN_IE */ @@ -4482,7 +4491,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, exit: if ((err) && (!mbss)) { brcmf_set_mpc(ifp, 1); - brcmf_configure_arp_offload(ifp, true); + brcmf_configure_arp_nd_offload(ifp, true); } return err; } @@ -4540,7 +4549,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) brcmf_err("bss_enable config failed %d\n", err); } brcmf_set_mpc(ifp, 1); - brcmf_configure_arp_offload(ifp, true); + brcmf_configure_arp_nd_offload(ifp, true); clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); brcmf_net_setcarrier(ifp, false); @@ -6287,7 +6296,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) if (err) goto default_conf_out; - brcmf_configure_arp_offload(ifp, true); + brcmf_configure_arp_nd_offload(ifp, true); cfg->dongle_up = true; default_conf_out: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index ed9998b69709..9507cc933c3b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -172,6 +174,35 @@ _brcmf_set_mac_address(struct work_struct *work) } } +#if IS_ENABLED(CONFIG_IPV6) +static void _brcmf_update_ndtable(struct work_struct *work) +{ + struct brcmf_if *ifp; + int i, ret; + + ifp = container_of(work, struct brcmf_if, ndoffload_work); + + /* clear the table in firmware */ + ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0); + if (ret) { + brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret); + return; + } + + for (i = 0; i < ifp->ipv6addr_idx; i++) { + ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip", + &ifp->ipv6_addr_tbl[i], + sizeof(struct in6_addr)); + if (ret) + brcmf_err("add nd ip err %d\n", ret); + } +} +#else +static void _brcmf_update_ndtable(struct work_struct *work) +{ +} +#endif + static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) { struct brcmf_if *ifp = netdev_priv(ndev); @@ -685,6 +716,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); + INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable); if (rtnl_locked) err = register_netdevice(ndev); @@ -884,6 +916,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { cancel_work_sync(&ifp->setmacaddr_work); cancel_work_sync(&ifp->multicast_work); + cancel_work_sync(&ifp->ndoffload_work); } brcmf_net_detach(ifp->ndev); } else { @@ -1025,6 +1058,56 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb, } #endif +#if IS_ENABLED(CONFIG_IPV6) +static int brcmf_inet6addr_changed(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub, + inet6addr_notifier); + struct inet6_ifaddr *ifa = data; + struct brcmf_if *ifp; + int i; + struct in6_addr *table; + + /* Only handle primary interface */ + ifp = drvr->iflist[0]; + if (!ifp) + return NOTIFY_DONE; + if (ifp->ndev != ifa->idev->dev) + return NOTIFY_DONE; + + table = ifp->ipv6_addr_tbl; + for (i = 0; i < NDOL_MAX_ENTRIES; i++) + if (ipv6_addr_equal(&ifa->addr, &table[i])) + break; + + switch (action) { + case NETDEV_UP: + if (i == NDOL_MAX_ENTRIES) { + if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) { + table[ifp->ipv6addr_idx++] = ifa->addr; + } else { + for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++) + table[i] = table[i + 1]; + table[NDOL_MAX_ENTRIES - 1] = ifa->addr; + } + } + break; + case NETDEV_DOWN: + if (i < NDOL_MAX_ENTRIES) + for (; i < ifp->ipv6addr_idx; i++) + table[i] = table[i + 1]; + break; + default: + break; + } + + schedule_work(&ifp->ndoffload_work); + + return NOTIFY_OK; +} +#endif + int brcmf_attach(struct device *dev) { struct brcmf_pub *drvr = NULL; @@ -1164,30 +1247,41 @@ int brcmf_bus_start(struct device *dev) #ifdef CONFIG_INET drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed; ret = register_inetaddr_notifier(&drvr->inetaddr_notifier); + if (ret) + goto fail; + +#if IS_ENABLED(CONFIG_IPV6) + drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed; + ret = register_inet6addr_notifier(&drvr->inet6addr_notifier); + if (ret) { + unregister_inetaddr_notifier(&drvr->inetaddr_notifier); + goto fail; + } #endif +#endif /* CONFIG_INET */ + + return 0; fail: - if (ret < 0) { - brcmf_err("failed: %d\n", ret); - if (drvr->config) { - brcmf_cfg80211_detach(drvr->config); - drvr->config = NULL; - } - if (drvr->fws) { - brcmf_fws_del_interface(ifp); - brcmf_fws_deinit(drvr); - } - if (ifp) - brcmf_net_detach(ifp->ndev); - if (p2p_ifp) - brcmf_net_detach(p2p_ifp->ndev); - drvr->iflist[0] = NULL; - drvr->iflist[1] = NULL; - if (brcmf_ignoring_probe_fail(drvr)) - ret = 0; - return ret; + brcmf_err("failed: %d\n", ret); + if (drvr->config) { + brcmf_cfg80211_detach(drvr->config); + drvr->config = NULL; } - return 0; + if (drvr->fws) { + brcmf_fws_del_interface(ifp); + brcmf_fws_deinit(drvr); + } + if (ifp) + brcmf_net_detach(ifp->ndev); + if (p2p_ifp) + brcmf_net_detach(p2p_ifp->ndev); + drvr->iflist[0] = NULL; + drvr->iflist[1] = NULL; + if (brcmf_ignoring_probe_fail(drvr)) + ret = 0; + + return ret; } void brcmf_bus_add_txhdrlen(struct device *dev, uint len) @@ -1237,6 +1331,10 @@ void brcmf_detach(struct device *dev) unregister_inetaddr_notifier(&drvr->inetaddr_notifier); #endif +#if IS_ENABLED(CONFIG_IPV6) + unregister_inet6addr_notifier(&drvr->inet6addr_notifier); +#endif + /* stop firmware event handling */ brcmf_fweh_detach(drvr); if (drvr->config) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 8f39435f976f..500dac6e1f82 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -48,6 +48,8 @@ */ #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 +#define NDOL_MAX_ENTRIES 8 + /** * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info * @@ -143,6 +145,7 @@ struct brcmf_pub { #endif struct notifier_block inetaddr_notifier; + struct notifier_block inet6addr_notifier; struct brcmf_mp_device *settings; }; @@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason { * @stats: interface specific network statistics. * @setmacaddr_work: worker object for setting mac address. * @multicast_work: worker object for multicast provisioning. + * @ndoffload_work: worker object for neighbor discovery offload configuration. * @fws_desc: interface specific firmware-signalling descriptor. * @ifidx: interface index in device firmware. * @bsscfgidx: index of bss associated with this interface. @@ -191,6 +195,7 @@ struct brcmf_if { struct net_device_stats stats; struct work_struct setmacaddr_work; struct work_struct multicast_work; + struct work_struct ndoffload_work; struct brcmf_fws_mac_descriptor *fws_desc; int ifidx; s32 bsscfgidx; @@ -199,6 +204,8 @@ struct brcmf_if { spinlock_t netif_stop_lock; atomic_t pend_8021x_cnt; wait_queue_head_t pend_8021x_wait; + struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES]; + u8 ipv6addr_idx; }; struct brcmf_skb_reorder_data { -- cgit v1.2.3 From cd2bc19c61b2da81ce310edb20f98e51fa7a5889 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 17 Feb 2016 11:26:56 +0100 Subject: brcmfmac: check return for ARP ip setting iovar The return value of iovar set function should be saved and checked. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 9507cc933c3b..dcf9393ad8ff 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1039,14 +1039,14 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb, return NOTIFY_OK; } for (i = 0; i < ARPOL_MAX_ENTRIES; i++) { - if (addr_table[i] != 0) { - brcmf_fil_iovar_data_set(ifp, - "arp_hostip", &addr_table[i], - sizeof(addr_table[i])); - if (ret) - brcmf_err("add arp ip err %d\n", - ret); - } + if (addr_table[i] == 0) + continue; + ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip", + &addr_table[i], + sizeof(addr_table[i])); + if (ret) + brcmf_err("add arp ip err %d\n", + ret); } } break; -- cgit v1.2.3 From 6ac27689b01e23e21f08d6f55d23a94eb10a8efc Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:26:57 +0100 Subject: brcmfmac: use device memsize config from fw if defined Newer type pcie devices have memory which get shared between fw and hw. The division of this memory is done firmware compile time. As a result the ramsize as used by driver needs to be adjusted for this. This is done by reading the memory size from the firmware. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index d5f9ef470447..d89212b4649e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -207,6 +207,10 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4 #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3 +/* Magic number at a magic location to find RAM size */ +#define BRCMF_RAMSIZE_MAGIC 0x534d4152 /* SMAR */ +#define BRCMF_RAMSIZE_OFFSET 0x6c + struct brcmf_pcie_console { u32 base_addr; @@ -1412,6 +1416,28 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { }; +static void +brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data, + u32 data_len) +{ + __le32 *field; + u32 newsize; + + if (data_len < BRCMF_RAMSIZE_OFFSET + 8) + return; + + field = (__le32 *)&data[BRCMF_RAMSIZE_OFFSET]; + if (le32_to_cpup(field) != BRCMF_RAMSIZE_MAGIC) + return; + field++; + newsize = le32_to_cpup(field); + + brcmf_dbg(PCIE, "Found ramsize info in FW, adjusting to 0x%x\n", + newsize); + devinfo->ci->ramsize = newsize; +} + + static int brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, u32 sharedram_addr) @@ -1694,6 +1720,13 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw, brcmf_pcie_attach(devinfo); + /* Some of the firmwares have the size of the memory of the device + * defined inside the firmware. This is because part of the memory in + * the device is shared and the devision is determined by FW. Parse + * the firmware and adjust the chip memory size now. + */ + brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size); + ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len); if (ret) goto fail; -- cgit v1.2.3 From 9300bf8610fd90a63a04dcc6be8223552321edad Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:26:58 +0100 Subject: brcmfmac: use bar1 window size as provided by pci subsystem The PCIE bar1 window size is specified by chip. Currently the ioremap of bar1 was using a define which always matched the size of bar1, but newer chips can have a different bar1 sizes. With this patch the ioremap will be called with the by chip provided window size. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index d89212b4649e..3fd4e3b1a211 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -72,7 +72,6 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */ -#define BRCMF_PCIE_TCM_MAP_SIZE (4096 * 1024) #define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024) /* backplane addres space accessed by BAR0 */ @@ -252,7 +251,6 @@ struct brcmf_pciedev_info { char nvram_name[BRCMF_FW_NAME_LEN]; void __iomem *regs; void __iomem *tcm; - u32 tcm_size; u32 ram_base; u32 ram_size; struct brcmf_chip *ci; @@ -1592,8 +1590,7 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo) } devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE); - devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE); - devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE; + devinfo->tcm = ioremap_nocache(bar1_addr, bar1_size); if (!devinfo->regs || !devinfo->tcm) { brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs, @@ -1602,8 +1599,9 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo) } brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n", devinfo->regs, (unsigned long long)bar0_addr); - brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n", - devinfo->tcm, (unsigned long long)bar1_addr); + brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx size 0x%x\n", + devinfo->tcm, (unsigned long long)bar1_addr, + (unsigned int)bar1_size); return 0; } -- cgit v1.2.3 From bc86fdb9ac02c77b9f55325f64fb70decc425962 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:26:59 +0100 Subject: brcmfmac: add support for the PCIE 4366c0 chip A newer version of the 4366 PCIE chip has been released. Add support for this version of the chip. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 3fd4e3b1a211..3cb32b73fa23 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -53,6 +53,7 @@ BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt"); BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt"); BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt"); BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt"); +BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt"); BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { @@ -66,7 +67,8 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFFF, 4366B), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), }; -- cgit v1.2.3 From d457a44fd85cd766c8bb48d6b542467bf89601b4 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:00 +0100 Subject: brcmfmac: remove pcie gen1 support The PCIE bus driver supports older gen1 (v1) chips, but there is no actual device which is using this older pcie core which is supported by brcmfmac. Remove all gen1 related code. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 135 +++------------------ 1 file changed, 20 insertions(+), 115 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 3cb32b73fa23..1866b66b47f2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -100,9 +100,6 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124 #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX 0x140 -#define BRCMF_PCIE_GENREV1 1 -#define BRCMF_PCIE_GENREV2 2 - #define BRCMF_PCIE2_INTA 0x01 #define BRCMF_PCIE2_INTB 0x02 @@ -257,9 +254,7 @@ struct brcmf_pciedev_info { u32 ram_size; struct brcmf_chip *ci; u32 coreid; - u32 generic_corerev; struct brcmf_pcie_shared_info shared; - void (*ringbell)(struct brcmf_pciedev_info *devinfo); wait_queue_head_t mbdata_resp_wait; bool mbdata_completed; bool irq_allocated; @@ -746,68 +741,22 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo) } -static __used void brcmf_pcie_ringbell_v1(struct brcmf_pciedev_info *devinfo) -{ - u32 reg_value; - - brcmf_dbg(PCIE, "RING !\n"); - reg_value = brcmf_pcie_read_reg32(devinfo, - BRCMF_PCIE_PCIE2REG_MAILBOXINT); - reg_value |= BRCMF_PCIE2_INTB; - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, - reg_value); -} - - -static void brcmf_pcie_ringbell_v2(struct brcmf_pciedev_info *devinfo) -{ - brcmf_dbg(PCIE, "RING !\n"); - /* Any arbitrary value will do, lets use 1 */ - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1); -} - - static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo) { - if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) - pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK, - 0); - else - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, - 0); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0); } static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo) { - if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) - pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK, - BRCMF_PCIE_INT_DEF); - else - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, - BRCMF_PCIE_MB_INT_D2H_DB | - BRCMF_PCIE_MB_INT_FN0_0 | - BRCMF_PCIE_MB_INT_FN0_1); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, + BRCMF_PCIE_MB_INT_D2H_DB | + BRCMF_PCIE_MB_INT_FN0_0 | + BRCMF_PCIE_MB_INT_FN0_1); } -static irqreturn_t brcmf_pcie_quick_check_isr_v1(int irq, void *arg) -{ - struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; - u32 status; - - status = 0; - pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTSTATUS, &status); - if (status) { - brcmf_pcie_intr_disable(devinfo); - brcmf_dbg(PCIE, "Enter\n"); - return IRQ_WAKE_THREAD; - } - return IRQ_NONE; -} - - -static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg) +static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg) { struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; @@ -820,29 +769,7 @@ static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg) } -static irqreturn_t brcmf_pcie_isr_thread_v1(int irq, void *arg) -{ - struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; - const struct pci_dev *pdev = devinfo->pdev; - u32 status; - - devinfo->in_irq = true; - status = 0; - pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status); - brcmf_dbg(PCIE, "Enter %x\n", status); - if (status) { - pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status); - if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) - brcmf_proto_msgbuf_rx_trigger(&devinfo->pdev->dev); - } - if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) - brcmf_pcie_intr_enable(devinfo); - devinfo->in_irq = false; - return IRQ_HANDLED; -} - - -static irqreturn_t brcmf_pcie_isr_thread_v2(int irq, void *arg) +static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg) { struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; u32 status; @@ -879,28 +806,14 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo) brcmf_pcie_intr_disable(devinfo); brcmf_dbg(PCIE, "Enter\n"); - /* is it a v1 or v2 implementation */ + pci_enable_msi(pdev); - if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { - if (request_threaded_irq(pdev->irq, - brcmf_pcie_quick_check_isr_v1, - brcmf_pcie_isr_thread_v1, - IRQF_SHARED, "brcmf_pcie_intr", - devinfo)) { - pci_disable_msi(pdev); - brcmf_err("Failed to request IRQ %d\n", pdev->irq); - return -EIO; - } - } else { - if (request_threaded_irq(pdev->irq, - brcmf_pcie_quick_check_isr_v2, - brcmf_pcie_isr_thread_v2, - IRQF_SHARED, "brcmf_pcie_intr", - devinfo)) { - pci_disable_msi(pdev); - brcmf_err("Failed to request IRQ %d\n", pdev->irq); - return -EIO; - } + if (request_threaded_irq(pdev->irq, brcmf_pcie_quick_check_isr, + brcmf_pcie_isr_thread, IRQF_SHARED, + "brcmf_pcie_intr", devinfo)) { + pci_disable_msi(pdev); + brcmf_err("Failed to request IRQ %d\n", pdev->irq); + return -EIO; } devinfo->irq_allocated = true; return 0; @@ -931,16 +844,9 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo) if (devinfo->in_irq) brcmf_err("Still in IRQ (processing) !!!\n"); - if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { - status = 0; - pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status); - pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status); - } else { - status = brcmf_pcie_read_reg32(devinfo, - BRCMF_PCIE_PCIE2REG_MAILBOXINT); - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, - status); - } + status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status); + devinfo->irq_allocated = false; } @@ -989,7 +895,9 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx) if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) return -EIO; - devinfo->ringbell(devinfo); + brcmf_dbg(PCIE, "RING !\n"); + /* Any arbitrary value will do, lets use 1 */ + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1); return 0; } @@ -1503,9 +1411,6 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, u32 address; u32 resetintr; - devinfo->ringbell = brcmf_pcie_ringbell_v2; - devinfo->generic_corerev = BRCMF_PCIE_GENREV2; - brcmf_dbg(PCIE, "Halt ARM.\n"); err = brcmf_pcie_enter_download_state(devinfo); if (err) -- cgit v1.2.3 From e9217b4b62a7296b5c008fd607579dbaf40bd754 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:01 +0100 Subject: brcmfmac: increase timeout for tx eapol When keys get set and updated this has to happen after eapol got transmitted (without key or old key) before the key can be updated. To make sure the order of sending eapol and configuring key is done correctly a timeout for tx of eapol is applied. This timeout is set to 50 msec, which is not always enough. Especially in AP mode and key updates the timeout may need to be much longer because client(s) can be in powersave. Increase the timeout from 50 to 950 msec. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index dcf9393ad8ff..3087d10f85b2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -42,7 +42,7 @@ MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); MODULE_LICENSE("Dual BSD/GPL"); -#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(50) +#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950) /* AMPDU rx reordering definitions */ #define BRCMF_RXREORDER_FLOWID_OFFSET 0 -- cgit v1.2.3 From d84d99e007770b4dd9b9e8be99da043c6555e274 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:02 +0100 Subject: brcmfmac: move module init and exit to common In preparation of module parameters for all devices the module init and exit routines are moved to the common file. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/common.c | 36 +++++++++++++++++++++- .../wireless/broadcom/brcm80211/brcmfmac/common.h | 1 - .../wireless/broadcom/brcm80211/brcmfmac/core.c | 15 ++------- .../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 ++ 4 files changed, 39 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 8199862c7cdb..b8dc68db708f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -28,6 +28,10 @@ #include "tracepoint.h" #include "common.h" +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +MODULE_LICENSE("Dual BSD/GPL"); + const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 @@ -221,7 +225,7 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...) } #endif -void brcmf_mp_attach(void) +static void brcmf_mp_attach(void) { strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path, BRCMF_FW_ALTPATH_LEN); @@ -249,3 +253,33 @@ void brcmf_mp_device_detach(struct brcmf_pub *drvr) kfree(drvr->settings); } +static int __init brcmfmac_module_init(void) +{ + int err; + + /* Initialize debug system first */ + brcmf_debugfs_init(); + +#ifdef CONFIG_BRCMFMAC_SDIO + brcmf_sdio_init(); +#endif + /* Initialize global module paramaters */ + brcmf_mp_attach(); + + /* Continue the initialization by registering the different busses */ + err = brcmf_core_init(); + if (err) + brcmf_debugfs_exit(); + + return err; +} + +static void __exit brcmfmac_module_exit(void) +{ + brcmf_core_exit(); + brcmf_debugfs_exit(); +} + +module_init(brcmfmac_module_init); +module_exit(brcmfmac_module_exit); + diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index b678b2d60749..256be1b0c41b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -89,7 +89,6 @@ struct brcmf_mp_device { struct cc_translate *country_codes; }; -void brcmf_mp_attach(void); int brcmf_mp_device_attach(struct brcmf_pub *drvr); void brcmf_mp_device_detach(struct brcmf_pub *drvr); #ifdef DEBUG diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 3087d10f85b2..7b24e2b71a43 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -38,10 +38,6 @@ #include "pcie.h" #include "common.h" -MODULE_AUTHOR("Broadcom Corporation"); -MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); -MODULE_LICENSE("Dual BSD/GPL"); - #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950) /* AMPDU rx reordering definitions */ @@ -1422,19 +1418,15 @@ static void brcmf_driver_register(struct work_struct *work) } static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register); -static int __init brcmfmac_module_init(void) +int __init brcmf_core_init(void) { - brcmf_debugfs_init(); -#ifdef CONFIG_BRCMFMAC_SDIO - brcmf_sdio_init(); -#endif if (!schedule_work(&brcmf_driver_work)) return -EBUSY; return 0; } -static void __exit brcmfmac_module_exit(void) +void __exit brcmf_core_exit(void) { cancel_work_sync(&brcmf_driver_work); @@ -1447,8 +1439,5 @@ static void __exit brcmfmac_module_exit(void) #ifdef CONFIG_BRCMFMAC_PCIE brcmf_pcie_exit(); #endif - brcmf_debugfs_exit(); } -module_init(brcmfmac_module_init); -module_exit(brcmfmac_module_exit); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 500dac6e1f82..7bdb6fef99c3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -227,5 +227,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); +int __init brcmf_core_init(void); +void __exit brcmf_core_exit(void); #endif /* BRCMFMAC_CORE_H */ -- cgit v1.2.3 From 5c22fb85102a751e5a305d8fd13a1856a725bf01 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:03 +0100 Subject: brcmfmac: add wowl gtk rekeying offload support This patch adds support for gtk rekeying offload and for gtk rekeying failure during wowl mode. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 65 ++++++++++++++++++---- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 2 + .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 12 ++++ .../wireless/broadcom/brcm80211/brcmfmac/feature.h | 6 +- .../broadcom/brcm80211/brcmfmac/fwil_types.h | 21 ++++++- 5 files changed, 93 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 71f1fdf2e7e8..6d849bb2e27c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3526,6 +3526,10 @@ static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp) else wakeup_data.net_detect = cfg->wowl.nd_info; } + if (wakeind & BRCMF_WOWL_GTK_FAILURE) { + brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n"); + wakeup_data.gtk_rekey_failure = true; + } } else { wakeup = NULL; } @@ -3607,6 +3611,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg, brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, brcmf_wowl_nd_results); } + if (wowl->gtk_rekey_failure) + wowl_config |= BRCMF_WOWL_GTK_FAILURE; if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) wowl_config |= BRCMF_WOWL_UNASSOC; @@ -4874,7 +4880,32 @@ static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy, return ret; } -static struct cfg80211_ops wl_cfg80211_ops = { +#ifdef CONFIG_PM +static int +brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_gtk_rekey_data *gtk) +{ + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_gtk_keyinfo_le gtk_le; + int ret; + + brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx); + + memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck)); + memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek)); + memcpy(gtk_le.replay_counter, gtk->replay_ctr, + sizeof(gtk_le.replay_counter)); + + ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", >k_le, + sizeof(gtk_le)); + if (ret < 0) + brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret); + + return ret; +} +#endif + +static struct cfg80211_ops brcmf_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, .change_virtual_intf = brcmf_cfg80211_change_iface, @@ -6139,19 +6170,18 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp) { #ifdef CONFIG_PM struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - s32 err; - u32 wowl_cap; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { - err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); - if (!err) { - if (wowl_cap & BRCMF_WOWL_PFN_FOUND) { - brcmf_wowlan_support.flags |= - WIPHY_WOWLAN_NET_DETECT; - init_waitqueue_head(&cfg->wowl.nd_data_wait); - } + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) { + brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; + init_waitqueue_head(&cfg->wowl.nd_data_wait); } } + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) { + brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY; + brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE; + } + wiphy->wowlan = &brcmf_wowlan_support; #endif } @@ -6538,6 +6568,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev; struct brcmf_cfg80211_info *cfg; struct wiphy *wiphy; + struct cfg80211_ops *ops; struct brcmf_cfg80211_vif *vif; struct brcmf_if *ifp; s32 err = 0; @@ -6549,8 +6580,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return NULL; } + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + return NULL; + + memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops)); ifp = netdev_priv(ndev); - wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); +#ifdef CONFIG_PM + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) + ops->set_rekey_data = brcmf_cfg80211_set_rekey_data; +#endif + wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info)); if (!wiphy) { brcmf_err("Could not allocate wiphy device\n"); return NULL; @@ -6560,6 +6600,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, cfg = wiphy_priv(wiphy); cfg->wiphy = wiphy; + cfg->ops = ops; cfg->pub = drvr; init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); @@ -6686,6 +6727,7 @@ priv_out: ifp->vif = NULL; wiphy_out: brcmf_free_wiphy(wiphy); + kfree(ops); return NULL; } @@ -6696,6 +6738,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); + kfree(cfg->ops); wl_deinit_priv(cfg); brcmf_free_wiphy(cfg->wiphy); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 01f096f7a089..e4c1d4364684 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -256,6 +256,7 @@ struct brcmf_cfg80211_wowl { * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface * * @wiphy: wiphy object for cfg80211 interface. + * @ops: pointer to copy of ops as registered with wiphy object. * @conf: dongle configuration. * @p2p: peer-to-peer specific information. * @btcoex: Bluetooth coexistence information. @@ -288,6 +289,7 @@ struct brcmf_cfg80211_wowl { */ struct brcmf_cfg80211_info { struct wiphy *wiphy; + struct cfg80211_ops *ops; struct brcmf_cfg80211_conf *conf; struct brcmf_p2p_info p2p; struct brcmf_btcoex_info *btcoex; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 1ffa95f1b8d2..098732a0c91b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -136,6 +136,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) { struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); struct brcmf_pno_macaddr_le pfn_mac; + u32 wowl_cap; s32 err; brcmf_feat_firmware_capabilities(ifp); @@ -143,6 +144,17 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); if (drvr->bus_if->wowl_supported) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) { + err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); + if (!err) { + if (wowl_cap & BRCMF_WOWL_PFN_FOUND) + ifp->drvr->feat_flags |= + BIT(BRCMF_FEAT_WOWL_ND); + if (wowl_cap & BRCMF_WOWL_GTK_FAILURE) + ifp->drvr->feat_flags |= + BIT(BRCMF_FEAT_WOWL_GTK); + } + } /* MBSS does not work for 43362 */ if (drvr->bus_if->chip == BRCM_CC_43362_CHIP_ID) ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index 2e2479d41337..f940c29bcfaf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -27,6 +27,8 @@ * RSDB: Real Simultaneous Dual Band * TDLS: Tunneled Direct Link Setup * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan. + * WOWL_ND: WOWL net detect (PNO) + * WOWL_GTK: (WOWL) GTK rekeying offload */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -36,7 +38,9 @@ BRCMF_FEAT_DEF(P2P) \ BRCMF_FEAT_DEF(RSDB) \ BRCMF_FEAT_DEF(TDLS) \ - BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) + BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \ + BRCMF_FEAT_DEF(WOWL_ND) \ + BRCMF_FEAT_DEF(WOWL_GTK) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index e9e177dad1a6..6d41ae392a8f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -111,7 +111,9 @@ /* Wakeup if received matched secured pattern: */ #define BRCMF_WOWL_SECURE (1 << 25) /* Wakeup on finding preferred network */ -#define BRCMF_WOWL_PFN_FOUND (1 << 26) +#define BRCMF_WOWL_PFN_FOUND (1 << 27) +/* Wakeup on receiving pairwise key EAP packets: */ +#define WIPHY_WOWL_EAP_PK (1 << 28) /* Link Down indication in WoWL mode: */ #define BRCMF_WOWL_LINKDOWN (1 << 31) @@ -136,6 +138,10 @@ #define BRCMF_MCSSET_LEN 16 +#define BRCMF_RSN_KCK_LENGTH 16 +#define BRCMF_RSN_KEK_LENGTH 16 +#define BRCMF_RSN_REPLAY_LEN 8 + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { BRCMF_JOIN_PREF_RSSI = 1, @@ -789,4 +795,17 @@ struct brcmf_pktcnt_le { __le32 rx_ocast_good_pkt; }; +/** + * struct brcmf_gtk_keyinfo_le - GTP rekey data + * + * @kck: key confirmation key. + * @kek: key encryption key. + * @replay_counter: replay counter. + */ +struct brcmf_gtk_keyinfo_le { + u8 kck[BRCMF_RSN_KCK_LENGTH]; + u8 kek[BRCMF_RSN_KEK_LENGTH]; + u8 replay_counter[BRCMF_RSN_REPLAY_LEN]; +}; + #endif /* FWIL_TYPES_H_ */ -- cgit v1.2.3 From 8ea56be0869f8230ed7b2779397225fe45080dd1 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:04 +0100 Subject: brcmfmac: move platform data retrieval code to common In preparation of module parameters for all devices the module platform data retrieval is moved from sdio to common. It is still only used for sdio devices. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 84 +++++----------------- .../wireless/broadcom/brcm80211/brcmfmac/common.c | 53 ++++++++++++-- .../wireless/broadcom/brcm80211/brcmfmac/common.h | 3 + .../net/wireless/broadcom/brcm80211/brcmfmac/of.c | 23 +++--- .../net/wireless/broadcom/brcm80211/brcmfmac/of.h | 6 +- 5 files changed, 84 insertions(+), 85 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index b98db8a0a069..25cd71229c95 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -27,8 +27,6 @@ #include #include #include -#include -#include #include #include #include @@ -46,7 +44,6 @@ #include "bus.h" #include "debug.h" #include "sdio.h" -#include "of.h" #include "core.h" #include "common.h" @@ -106,18 +103,18 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func) int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) { + struct brcmfmac_sdio_platform_data *pdata; int ret = 0; u8 data; u32 addr, gpiocontrol; unsigned long flags; - if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) { + pdata = sdiodev->pdata; + if ((pdata) && (pdata->oob_irq_supported)) { brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", - sdiodev->pdata->oob_irq_nr); - ret = request_irq(sdiodev->pdata->oob_irq_nr, - brcmf_sdiod_oob_irqhandler, - sdiodev->pdata->oob_irq_flags, - "brcmf_oob_intr", + pdata->oob_irq_nr); + ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, + pdata->oob_irq_flags, "brcmf_oob_intr", &sdiodev->func[1]->dev); if (ret != 0) { brcmf_err("request_irq failed %d\n", ret); @@ -129,7 +126,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) sdiodev->irq_en = true; spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); - ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr); + ret = enable_irq_wake(pdata->oob_irq_nr); if (ret != 0) { brcmf_err("enable_irq_wake failed %d\n", ret); return ret; @@ -158,7 +155,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) /* redirect, configure and enable io for interrupt signal */ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; - if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH) + if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH) data |= SDIO_SEPINT_ACT_HI; brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); @@ -176,9 +173,12 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) { + struct brcmfmac_sdio_platform_data *pdata; + brcmf_dbg(SDIO, "Entering\n"); - if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) { + pdata = sdiodev->pdata; + if ((pdata) && (pdata->oob_irq_supported)) { sdio_claim_host(sdiodev->func[1]); brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); @@ -187,11 +187,10 @@ int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) if (sdiodev->oob_irq_requested) { sdiodev->oob_irq_requested = false; if (sdiodev->irq_wake) { - disable_irq_wake(sdiodev->pdata->oob_irq_nr); + disable_irq_wake(pdata->oob_irq_nr); sdiodev->irq_wake = false; } - free_irq(sdiodev->pdata->oob_irq_nr, - &sdiodev->func[1]->dev); + free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); sdiodev->irq_en = false; } } else { @@ -1103,8 +1102,6 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); -static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata; - static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev, int val) @@ -1167,10 +1164,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, dev_set_drvdata(&func->dev, bus_if); dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); sdiodev->dev = &sdiodev->func[1]->dev; - sdiodev->pdata = brcmfmac_sdio_pdata; - - if (!sdiodev->pdata) - brcmf_of_probe(sdiodev); + sdiodev->pdata = brcmf_get_module_param(sdiodev->dev); #ifdef CONFIG_PM_SLEEP /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ @@ -1296,7 +1290,7 @@ static const struct dev_pm_ops brcmf_sdio_pm_ops = { static struct sdio_driver brcmf_sdmmc_driver = { .probe = brcmf_ops_sdio_probe, .remove = brcmf_ops_sdio_remove, - .name = BRCMFMAC_SDIO_PDATA_NAME, + .name = KBUILD_MODNAME, .id_table = brcmf_sdmmc_ids, .drv = { .owner = THIS_MODULE, @@ -1306,37 +1300,6 @@ static struct sdio_driver brcmf_sdmmc_driver = { }, }; -static int __init brcmf_sdio_pd_probe(struct platform_device *pdev) -{ - brcmf_dbg(SDIO, "Enter\n"); - - brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev); - - if (brcmfmac_sdio_pdata->power_on) - brcmfmac_sdio_pdata->power_on(); - - return 0; -} - -static int brcmf_sdio_pd_remove(struct platform_device *pdev) -{ - brcmf_dbg(SDIO, "Enter\n"); - - if (brcmfmac_sdio_pdata->power_off) - brcmfmac_sdio_pdata->power_off(); - - sdio_unregister_driver(&brcmf_sdmmc_driver); - - return 0; -} - -static struct platform_driver brcmf_sdio_pd = { - .remove = brcmf_sdio_pd_remove, - .driver = { - .name = BRCMFMAC_SDIO_PDATA_NAME, - } -}; - void brcmf_sdio_register(void) { int ret; @@ -1350,19 +1313,6 @@ void brcmf_sdio_exit(void) { brcmf_dbg(SDIO, "Enter\n"); - if (brcmfmac_sdio_pdata) - platform_driver_unregister(&brcmf_sdio_pd); - else - sdio_unregister_driver(&brcmf_sdmmc_driver); + sdio_unregister_driver(&brcmf_sdmmc_driver); } -void __init brcmf_sdio_init(void) -{ - int ret; - - brcmf_dbg(SDIO, "Enter\n"); - - ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe); - if (ret == -ENODEV) - brcmf_dbg(SDIO, "No platform data available.\n"); -} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b8dc68db708f..020901c2e0ca 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -27,6 +27,7 @@ #include "fwil_types.h" #include "tracepoint.h" #include "common.h" +#include "of.h" MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -79,6 +80,7 @@ module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0); MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging"); #endif +static struct brcmfmac_sdio_platform_data *brcmfmac_pdata; struct brcmf_mp_global_t brcmf_mp_global; int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) @@ -231,6 +233,13 @@ static void brcmf_mp_attach(void) BRCMF_FW_ALTPATH_LEN); } +struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev) +{ + if (!brcmfmac_pdata) + brcmf_of_probe(dev, &brcmfmac_pdata); + return brcmfmac_pdata; +} + int brcmf_mp_device_attach(struct brcmf_pub *drvr) { drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC); @@ -253,6 +262,35 @@ void brcmf_mp_device_detach(struct brcmf_pub *drvr) kfree(drvr->settings); } +static int __init brcmf_common_pd_probe(struct platform_device *pdev) +{ + brcmf_dbg(INFO, "Enter\n"); + + brcmfmac_pdata = dev_get_platdata(&pdev->dev); + + if (brcmfmac_pdata->power_on) + brcmfmac_pdata->power_on(); + + return 0; +} + +static int brcmf_common_pd_remove(struct platform_device *pdev) +{ + brcmf_dbg(INFO, "Enter\n"); + + if (brcmfmac_pdata->power_off) + brcmfmac_pdata->power_off(); + + return 0; +} + +static struct platform_driver brcmf_pd = { + .remove = brcmf_common_pd_remove, + .driver = { + .name = BRCMFMAC_SDIO_PDATA_NAME, + } +}; + static int __init brcmfmac_module_init(void) { int err; @@ -260,16 +298,21 @@ static int __init brcmfmac_module_init(void) /* Initialize debug system first */ brcmf_debugfs_init(); -#ifdef CONFIG_BRCMFMAC_SDIO - brcmf_sdio_init(); -#endif + /* Get the platform data (if available) for our devices */ + err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe); + if (err == -ENODEV) + brcmf_dbg(INFO, "No platform data available.\n"); + /* Initialize global module paramaters */ brcmf_mp_attach(); /* Continue the initialization by registering the different busses */ err = brcmf_core_init(); - if (err) + if (err) { brcmf_debugfs_exit(); + if (brcmfmac_pdata) + platform_driver_unregister(&brcmf_pd); + } return err; } @@ -277,6 +320,8 @@ static int __init brcmfmac_module_init(void) static void __exit brcmfmac_module_exit(void) { brcmf_core_exit(); + if (brcmfmac_pdata) + platform_driver_unregister(&brcmf_pd); brcmf_debugfs_exit(); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 256be1b0c41b..54a26ede808d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -15,6 +15,8 @@ #ifndef BRCMFMAC_COMMON_H #define BRCMFMAC_COMMON_H +#include +#include #include "fwil_types.h" extern const u8 ALLFFMAC[ETH_ALEN]; @@ -89,6 +91,7 @@ struct brcmf_mp_device { struct cc_translate *country_codes; }; +struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev); int brcmf_mp_device_attach(struct brcmf_pub *drvr); void brcmf_mp_device_detach(struct brcmf_pub *drvr); #ifdef DEBUG diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index 03f35e0c52ca..8201d937b826 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -16,17 +16,16 @@ #include #include #include -#include -#include -#include #include #include "debug.h" -#include "sdio.h" +#include "core.h" +#include "common.h" +#include "of.h" -void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) +void +brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio) { - struct device *dev = sdiodev->dev; struct device_node *np = dev->of_node; int irq; u32 irqf; @@ -35,12 +34,12 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) return; - sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL); - if (!sdiodev->pdata) + *sdio = devm_kzalloc(dev, sizeof(*sdio), GFP_KERNEL); + if (!(*sdio)) return; if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) - sdiodev->pdata->drive_strength = val; + (*sdio)->drive_strength = val; /* make sure there are interrupts defined in the node */ if (!of_find_property(np, "interrupts", NULL)) @@ -53,7 +52,7 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) } irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); - sdiodev->pdata->oob_irq_supported = true; - sdiodev->pdata->oob_irq_nr = irq; - sdiodev->pdata->oob_irq_flags = irqf; + (*sdio)->oob_irq_supported = true; + (*sdio)->oob_irq_nr = irq; + (*sdio)->oob_irq_flags = irqf; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 5f7c3550deda..84b474484cea 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -14,9 +14,11 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef CONFIG_OF -void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev); +void +brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio); #else -static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) +static void brcmf_of_probe(struct device *dev, + struct brcmfmac_sdio_platform_data **sdio) { } #endif /* CONFIG_OF */ -- cgit v1.2.3 From 73ef9e640e94ab6205c0bb92dc8bac53a40d952e Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:05 +0100 Subject: brcmfmac: keep ARP and ND offload enabled during WOWL Currently ARP and ND (IPv6 Neigbor Discovery) offload get disabled on entering suspend. However when firmwares support the wowl_cap iovar then these offload routines can be kept enabled as they will work during WOWL as well. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ++++-- drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 6d849bb2e27c..5609a79df1c1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3556,7 +3556,8 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) brcmf_report_wowl_wakeind(wiphy, ifp); brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0); brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0); - brcmf_configure_arp_nd_offload(ifp, true); + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND)) + brcmf_configure_arp_nd_offload(ifp, true); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, cfg->wowl.pre_pmmode); cfg->wowl.active = false; @@ -3580,7 +3581,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg, brcmf_dbg(TRACE, "Suspend, wowl config.\n"); - brcmf_configure_arp_nd_offload(ifp, false); + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND)) + brcmf_configure_arp_nd_offload(ifp, false); brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 098732a0c91b..bfa19bb632b7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -147,6 +147,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) { err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); if (!err) { + ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND); if (wowl_cap & BRCMF_WOWL_PFN_FOUND) ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ND); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index f940c29bcfaf..a3efa35a5c21 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -29,6 +29,7 @@ * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan. * WOWL_ND: WOWL net detect (PNO) * WOWL_GTK: (WOWL) GTK rekeying offload + * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -40,7 +41,8 @@ BRCMF_FEAT_DEF(TDLS) \ BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \ BRCMF_FEAT_DEF(WOWL_ND) \ - BRCMF_FEAT_DEF(WOWL_GTK) + BRCMF_FEAT_DEF(WOWL_GTK) \ + BRCMF_FEAT_DEF(WOWL_ARP_ND) /* * Quirks: -- cgit v1.2.3 From 4d7928959832ea41f7f91456b76da19cad01bd09 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:07 +0100 Subject: brcmfmac: switch to new platform data Platform data is only available for sdio. With this patch a new platform data structure is being used which allows for platform data for any device and configurable per device. This patch only switches to the new structure and adds support for SDIO devices. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 15 +---- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +- .../wireless/broadcom/brcm80211/brcmfmac/common.c | 43 ++++++++++-- .../wireless/broadcom/brcm80211/brcmfmac/common.h | 35 ++-------- .../net/wireless/broadcom/brcm80211/brcmfmac/of.c | 3 +- .../net/wireless/broadcom/brcm80211/brcmfmac/of.h | 5 +- .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 77 +++++++++++++--------- .../wireless/broadcom/brcm80211/brcmfmac/sdio.h | 2 +- 8 files changed, 97 insertions(+), 87 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 25cd71229c95..bb4aece9ad2c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -103,7 +103,7 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func) int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) { - struct brcmfmac_sdio_platform_data *pdata; + struct brcmfmac_sdio_pd *pdata; int ret = 0; u8 data; u32 addr, gpiocontrol; @@ -173,7 +173,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) { - struct brcmfmac_sdio_platform_data *pdata; + struct brcmfmac_sdio_pd *pdata; brcmf_dbg(SDIO, "Entering\n"); @@ -1164,17 +1164,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, dev_set_drvdata(&func->dev, bus_if); dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); sdiodev->dev = &sdiodev->func[1]->dev; - sdiodev->pdata = brcmf_get_module_param(sdiodev->dev); - -#ifdef CONFIG_PM_SLEEP - /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ - * is true or when platform data OOB irq is true). - */ - if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && - ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || - (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) - bus_if->wowl_supported = true; -#endif brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5609a79df1c1..5e3acaca7231 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6459,8 +6459,8 @@ int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg, static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2], struct brcmf_fil_country_le *ccreq) { - struct cc_translate *country_codes; - struct cc_entry *cc; + struct brcmfmac_pd_cc *country_codes; + struct brcmfmac_pd_cc_entry *cc; s32 found_index; int i; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 020901c2e0ca..4bd3225cdea6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -80,7 +80,7 @@ module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0); MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging"); #endif -static struct brcmfmac_sdio_platform_data *brcmfmac_pdata; +static struct brcmfmac_platform_data *brcmfmac_pdata; struct brcmf_mp_global_t brcmf_mp_global; int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) @@ -229,15 +229,46 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...) static void brcmf_mp_attach(void) { + /* If module param firmware path is set then this will always be used, + * if not set then if available use the platform data version. To make + * sure it gets initialized at all, always copy the module param version + */ strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path, BRCMF_FW_ALTPATH_LEN); + if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) && + (brcmf_mp_global.firmware_path[0] == '\0')) { + strlcpy(brcmf_mp_global.firmware_path, + brcmfmac_pdata->fw_alternative_path, + BRCMF_FW_ALTPATH_LEN); + } } -struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev) +struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, + enum brcmf_bus_type bus_type, + u32 chip, u32 chiprev) { - if (!brcmfmac_pdata) - brcmf_of_probe(dev, &brcmfmac_pdata); - return brcmfmac_pdata; + struct brcmfmac_sdio_pd *pdata; + struct brcmfmac_pd_device *device_pd; + int i; + + if (brcmfmac_pdata) { + for (i = 0; i < brcmfmac_pdata->device_count; i++) { + device_pd = &brcmfmac_pdata->devices[i]; + if ((device_pd->bus_type == bus_type) && + (device_pd->id == chip) && + ((device_pd->rev == chiprev) || + (device_pd->rev == -1))) { + brcmf_dbg(INFO, "Platform data for device found\n"); + if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO) + return &device_pd->bus.sdio; + break; + } + } + } + pdata = NULL; + brcmf_of_probe(dev, &pdata); + + return pdata; } int brcmf_mp_device_attach(struct brcmf_pub *drvr) @@ -287,7 +318,7 @@ static int brcmf_common_pd_remove(struct platform_device *pdev) static struct platform_driver brcmf_pd = { .remove = brcmf_common_pd_remove, .driver = { - .name = BRCMFMAC_SDIO_PDATA_NAME, + .name = BRCMFMAC_PDATA_NAME, } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 54a26ede808d..a64e40e8bfda 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -16,7 +16,7 @@ #define BRCMFMAC_COMMON_H #include -#include +#include #include "fwil_types.h" extern const u8 ALLFFMAC[ETH_ALEN]; @@ -42,33 +42,6 @@ struct brcmf_mp_global_t { extern struct brcmf_mp_global_t brcmf_mp_global; -/** - * struct cc_entry - Struct for translating user space country code (iso3166) to - * firmware country code and revision. - * - * @iso3166: iso3166 alpha 2 country code string. - * @cc: firmware country code string. - * @rev: firmware country code revision. - */ -struct cc_entry { - char iso3166[BRCMF_COUNTRY_BUF_SZ]; - char cc[BRCMF_COUNTRY_BUF_SZ]; - s32 rev; -}; - -/** - * struct cc_translate - Struct for translating country codes as set by user - * space to a country code and rev which can be used by - * firmware. - * - * @table_size: number of entries in table (> 0) - * @table: dynamic array of 1 or more elements with translation information. - */ -struct cc_translate { - int table_size; - struct cc_entry table[0]; -}; - /** * struct brcmf_mp_device - Device module paramaters. * @@ -88,10 +61,12 @@ struct brcmf_mp_device { int fcmode; bool roamoff; bool ignore_probe_fail; - struct cc_translate *country_codes; + struct brcmfmac_pd_cc *country_codes; }; -struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev); +struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, + enum brcmf_bus_type bus_type, + u32 chip, u32 chiprev); int brcmf_mp_device_attach(struct brcmf_pub *drvr); void brcmf_mp_device_detach(struct brcmf_pub *drvr); #ifdef DEBUG diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index 8201d937b826..ece0b65dd039 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -23,8 +23,7 @@ #include "common.h" #include "of.h" -void -brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio) +void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) { struct device_node *np = dev->of_node; int irq; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 84b474484cea..1ba951f9b542 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -15,10 +15,9 @@ */ #ifdef CONFIG_OF void -brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio); +brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio); #else -static void brcmf_of_probe(struct device *dev, - struct brcmfmac_sdio_platform_data **sdio) +static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) { } #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index c790fa89db05..6e367041f691 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include #include @@ -44,6 +42,8 @@ #include "sdio.h" #include "chip.h" #include "firmware.h" +#include "core.h" +#include "common.h" #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) @@ -3775,26 +3775,28 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { static bool brcmf_sdio_probe_attach(struct brcmf_sdio *bus) { + struct brcmf_sdio_dev *sdiodev; u8 clkctl = 0; int err = 0; int reg_addr; u32 reg_val; u32 drivestrength; - sdio_claim_host(bus->sdiodev->func[1]); + sdiodev = bus->sdiodev; + sdio_claim_host(sdiodev->func[1]); pr_debug("F1 signature read @0x18000000=0x%4x\n", - brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); + brcmf_sdiod_regrl(sdiodev, SI_ENUM_BASE, NULL)); /* * Force PLL off until brcmf_chip_attach() * programs PLL control regs */ - brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, BRCMF_INIT_CLKCTL1, &err); if (!err) - clkctl = brcmf_sdiod_regrb(bus->sdiodev, + clkctl = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err); if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { @@ -3803,50 +3805,77 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) goto fail; } - bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops); + bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops); if (IS_ERR(bus->ci)) { brcmf_err("brcmf_chip_attach failed!\n"); bus->ci = NULL; goto fail; } + sdiodev->pdata = brcmf_get_module_param(sdiodev->dev, + BRCMF_BUSTYPE_SDIO, + bus->ci->chip, + bus->ci->chiprev); + /* platform specific configuration: + * alignments must be at least 4 bytes for ADMA + */ + bus->head_align = ALIGNMENT; + bus->sgentry_align = ALIGNMENT; + if (sdiodev->pdata) { + if (sdiodev->pdata->sd_head_align > ALIGNMENT) + bus->head_align = sdiodev->pdata->sd_head_align; + if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) + bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; + } + /* allocate scatter-gather table. sg support + * will be disabled upon allocation failure. + */ + brcmf_sdiod_sgtable_alloc(sdiodev); + +#ifdef CONFIG_PM_SLEEP + /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ + * is true or when platform data OOB irq is true). + */ + if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && + ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || + (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) + sdiodev->bus_if->wowl_supported = true; +#endif if (brcmf_sdio_kso_init(bus)) { brcmf_err("error enabling KSO\n"); goto fail; } - if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength)) - drivestrength = bus->sdiodev->pdata->drive_strength; + if ((sdiodev->pdata) && (sdiodev->pdata->drive_strength)) + drivestrength = sdiodev->pdata->drive_strength; else drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; - brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength); + brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength); /* Set card control so an SDIO card reset does a WLAN backplane reset */ - reg_val = brcmf_sdiod_regrb(bus->sdiodev, - SDIO_CCCR_BRCM_CARDCTRL, &err); + reg_val = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, &err); if (err) goto fail; reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET; - brcmf_sdiod_regwb(bus->sdiodev, - SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err); if (err) goto fail; /* set PMUControl so a backplane reset does PMU state reload */ reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); - reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); + reg_val = brcmf_sdiod_regrl(sdiodev, reg_addr, &err); if (err) goto fail; reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT); - brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err); + brcmf_sdiod_regwl(sdiodev, reg_addr, reg_val, &err); if (err) goto fail; - sdio_release_host(bus->sdiodev->func[1]); + sdio_release_host(sdiodev->func[1]); brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); @@ -3867,7 +3896,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) return true; fail: - sdio_release_host(bus->sdiodev->func[1]); + sdio_release_host(sdiodev->func[1]); return false; } @@ -4045,18 +4074,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->txminmax = BRCMF_TXMINMAX; bus->tx_seq = SDPCM_SEQ_WRAP - 1; - /* platform specific configuration: - * alignments must be at least 4 bytes for ADMA - */ - bus->head_align = ALIGNMENT; - bus->sgentry_align = ALIGNMENT; - if (sdiodev->pdata) { - if (sdiodev->pdata->sd_head_align > ALIGNMENT) - bus->head_align = sdiodev->pdata->sd_head_align; - if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) - bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; - } - /* single-threaded workqueue */ wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM, dev_name(&sdiodev->func[1]->dev)); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index 23f223150cef..50df9cb21af2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -184,7 +184,7 @@ struct brcmf_sdio_dev { struct brcmf_sdio *bus; struct device *dev; struct brcmf_bus *bus_if; - struct brcmfmac_sdio_platform_data *pdata; + struct brcmfmac_sdio_pd *pdata; bool oob_irq_requested; bool irq_en; /* irq enable flags */ spinlock_t irq_en_lock; -- cgit v1.2.3 From af5b5e62f72e08e6e7e3d3cd78ee7e4cec96f7c8 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:08 +0100 Subject: brcmfmac: merge platform data and module paramaters Merge module parameters and platform data in one struct. This is the last step to move to the new platform data per device. Now parameters of platform data will be merged with module parameters per device. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 20 +++---- .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 4 +- .../wireless/broadcom/brcm80211/brcmfmac/common.c | 68 +++++++++++++--------- .../wireless/broadcom/brcm80211/brcmfmac/common.h | 39 +++++-------- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 11 +--- .../net/wireless/broadcom/brcm80211/brcmfmac/of.c | 14 ++--- .../net/wireless/broadcom/brcm80211/brcmfmac/of.h | 5 +- .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 24 ++++++-- .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 46 ++++++++------- .../wireless/broadcom/brcm80211/brcmfmac/sdio.h | 2 +- .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 16 ++++- 11 files changed, 139 insertions(+), 110 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index bb4aece9ad2c..da0cdd313880 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -109,8 +109,8 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) u32 addr, gpiocontrol; unsigned long flags; - pdata = sdiodev->pdata; - if ((pdata) && (pdata->oob_irq_supported)) { + pdata = &sdiodev->settings->bus.sdio; + if (pdata->oob_irq_supported) { brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", pdata->oob_irq_nr); ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, @@ -177,8 +177,8 @@ int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(SDIO, "Entering\n"); - pdata = sdiodev->pdata; - if ((pdata) && (pdata->oob_irq_supported)) { + pdata = &sdiodev->settings->bus.sdio; + if (pdata->oob_irq_supported) { sdio_claim_host(sdiodev->func[1]); brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); @@ -522,7 +522,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, target_list = pktlist; /* for host with broken sg support, prepare a page aligned list */ __skb_queue_head_init(&local_list); - if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) { + if (!write && sdiodev->settings->bus.sdio.broken_sg_support) { req_sz = 0; skb_queue_walk(pktlist, pkt_next) req_sz += pkt_next->len; @@ -629,7 +629,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, } } - if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) { + if (!write && sdiodev->settings->bus.sdio.broken_sg_support) { local_pkt_next = local_list.next; orig_offset = 0; skb_queue_walk(pktlist, pkt_next) { @@ -900,7 +900,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) return; nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, - sdiodev->bus_if->drvr->settings->sdiod_txglomsz); + sdiodev->settings->bus.sdio.txglomsz); nents += (nents >> 4) + 1; WARN_ON(nents > sdiodev->max_segment_count); @@ -912,7 +912,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) sdiodev->sg_support = false; } - sdiodev->txglomsz = sdiodev->bus_if->drvr->settings->sdiod_txglomsz; + sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz; } #ifdef CONFIG_PM_SLEEP @@ -1246,8 +1246,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev) sdio_flags = MMC_PM_KEEP_POWER; if (sdiodev->wowl_enabled) { - if (sdiodev->pdata->oob_irq_supported) - enable_irq_wake(sdiodev->pdata->oob_irq_nr); + if (sdiodev->settings->bus.sdio.oob_irq_supported) + enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); else sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 36093f93bfbe..8e02a478e889 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -43,6 +43,8 @@ enum brcmf_bus_protocol_type { BRCMF_PROTO_MSGBUF }; +struct brcmf_mp_device; + struct brcmf_bus_dcmd { char *name; char *param; @@ -217,7 +219,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp); /* Indication from bus module regarding presence/insertion of dongle. */ -int brcmf_attach(struct device *dev); +int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings); /* Indication from bus module regarding removal/absence of dongle */ void brcmf_detach(struct device *dev); /* Indication from bus module that dongle should be reset */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 4bd3225cdea6..9e909e3c2f0c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -243,14 +243,35 @@ static void brcmf_mp_attach(void) } } -struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, - enum brcmf_bus_type bus_type, - u32 chip, u32 chiprev) +struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, + enum brcmf_bus_type bus_type, + u32 chip, u32 chiprev) { - struct brcmfmac_sdio_pd *pdata; + struct brcmf_mp_device *settings; struct brcmfmac_pd_device *device_pd; + bool found; int i; + brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip, + chiprev); + settings = kzalloc(sizeof(*settings), GFP_ATOMIC); + if (!settings) + return NULL; + + /* start by using the module paramaters */ + settings->p2p_enable = !!brcmf_p2p_enable; + settings->feature_disable = brcmf_feature_disable; + settings->fcmode = brcmf_fcmode; + settings->roamoff = !!brcmf_roamoff; +#ifdef DEBUG + settings->ignore_probe_fail = !!brcmf_ignore_probe_fail; +#endif + + if (bus_type == BRCMF_BUSTYPE_SDIO) + settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz; + + /* See if there is any device specific platform data configured */ + found = false; if (brcmfmac_pdata) { for (i = 0; i < brcmfmac_pdata->device_count; i++) { device_pd = &brcmfmac_pdata->devices[i]; @@ -259,38 +280,29 @@ struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, ((device_pd->rev == chiprev) || (device_pd->rev == -1))) { brcmf_dbg(INFO, "Platform data for device found\n"); + settings->country_codes = + device_pd->country_codes; if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO) - return &device_pd->bus.sdio; + memcpy(&settings->bus.sdio, + &device_pd->bus.sdio, + sizeof(settings->bus.sdio)); + found = true; break; } } } - pdata = NULL; - brcmf_of_probe(dev, &pdata); - - return pdata; -} - -int brcmf_mp_device_attach(struct brcmf_pub *drvr) -{ - drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC); - if (!drvr->settings) - return -ENOMEM; - - drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz; - drvr->settings->p2p_enable = !!brcmf_p2p_enable; - drvr->settings->feature_disable = brcmf_feature_disable; - drvr->settings->fcmode = brcmf_fcmode; - drvr->settings->roamoff = !!brcmf_roamoff; -#ifdef DEBUG - drvr->settings->ignore_probe_fail = !!brcmf_ignore_probe_fail; -#endif - return 0; + if ((bus_type == BRCMF_BUSTYPE_SDIO) && (!found)) { + /* No platform data for this device. In case of SDIO try OF + * (Open Firwmare) Device Tree. + */ + brcmf_of_probe(dev, &settings->bus.sdio); + } + return settings; } -void brcmf_mp_device_detach(struct brcmf_pub *drvr) +void brcmf_release_module_param(struct brcmf_mp_device *module_param) { - kfree(drvr->settings); + kfree(module_param); } static int __init brcmf_common_pd_probe(struct platform_device *pdev) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index a64e40e8bfda..bd095abca393 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -45,41 +45,30 @@ extern struct brcmf_mp_global_t brcmf_mp_global; /** * struct brcmf_mp_device - Device module paramaters. * - * @sdiod_txglomsz: SDIO txglom size. - * @joinboost_5g_rssi: 5g rssi booost for preferred join selection. * @p2p_enable: Legacy P2P0 enable (old wpa_supplicant). * @feature_disable: Feature_disable bitmask. * @fcmode: FWS flow control. * @roamoff: Firmware roaming off? + * @ignore_probe_fail: Ignore probe failure. * @country_codes: If available, pointer to struct for translating country codes + * @bus: Bus specific platform data. Only SDIO at the mmoment. */ struct brcmf_mp_device { - int sdiod_txglomsz; - int joinboost_5g_rssi; - bool p2p_enable; - int feature_disable; - int fcmode; - bool roamoff; - bool ignore_probe_fail; + bool p2p_enable; + unsigned int feature_disable; + int fcmode; + bool roamoff; + bool ignore_probe_fail; struct brcmfmac_pd_cc *country_codes; + union { + struct brcmfmac_sdio_pd sdio; + } bus; }; -struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, - enum brcmf_bus_type bus_type, - u32 chip, u32 chiprev); -int brcmf_mp_device_attach(struct brcmf_pub *drvr); -void brcmf_mp_device_detach(struct brcmf_pub *drvr); -#ifdef DEBUG -static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr) -{ - return drvr->settings->ignore_probe_fail; -} -#else -static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr) -{ - return false; -} -#endif +struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, + enum brcmf_bus_type bus_type, + u32 chip, u32 chiprev); +void brcmf_release_module_param(struct brcmf_mp_device *module_param); /* Sets dongle media info (drv_version, mac address). */ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 7b24e2b71a43..ff825cd7739e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1104,7 +1104,7 @@ static int brcmf_inet6addr_changed(struct notifier_block *nb, } #endif -int brcmf_attach(struct device *dev) +int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) { struct brcmf_pub *drvr = NULL; int ret = 0; @@ -1126,10 +1126,7 @@ int brcmf_attach(struct device *dev) drvr->hdrlen = 0; drvr->bus_if = dev_get_drvdata(dev); drvr->bus_if->drvr = drvr; - - /* Initialize device specific settings */ - if (brcmf_mp_device_attach(drvr)) - goto fail; + drvr->settings = settings; /* attach debug facilities */ brcmf_debug_attach(drvr); @@ -1274,7 +1271,7 @@ fail: brcmf_net_detach(p2p_ifp->ndev); drvr->iflist[0] = NULL; drvr->iflist[1] = NULL; - if (brcmf_ignoring_probe_fail(drvr)) + if (drvr->settings->ignore_probe_fail) ret = 0; return ret; @@ -1350,8 +1347,6 @@ void brcmf_detach(struct device *dev) brcmf_proto_detach(drvr); - brcmf_mp_device_detach(drvr); - brcmf_debug_detach(drvr); bus_if->drvr = NULL; kfree(drvr); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index ece0b65dd039..425c41dc0a59 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -23,7 +23,7 @@ #include "common.h" #include "of.h" -void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) +void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio) { struct device_node *np = dev->of_node; int irq; @@ -33,12 +33,8 @@ void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) return; - *sdio = devm_kzalloc(dev, sizeof(*sdio), GFP_KERNEL); - if (!(*sdio)) - return; - if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) - (*sdio)->drive_strength = val; + sdio->drive_strength = val; /* make sure there are interrupts defined in the node */ if (!of_find_property(np, "interrupts", NULL)) @@ -51,7 +47,7 @@ void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) } irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); - (*sdio)->oob_irq_supported = true; - (*sdio)->oob_irq_nr = irq; - (*sdio)->oob_irq_flags = irqf; + sdio->oob_irq_supported = true; + sdio->oob_irq_nr = irq; + sdio->oob_irq_flags = irqf; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 1ba951f9b542..a9d94c15d0f5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -14,10 +14,9 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef CONFIG_OF -void -brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio); +void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio); #else -static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) +static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio) { } #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 1866b66b47f2..52fef5e1d615 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -37,6 +37,8 @@ #include "pcie.h" #include "firmware.h" #include "chip.h" +#include "core.h" +#include "common.h" enum brcmf_pcie_state { @@ -266,6 +268,7 @@ struct brcmf_pciedev_info { u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset); void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset, u16 value); + struct brcmf_mp_device *settings; }; struct brcmf_pcie_ringbuf { @@ -1525,16 +1528,16 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo) } -static int brcmf_pcie_attach_bus(struct device *dev) +static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo) { int ret; /* Attach to the common driver interface */ - ret = brcmf_attach(dev); + ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings); if (ret) { brcmf_err("brcmf_attach failed\n"); } else { - ret = brcmf_bus_start(dev); + ret = brcmf_bus_start(&devinfo->pdev->dev); if (ret) brcmf_err("dongle is not responding\n"); } @@ -1672,7 +1675,7 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw, init_waitqueue_head(&devinfo->mbdata_resp_wait); brcmf_pcie_intr_enable(devinfo); - if (brcmf_pcie_attach_bus(bus->dev) == 0) + if (brcmf_pcie_attach_bus(devinfo) == 0) return; brcmf_pcie_bus_console_read(devinfo); @@ -1716,6 +1719,15 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto fail; } + devinfo->settings = brcmf_get_module_param(&devinfo->pdev->dev, + BRCMF_BUSTYPE_PCIE, + devinfo->ci->chip, + devinfo->ci->chiprev); + if (!devinfo->settings) { + ret = -ENOMEM; + goto fail; + } + bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (!bus) { ret = -ENOMEM; @@ -1760,6 +1772,8 @@ fail: brcmf_pcie_release_resource(devinfo); if (devinfo->ci) brcmf_chip_detach(devinfo->ci); + if (devinfo->settings) + brcmf_release_module_param(devinfo->settings); kfree(pcie_bus_dev); kfree(devinfo); return ret; @@ -1799,6 +1813,8 @@ brcmf_pcie_remove(struct pci_dev *pdev) if (devinfo->ci) brcmf_chip_detach(devinfo->ci); + if (devinfo->settings) + brcmf_release_module_param(devinfo->settings); kfree(devinfo); dev_set_drvdata(&pdev->dev, NULL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 6e367041f691..43fd3f402eba 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -2442,15 +2442,17 @@ static void brcmf_sdio_bus_stop(struct device *dev) static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) { + struct brcmf_sdio_dev *sdiodev; unsigned long flags; - if (bus->sdiodev->oob_irq_requested) { - spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags); - if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) { - enable_irq(bus->sdiodev->pdata->oob_irq_nr); - bus->sdiodev->irq_en = true; + sdiodev = bus->sdiodev; + if (sdiodev->oob_irq_requested) { + spin_lock_irqsave(&sdiodev->irq_en_lock, flags); + if (!sdiodev->irq_en && !atomic_read(&bus->ipend)) { + enable_irq(sdiodev->settings->bus.sdio.oob_irq_nr); + sdiodev->irq_en = true; } - spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags); + spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); } } @@ -3394,9 +3396,7 @@ static int brcmf_sdio_bus_preinit(struct device *dev) sizeof(u32)); } else { /* otherwise, set txglomalign */ - value = 4; - if (sdiodev->pdata) - value = sdiodev->pdata->sd_sgentry_align; + value = sdiodev->settings->bus.sdio.sd_sgentry_align; /* SDIO ADMA requires at least 32 bit alignment */ value = max_t(u32, value, 4); err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value, @@ -3811,21 +3811,25 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) bus->ci = NULL; goto fail; } - sdiodev->pdata = brcmf_get_module_param(sdiodev->dev, + sdiodev->settings = brcmf_get_module_param(sdiodev->dev, BRCMF_BUSTYPE_SDIO, bus->ci->chip, bus->ci->chiprev); + if (!sdiodev->settings) { + brcmf_err("Failed to get device parameters\n"); + goto fail; + } /* platform specific configuration: * alignments must be at least 4 bytes for ADMA */ bus->head_align = ALIGNMENT; bus->sgentry_align = ALIGNMENT; - if (sdiodev->pdata) { - if (sdiodev->pdata->sd_head_align > ALIGNMENT) - bus->head_align = sdiodev->pdata->sd_head_align; - if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) - bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; - } + if (sdiodev->settings->bus.sdio.sd_head_align > ALIGNMENT) + bus->head_align = sdiodev->settings->bus.sdio.sd_head_align; + if (sdiodev->settings->bus.sdio.sd_sgentry_align > ALIGNMENT) + bus->sgentry_align = + sdiodev->settings->bus.sdio.sd_sgentry_align; + /* allocate scatter-gather table. sg support * will be disabled upon allocation failure. */ @@ -3837,7 +3841,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) */ if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || - (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) + (sdiodev->settings->bus.sdio.oob_irq_supported))) sdiodev->bus_if->wowl_supported = true; #endif @@ -3846,8 +3850,8 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) goto fail; } - if ((sdiodev->pdata) && (sdiodev->pdata->drive_strength)) - drivestrength = sdiodev->pdata->drive_strength; + if (sdiodev->settings->bus.sdio.drive_strength) + drivestrength = sdiodev->settings->bus.sdio.drive_strength; else drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength); @@ -4124,7 +4128,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; /* Attach to the common layer, reserve hdr space */ - ret = brcmf_attach(bus->sdiodev->dev); + ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings); if (ret != 0) { brcmf_err("brcmf_attach failed\n"); goto fail; @@ -4228,6 +4232,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) } brcmf_chip_detach(bus->ci); } + if (bus->sdiodev->settings) + brcmf_release_module_param(bus->sdiodev->settings); kfree(bus->rxbuf); kfree(bus->hdrbuf); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index 50df9cb21af2..dcf0ce8cd2c1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -184,7 +184,7 @@ struct brcmf_sdio_dev { struct brcmf_sdio *bus; struct device *dev; struct brcmf_bus *bus_if; - struct brcmfmac_sdio_pd *pdata; + struct brcmf_mp_device *settings; bool oob_irq_requested; bool irq_en; /* irq enable flags */ spinlock_t irq_en_lock; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index c72b7b352a77..869eb82db8b1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -27,6 +27,8 @@ #include "debug.h" #include "firmware.h" #include "usb.h" +#include "core.h" +#include "common.h" #define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000) @@ -171,6 +173,7 @@ struct brcmf_usbdev_info { struct urb *bulk_urb; /* used for FW download */ bool wowl_enabled; + struct brcmf_mp_device *settings; }; static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, @@ -1027,6 +1030,9 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo) kfree(devinfo->tx_reqs); kfree(devinfo->rx_reqs); + + if (devinfo->settings) + brcmf_release_module_param(devinfo->settings); } @@ -1136,7 +1142,7 @@ static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo) int ret; /* Attach to the common driver interface */ - ret = brcmf_attach(devinfo->dev); + ret = brcmf_attach(devinfo->dev, devinfo->settings); if (ret) { brcmf_err("brcmf_attach failed\n"); return ret; @@ -1223,6 +1229,14 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) bus->wowl_supported = true; #endif + devinfo->settings = brcmf_get_module_param(bus->dev, BRCMF_BUSTYPE_USB, + bus_pub->devid, + bus_pub->chiprev); + if (!devinfo->settings) { + ret = -ENOMEM; + goto fail; + } + if (!brcmf_usb_dlneeded(devinfo)) { ret = brcmf_usb_bus_setup(devinfo); if (ret) -- cgit v1.2.3 From 219e0f747ad6d2b504199dbbaee6b9ad269dde07 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:09 +0100 Subject: brcmfmac: integrate add_keyext in add_key brcmf_add_keyext is called when a key is configured for a specific mac address. This function is very similar to the calling function brcmf_add_key. Integrate this function and also use existing del_key function in case key is to be cleared. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 154 ++++++--------------- 1 file changed, 39 insertions(+), 115 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5e3acaca7231..5203d8f38474 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2073,84 +2073,34 @@ done: } static s32 -brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, const u8 *mac_addr, struct key_params *params) +brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_idx, bool pairwise, const u8 *mac_addr) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_wsec_key key; s32 err = 0; - u8 keybuf[8]; + + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) + return -EIO; + + if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + return -EINVAL; + } memset(&key, 0, sizeof(key)); - key.index = (u32) key_idx; - /* Instead of bcast for ea address for default wep keys, - driver needs it to be Null */ - if (!is_multicast_ether_addr(mac_addr)) - memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); - key.len = (u32) params->key_len; - /* check for key index change */ - if (key.len == 0) { - /* key delete */ - err = send_key_to_dongle(ifp, &key); - if (err) - brcmf_err("key delete error (%d)\n", err); - } else { - if (key.len > sizeof(key.data)) { - brcmf_err("Invalid key length (%d)\n", key.len); - return -EINVAL; - } - brcmf_dbg(CONN, "Setting the key index %d\n", key.index); - memcpy(key.data, params->key, key.len); + key.index = (u32)key_idx; + key.flags = BRCMF_PRIMARY_KEY; + key.algo = CRYPTO_ALGO_OFF; - if (!brcmf_is_apmode(ifp->vif) && - (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { - brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); - memcpy(keybuf, &key.data[24], sizeof(keybuf)); - memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); - memcpy(&key.data[16], keybuf, sizeof(keybuf)); - } + brcmf_dbg(CONN, "key index (%d)\n", key_idx); - /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ - if (params->seq && params->seq_len == 6) { - /* rx iv */ - u8 *ivptr; - ivptr = (u8 *) params->seq; - key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | - (ivptr[3] << 8) | ivptr[2]; - key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; - key.iv_initialized = true; - } + /* Set the new key/index */ + err = send_key_to_dongle(ifp, &key); - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); - break; - case WLAN_CIPHER_SUITE_TKIP: - key.algo = CRYPTO_ALGO_TKIP; - brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); - break; - default: - brcmf_err("Invalid cipher (0x%x)\n", params->cipher); - return -EINVAL; - } - err = send_key_to_dongle(ifp, &key); - if (err) - brcmf_err("wsec_key error (%d)\n", err); - } + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -2163,8 +2113,9 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_wsec_key *key; s32 val; s32 wsec; - s32 err = 0; + s32 err; u8 keybuf[8]; + bool ext_key; brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(CONN, "key index (%d)\n", key_idx); @@ -2177,27 +2128,32 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return -EINVAL; } - if (mac_addr && - (params->cipher != WLAN_CIPHER_SUITE_WEP40) && - (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { - brcmf_dbg(TRACE, "Exit"); - return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); - } - - key = &ifp->vif->profile.key[key_idx]; - memset(key, 0, sizeof(*key)); + if (params->key_len == 0) + return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise, + mac_addr); if (params->key_len > sizeof(key->data)) { brcmf_err("Too long key length (%u)\n", params->key_len); - err = -EINVAL; - goto done; + return -EINVAL; } + + ext_key = false; + if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) && + (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { + brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr); + ext_key = true; + } + + key = &ifp->vif->profile.key[key_idx]; + memset(key, 0, sizeof(*key)); + if ((ext_key) && (!is_multicast_ether_addr(mac_addr))) + memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN); key->len = params->key_len; key->index = key_idx; - memcpy(key->data, params->key, key->len); + if (!ext_key) + key->flags = BRCMF_PRIMARY_KEY; - key->flags = BRCMF_PRIMARY_KEY; switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: key->algo = CRYPTO_ALGO_WEP1; @@ -2237,7 +2193,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, } err = send_key_to_dongle(ifp, key); - if (err) + if (ext_key || err) goto done; err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); @@ -2257,38 +2213,6 @@ done: return err; } -static s32 -brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool pairwise, const u8 *mac_addr) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_wsec_key key; - s32 err = 0; - - brcmf_dbg(TRACE, "Enter\n"); - if (!check_vif_up(ifp->vif)) - return -EIO; - - if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { - /* we ignore this key index in this case */ - return -EINVAL; - } - - memset(&key, 0, sizeof(key)); - - key.index = (u32) key_idx; - key.flags = BRCMF_PRIMARY_KEY; - key.algo = CRYPTO_ALGO_OFF; - - brcmf_dbg(CONN, "key index (%d)\n", key_idx); - - /* Set the new key/index */ - err = send_key_to_dongle(ifp, &key); - - brcmf_dbg(TRACE, "Exit\n"); - return err; -} - static s32 brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, -- cgit v1.2.3 From 240d61a9ddeb8a77f11369f67f6ef060354b909d Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 17 Feb 2016 11:27:10 +0100 Subject: brcmfmac: add 802.11w management frame protection support Add full support for both AP and STA for management frame protection. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 272 +++++++++++++++------ .../broadcom/brcm80211/brcmfmac/cfg80211.h | 3 +- .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 + .../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +- .../broadcom/brcm80211/brcmfmac/fwil_types.h | 4 + .../broadcom/brcm80211/include/brcmu_wifi.h | 2 + 6 files changed, 211 insertions(+), 75 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5203d8f38474..d5c2a27573b4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -72,8 +72,13 @@ #define RSN_AKM_NONE 0 /* None (IBSS) */ #define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ #define RSN_AKM_PSK 2 /* Pre-shared Key */ +#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */ +#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */ #define RSN_CAP_LEN 2 /* Length of RSN capabilities */ -#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C +#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3)) +#define RSN_CAP_MFPR_MASK BIT(6) +#define RSN_CAP_MFPC_MASK BIT(7) +#define RSN_PMKID_COUNT_LEN 2 #define VNDR_IE_CMD_LEN 4 /* length of the set command * string :"add", "del" (+ NUL) @@ -211,12 +216,19 @@ static const struct ieee80211_regdomain brcmf_regdom = { REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), } }; -static const u32 __wl_cipher_suites[] = { +/* Note: brcmf_cipher_suites is an array of int defining which cipher suites + * are supported. A pointer to this array and the number of entries is passed + * on to upper layers. AES_CMAC defines whether or not the driver supports MFP. + * So the cipher suite AES_CMAC has to be the last one in the array, and when + * device does not support MFP then the number of suites will be decreased by 1 + */ +static const u32 brcmf_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, - WLAN_CIPHER_SUITE_AES_CMAC, + /* Keep as last entry: */ + WLAN_CIPHER_SUITE_AES_CMAC }; /* Vendor specific ie. id = 221, oui and type defines exact ie */ @@ -1533,7 +1545,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, static s32 brcmf_set_wsec_mode(struct net_device *ndev, - struct cfg80211_connect_params *sme, bool mfp) + struct cfg80211_connect_params *sme) { struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; @@ -1592,10 +1604,7 @@ brcmf_set_wsec_mode(struct net_device *ndev, sme->privacy) pval = AES_ENABLED; - if (mfp) - wsec = pval | gval | MFP_CAPABLE; - else - wsec = pval | gval; + wsec = pval | gval; err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec); if (err) { brcmf_err("error (%d)\n", err); @@ -1612,56 +1621,100 @@ brcmf_set_wsec_mode(struct net_device *ndev, static s32 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); - struct brcmf_cfg80211_security *sec; - s32 val = 0; - s32 err = 0; + struct brcmf_if *ifp = netdev_priv(ndev); + s32 val; + s32 err; + const struct brcmf_tlv *rsn_ie; + const u8 *ie; + u32 ie_len; + u32 offset; + u16 rsn_cap; + u32 mfp; + u16 count; - if (sme->crypto.n_akm_suites) { - err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), - "wpa_auth", &val); - if (err) { - brcmf_err("could not get wpa_auth (%d)\n", err); - return err; + if (!sme->crypto.n_akm_suites) + return 0; + + err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val); + if (err) { + brcmf_err("could not get wpa_auth (%d)\n", err); + return err; + } + if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA_AUTH_PSK; + break; + default: + brcmf_err("invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; } - if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_PSK: - val = WPA_AUTH_PSK; - break; - default: - brcmf_err("invalid cipher group (%d)\n", - sme->crypto.cipher_group); - return -EINVAL; - } - } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA2_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_PSK: - val = WPA2_AUTH_PSK; - break; - default: - brcmf_err("invalid cipher group (%d)\n", - sme->crypto.cipher_group); - return -EINVAL; - } + } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_8021X_SHA256: + val = WPA2_AUTH_1X_SHA256; + break; + case WLAN_AKM_SUITE_PSK_SHA256: + val = WPA2_AUTH_PSK_SHA256; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA2_AUTH_PSK; + break; + default: + brcmf_err("invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; } + } - brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), - "wpa_auth", val); - if (err) { - brcmf_err("could not set wpa_auth (%d)\n", err); - return err; - } + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) + goto skip_mfp_config; + /* The MFP mode (1 or 2) needs to be determined, parse IEs. The + * IE will not be verified, just a quick search for MFP config + */ + rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len, + WLAN_EID_RSN); + if (!rsn_ie) + goto skip_mfp_config; + ie = (const u8 *)rsn_ie; + ie_len = rsn_ie->len + TLV_HDR_LEN; + /* Skip unicast suite */ + offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN; + if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len) + goto skip_mfp_config; + /* Skip multicast suite */ + count = ie[offset] + (ie[offset + 1] << 8); + offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN); + if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len) + goto skip_mfp_config; + /* Skip auth key management suite(s) */ + count = ie[offset] + (ie[offset + 1] << 8); + offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN); + if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len) + goto skip_mfp_config; + /* Ready to read capabilities */ + mfp = BRCMF_MFP_NONE; + rsn_cap = ie[offset] + (ie[offset + 1] << 8); + if (rsn_cap & RSN_CAP_MFPR_MASK) + mfp = BRCMF_MFP_REQUIRED; + else if (rsn_cap & RSN_CAP_MFPC_MASK) + mfp = BRCMF_MFP_CAPABLE; + brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp); + +skip_mfp_config: + brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); + if (err) { + brcmf_err("could not set wpa_auth (%d)\n", err); + return err; } - sec = &profile->sec; - sec->wpa_auth = sme->crypto.akm_suites[0]; return err; } @@ -1827,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED); + err = brcmf_set_wsec_mode(ndev, sme); if (err) { brcmf_err("wl_set_set_cipher failed (%d)\n", err); goto done; @@ -2077,10 +2130,12 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_wsec_key key; - s32 err = 0; + struct brcmf_wsec_key *key; + s32 err; brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CONN, "key index (%d)\n", key_idx); + if (!check_vif_up(ifp->vif)) return -EIO; @@ -2089,16 +2144,19 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, return -EINVAL; } - memset(&key, 0, sizeof(key)); + key = &ifp->vif->profile.key[key_idx]; - key.index = (u32)key_idx; - key.flags = BRCMF_PRIMARY_KEY; - key.algo = CRYPTO_ALGO_OFF; + if (key->algo == CRYPTO_ALGO_OFF) { + brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n"); + return -EINVAL; + } - brcmf_dbg(CONN, "key index (%d)\n", key_idx); + memset(key, 0, sizeof(*key)); + key->index = (u32)key_idx; + key->flags = BRCMF_PRIMARY_KEY; - /* Set the new key/index */ - err = send_key_to_dongle(ifp, &key); + /* Clear the key/index */ + err = send_key_to_dongle(ifp, key); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -2106,8 +2164,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, static s32 brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params) + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_wsec_key *key; @@ -2214,9 +2272,10 @@ done: } static s32 -brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, - void (*callback) (void *cookie, struct key_params * params)) +brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, + bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *params)) { struct key_params params; struct brcmf_if *ifp = netdev_priv(ndev); @@ -2268,8 +2327,15 @@ done: static s32 brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *ndev, u8 key_idx) + struct net_device *ndev, u8 key_idx) { + struct brcmf_if *ifp = netdev_priv(ndev); + + brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx); + + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) + return 0; + brcmf_dbg(INFO, "Not supported\n"); return -EOPNOTSUPP; @@ -3769,7 +3835,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, u32 auth = 0; /* d11 open authentication */ u16 count; s32 err = 0; - s32 len = 0; + s32 len; u32 i; u32 wsec; u32 pval = 0; @@ -3779,6 +3845,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, u8 *data; u16 rsn_cap; u32 wme_bss_disable; + u32 mfp; brcmf_dbg(TRACE, "Enter\n"); if (wpa_ie == NULL) @@ -3893,19 +3960,53 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) : (wpa_auth |= WPA_AUTH_PSK); break; + case RSN_AKM_SHA256_PSK: + brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n"); + wpa_auth |= WPA2_AUTH_PSK_SHA256; + break; + case RSN_AKM_SHA256_1X: + brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n"); + wpa_auth |= WPA2_AUTH_1X_SHA256; + break; default: brcmf_err("Ivalid key mgmt info\n"); } offset++; } + mfp = BRCMF_MFP_NONE; if (is_rsn_ie) { wme_bss_disable = 1; if ((offset + RSN_CAP_LEN) <= len) { rsn_cap = data[offset] + (data[offset + 1] << 8); if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK) wme_bss_disable = 0; + if (rsn_cap & RSN_CAP_MFPR_MASK) { + brcmf_dbg(TRACE, "MFP Required\n"); + mfp = BRCMF_MFP_REQUIRED; + /* Firmware only supports mfp required in + * combination with WPA2_AUTH_PSK_SHA256 or + * WPA2_AUTH_1X_SHA256. + */ + if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 | + WPA2_AUTH_1X_SHA256))) { + err = -EINVAL; + goto exit; + } + /* Firmware has requirement that WPA2_AUTH_PSK/ + * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI + * is to be included in the rsn ie. + */ + if (wpa_auth & WPA2_AUTH_PSK_SHA256) + wpa_auth |= WPA2_AUTH_PSK; + else if (wpa_auth & WPA2_AUTH_1X_SHA256) + wpa_auth |= WPA2_AUTH_UNSPECIFIED; + } else if (rsn_cap & RSN_CAP_MFPC_MASK) { + brcmf_dbg(TRACE, "MFP Capable\n"); + mfp = BRCMF_MFP_CAPABLE; + } } + offset += RSN_CAP_LEN; /* set wme_bss_disable to sync RSN Capabilities */ err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable", wme_bss_disable); @@ -3913,6 +4014,21 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, brcmf_err("wme_bss_disable error %d\n", err); goto exit; } + + /* Skip PMKID cnt as it is know to be 0 for AP. */ + offset += RSN_PMKID_COUNT_LEN; + + /* See if there is BIP wpa suite left for MFP */ + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) && + ((offset + WPA_IE_MIN_OUI_LEN) <= len)) { + err = brcmf_fil_bsscfg_data_set(ifp, "bip", + &data[offset], + WPA_IE_MIN_OUI_LEN); + if (err < 0) { + brcmf_err("bip error %d\n", err); + goto exit; + } + } } /* FOR WPS , set SES_OW_ENABLED */ wsec = (pval | gval | SES_OW_ENABLED); @@ -3929,6 +4045,16 @@ brcmf_configure_wpaie(struct brcmf_if *ifp, brcmf_err("wsec error %d\n", err); goto exit; } + /* Configure MFP, this needs to go after wsec otherwise the wsec command + * will overwrite the values set by MFP + */ + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) { + err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp); + if (err < 0) { + brcmf_err("mfp error %d\n", err); + goto exit; + } + } /* set upper-layer auth */ err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth); if (err < 0) { @@ -6149,8 +6275,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->n_addresses = i; wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wiphy->cipher_suites = __wl_cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); + wiphy->cipher_suites = brcmf_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites); + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) + wiphy->n_cipher_suites--; wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index e4c1d4364684..95e35bcc16ce 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -72,7 +72,7 @@ #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 -#define BRCMF_MAX_DEFAULT_KEYS 4 +#define BRCMF_MAX_DEFAULT_KEYS 6 /* beacon loss timeout defaults */ #define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON 2 @@ -107,7 +107,6 @@ struct brcmf_cfg80211_security { u32 auth_type; u32 cipher_pairwise; u32 cipher_group; - u32 wpa_auth; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index bfa19bb632b7..62985f2c0853 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -161,6 +161,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable"); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp"); pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index a3efa35a5c21..db4733a95e28 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -30,6 +30,7 @@ * WOWL_ND: WOWL net detect (PNO) * WOWL_GTK: (WOWL) GTK rekeying offload * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. + * MFP: 802.11w Management Frame Protection. */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -42,7 +43,8 @@ BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \ BRCMF_FEAT_DEF(WOWL_ND) \ BRCMF_FEAT_DEF(WOWL_GTK) \ - BRCMF_FEAT_DEF(WOWL_ARP_ND) + BRCMF_FEAT_DEF(WOWL_ARP_ND) \ + BRCMF_FEAT_DEF(MFP) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 6d41ae392a8f..a4118c0ef6ca 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -142,6 +142,10 @@ #define BRCMF_RSN_KEK_LENGTH 16 #define BRCMF_RSN_REPLAY_LEN 8 +#define BRCMF_MFP_NONE 0 +#define BRCMF_MFP_CAPABLE 1 +#define BRCMF_MFP_REQUIRED 2 + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { BRCMF_JOIN_PREF_RSSI = 1, diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h index 3f68dd5ecd11..7b9a77981df1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h @@ -236,6 +236,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) #define WPA2_AUTH_RESERVED3 0x0200 #define WPA2_AUTH_RESERVED4 0x0400 #define WPA2_AUTH_RESERVED5 0x0800 +#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */ +#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ #define DOT11_DEFAULT_RTS_LEN 2347 #define DOT11_DEFAULT_FRAG_LEN 2346 -- cgit v1.2.3 From 8dd37c7cd442411f52b90e8b556d38324450de46 Mon Sep 17 00:00:00 2001 From: Amitoj Kaur Chawla Date: Wed, 17 Feb 2016 18:03:37 +0530 Subject: mwifiex: Use to_delayed_work() Introduce the use of to_delayed_work() helper function instead of open coding it with container_of() A simplified version of the Coccinelle semantic patch used to make this change is: // @@ expression a; symbol work; @@ - container_of(a, struct delayed_work, work) + to_delayed_work(a) // Signed-off-by: Amitoj Kaur Chawla Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/11h.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 71a1b580796f..81c60d0a1bda 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -123,8 +123,7 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, void mwifiex_dfs_cac_work_queue(struct work_struct *work) { struct cfg80211_chan_def chandef; - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); + struct delayed_work *delayed_work = to_delayed_work(work); struct mwifiex_private *priv = container_of(delayed_work, struct mwifiex_private, dfs_cac_work); @@ -289,8 +288,7 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) { struct mwifiex_uap_bss_param *bss_cfg; - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); + struct delayed_work *delayed_work = to_delayed_work(work); struct mwifiex_private *priv = container_of(delayed_work, struct mwifiex_private, dfs_chan_sw_work); -- cgit v1.2.3 From 064b32f822afd9a578a4ec6bf754cd61cbe0c324 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sun, 21 Feb 2016 01:30:29 +0300 Subject: at76c50x-usb: avoid double usb_put_dev() after downloading internal firmware in at76_probe() There is no need in usb_put_dev() if at76_load_internal_fw() succeed. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Kalle Valo --- drivers/net/wireless/atmel/at76c50x-usb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index dab25136214a..1efb1d66e0b7 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -2481,9 +2481,7 @@ static int at76_probe(struct usb_interface *interface, dev_err(&interface->dev, "error %d downloading internal firmware\n", ret); - goto exit; } - usb_put_dev(udev); goto exit; } -- cgit v1.2.3 From ce2542435aadc9953656e8afddaab0caf0079a3a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 22 Feb 2016 11:35:46 +0000 Subject: rtlwifi: pass struct rtl_stats by reference as it is more efficient passing rtl_stats by value is inefficient; the structure is over 300 bytes in size and generally just one field (packet_report_type) is being accessed, so the pass by value is a relatively large overhead. This change just affects just the rx_command_packet calls. Signed-off-by: Colin Ian King Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/pci.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h | 2 +- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 140d2541562d..283d608b9973 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -855,7 +855,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } /* handle command packet here */ if (rtlpriv->cfg->ops->rx_command_packet && - rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { + rtlpriv->cfg->ops->rx_command_packet(hw, &stats, skb)) { dev_kfree_skb_any(skb); goto new_trx_end; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c index 791efbe6b18c..11701064b0e1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c @@ -851,7 +851,7 @@ void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) } u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb) { return 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h index eab5ae0eb46c..5a24d194ac76 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h @@ -790,7 +790,7 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index d39ee67f6113..24eff8ea4c2e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -1105,13 +1105,13 @@ void rtl92ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) } u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb) { u32 result = 0; struct rtl_priv *rtlpriv = rtl_priv(hw); - switch (status.packet_report_type) { + switch (status->packet_report_type) { case NORMAL_RX: result = 0; break; @@ -1121,7 +1121,7 @@ u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, break; default: RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE, - "Unknown packet type %d\n", status.packet_report_type); + "Unknown packet type %d\n", status->packet_report_type); break; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h index 8f78ac9e6040..a4c38345233e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h @@ -857,6 +857,6 @@ void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c index 2f7c144d7980..7b4a9b63583b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c @@ -710,7 +710,7 @@ void rtl8723e_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) } u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb) { return 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h index 017da7e194d8..32970bf18856 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h @@ -716,6 +716,6 @@ void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index 338ec9a9d09b..60345975f9fd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -758,13 +758,13 @@ void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) } u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb) { u32 result = 0; struct rtl_priv *rtlpriv = rtl_priv(hw); - switch (status.packet_report_type) { + switch (status->packet_report_type) { case NORMAL_RX: result = 0; break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h index 45949ac4854c..40c36607b8b9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h @@ -620,6 +620,6 @@ void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index 174743aef943..41efaa148d13 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -998,13 +998,13 @@ void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) } u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb) { u32 result = 0; struct rtl_priv *rtlpriv = rtl_priv(hw); - switch (status.packet_report_type) { + switch (status->packet_report_type) { case NORMAL_RX: result = 0; break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h index 31409042d8dd..ad565bebf1d5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h @@ -615,6 +615,6 @@ void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw, - struct rtl_stats status, + const struct rtl_stats *status, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 9e3cdd732eca..b07b364b93ab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2189,7 +2189,7 @@ struct rtl_hal_ops { bool (*get_btc_status) (void); bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr); u32 (*rx_command_packet)(struct ieee80211_hw *hw, - struct rtl_stats status, struct sk_buff *skb); + const struct rtl_stats *status, struct sk_buff *skb); void (*add_wowlan_pattern)(struct ieee80211_hw *hw, struct rtl_wow_pattern *rtl_pattern, u8 index); -- cgit v1.2.3 From de651ce3d750c19a7b8b7cef22407ecc496619f4 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Feb 2016 05:16:16 -0800 Subject: mwifiex: add delay when tdls confirm frame is queued It is observed that driver may send the data packet to tdls peer before tdls peer receives tdls setup confirm frame. Similar race condition exists during tdls teardown procedure also. This patch adds 10 milliseconds delay to resolve the race. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/tdls.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 9275f9c3f869..150649602e98 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -680,6 +680,13 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); + /* Delay 10ms to make sure tdls setup confirm/teardown frame + * is received by peer + */ + if (action_code == WLAN_TDLS_SETUP_CONFIRM || + action_code == WLAN_TDLS_TEARDOWN) + msleep_interruptible(10); + return 0; } -- cgit v1.2.3 From a6139b6271f9f95377fe3486aed6120c9142779b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 23 Feb 2016 05:16:17 -0800 Subject: mwifiex: fix corner case association failure This patch corrects the error case in association path by returning -1. Earlier "media_connected" used to remain on in this error case causing failure for further association attempts. Signed-off-by: Amitkumar Karwar Fixes: b887664d882ee4 ('mwifiex: channel switch handling for station') Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 5cbee58f8781..d5c56eb9e985 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -314,6 +314,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, mwifiex_dbg(adapter, ERROR, "Attempt to reconnect on csa closed chan(%d)\n", bss_desc->channel); + ret = -1; goto done; } -- cgit v1.2.3 From 8b7ef8b66eb9127b6d2ee46348b3f743bb40facb Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Feb 2016 05:16:18 -0800 Subject: mwifiex: add sdio multiport aggregation debug information This patch sdio multi port aggregation statistics which can be used for debugging. This debug data is collected in /sys/kernel/debug/mwifiex/mlan0/debug. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/ioctl.h | 6 ++++++ drivers/net/wireless/marvell/mwifiex/main.h | 5 +++++ drivers/net/wireless/marvell/mwifiex/sdio.c | 10 ++++++++++ drivers/net/wireless/marvell/mwifiex/util.c | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 14cfa37deb00..a5a48c183d37 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -184,6 +184,7 @@ struct mwifiex_ds_tx_ba_stream_tbl { }; #define DBG_CMD_NUM 5 +#define MWIFIEX_DBG_SDIO_MP_NUM 10 struct tdls_peer_info { u8 peer_addr[ETH_ALEN]; @@ -235,6 +236,11 @@ struct mwifiex_debug_info { u8 cmd_sent; u8 cmd_resp_received; u8 event_received; + u32 last_mp_wr_bitmap[MWIFIEX_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_ports[MWIFIEX_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_len[MWIFIEX_DBG_SDIO_MP_NUM]; + u32 last_mp_curr_wr_port[MWIFIEX_DBG_SDIO_MP_NUM]; + u8 last_sdio_mp_index; }; #define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index aea7aee46cf7..aafc4ab4e5ae 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -223,6 +223,11 @@ struct mwifiex_dbg { u16 last_cmd_resp_index; u16 last_event[DBG_CMD_NUM]; u16 last_event_index; + u32 last_mp_wr_bitmap[MWIFIEX_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_ports[MWIFIEX_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_len[MWIFIEX_DBG_SDIO_MP_NUM]; + u32 last_mp_curr_wr_port[MWIFIEX_DBG_SDIO_MP_NUM]; + u8 last_sdio_mp_index; }; enum MWIFIEX_HARDWARE_STATUS { diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index abf15dbdfe08..838b260f86fa 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1684,6 +1684,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, s32 f_precopy_cur_buf = 0; s32 f_postcopy_cur_buf = 0; u32 mport; + int index; if (!card->mpa_tx.enabled || (card->has_control_mask && (port == CTRL_PORT)) || @@ -1788,6 +1789,15 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, card->mpa_tx.buf_len, mport); + /* Save the last multi port tx aggreagation info to debug log */ + index = adapter->dbg.last_sdio_mp_index; + index = (index + 1) % MWIFIEX_DBG_SDIO_MP_NUM; + adapter->dbg.last_sdio_mp_index = index; + adapter->dbg.last_mp_wr_ports[index] = mport; + adapter->dbg.last_mp_wr_bitmap[index] = card->mp_wr_bitmap; + adapter->dbg.last_mp_wr_len[index] = card->mpa_tx.buf_len; + adapter->dbg.last_mp_curr_wr_port[index] = card->curr_wr_port; + MP_TX_AGGR_BUF_RESET(card); } diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 0cec8a64473e..6681be0511c7 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -78,6 +78,16 @@ static struct mwifiex_debug_data items[] = { item_addr(last_event), DBG_CMD_NUM}, {"last_event_index", item_size(last_event_index), item_addr(last_event_index), 1}, + {"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap), + item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM}, + {"last_mp_wr_ports", item_size(last_mp_wr_ports), + item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM}, + {"last_mp_wr_len", item_size(last_mp_wr_len), + item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM}, + {"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port), + item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM}, + {"last_sdio_mp_index", item_size(last_sdio_mp_index), + item_addr(last_sdio_mp_index), 1}, {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), item_addr(num_cmd_host_to_card_failure), 1}, {"num_cmd_sleep_cfm_fail", @@ -233,6 +243,16 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, memcpy(info->last_event, adapter->dbg.last_event, sizeof(adapter->dbg.last_event)); info->last_event_index = adapter->dbg.last_event_index; + memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap, + sizeof(adapter->dbg.last_mp_wr_bitmap)); + memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports, + sizeof(adapter->dbg.last_mp_wr_ports)); + memcpy(info->last_mp_curr_wr_port, + adapter->dbg.last_mp_curr_wr_port, + sizeof(adapter->dbg.last_mp_curr_wr_port)); + memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len, + sizeof(adapter->dbg.last_mp_wr_len)); + info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index; info->data_sent = adapter->data_sent; info->cmd_sent = adapter->cmd_sent; info->cmd_resp_received = adapter->cmd_resp_received; -- cgit v1.2.3 From 0cb52aac4d19510d13410ee4232c0248fabe750e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 Feb 2016 05:16:19 -0800 Subject: mwifiex: do not set multiport flag for tx/rx single packet multiport address flag(0x1000) should not be set during sdio cmd53, if we have only one packet to read/write. Signed-off-by: Cathy Luo Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sdio.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 838b260f86fa..b2c839ae2c3c 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1355,6 +1355,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, card->mpa_rx.start_port; } + if (card->mpa_rx.pkt_cnt == 1) + mport = adapter->ioport + port; + if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, mport, 1)) goto error; @@ -1786,6 +1789,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, card->mpa_tx.start_port; } + if (card->mpa_tx.pkt_cnt == 1) + mport = adapter->ioport + port; + ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, card->mpa_tx.buf_len, mport); -- cgit v1.2.3 From f36f299068794ffc5026f25b6a1b3ed615ea832d Mon Sep 17 00:00:00 2001 From: Anthony Wong Date: Tue, 23 Feb 2016 23:09:22 +0800 Subject: rt2x00: add new rt2800usb device Buffalo WLI-UC-G450 Add USB ID 0411:01fd for Buffalo WLI-UC-G450 wireless adapter, RT chipset 3593 Signed-off-by: Anthony Wong Cc: stable@vger.kernel.org Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index bf9afbf46c1b..4b0bb6b4f6f1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -1026,6 +1026,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0411, 0x01a2) }, { USB_DEVICE(0x0411, 0x01ee) }, { USB_DEVICE(0x0411, 0x01a8) }, + { USB_DEVICE(0x0411, 0x01fd) }, /* Corega */ { USB_DEVICE(0x07aa, 0x002f) }, { USB_DEVICE(0x07aa, 0x003c) }, -- cgit v1.2.3 From 32962d5b43b748c43b9b0b32d02674c1ce6997a9 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Thu, 25 Feb 2016 00:49:23 +0530 Subject: mwifiex: Fixed incorrect indentation issue This patch fixes the incorrect indentation of the case label. Signed-off-by: Ujjal Roy Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index f2dce81ba36e..29b7f6eed240 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -676,7 +676,7 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) } break; - case MWIFIEX_BSS_ROLE_STA: + case MWIFIEX_BSS_ROLE_STA: if (priv->media_connected) { mwifiex_dbg(adapter, ERROR, "cannot change wiphy params when connected"); -- cgit v1.2.3 From 3a968d766a63267b3d6b7a66b9d7023b7d93eaae Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Thu, 25 Feb 2016 00:49:43 +0530 Subject: mwifiex: Removed extra spaces before commas This patch fixes spaces before commas issue in coding style. Signed-off-by: Ujjal Roy Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 2 +- drivers/net/wireless/marvell/mwifiex/uap_cmd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index efb19e2e1169..de364381fe7b 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1401,7 +1401,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -1; } - if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE)) + if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE)) return -1; buf_pa = MWIFIEX_SKB_DMA_ADDR(skb); diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index e791166d90c4..16d95b22fe5c 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -192,7 +192,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, } priv->ap_11n_enabled = 1; } else { - memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap)); + memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap)); bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP); bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU; } -- cgit v1.2.3 From 354a1947a02528b19ee326e230cb44399cd31865 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Thu, 25 Feb 2016 00:49:56 +0530 Subject: mwifiex: Added missing spaces around brackets This patch fixes the missing spaces issue in coding style. Signed-off-by: Ujjal Roy Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index e43aff932360..05108618430d 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -244,9 +244,9 @@ setup_for_next: if (card->rx_cmd_ep == context->ep) { mwifiex_usb_submit_rx_urb(context, size); } else { - if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){ + if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) { mwifiex_usb_submit_rx_urb(context, size); - }else{ + } else { context->skb = NULL; } } -- cgit v1.2.3 From 2b02a36d12192f2a86388913143cd1e399eb971c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 25 Feb 2016 23:24:27 +0000 Subject: mt7601u: do not free dma_buf when ivp allocation fails If the allocation of ivp fails the error handling attempts to free an uninitialized dma_buf; this data structure just contains garbage on the stack, so the freeing will cause issues when the urb, buf and dma fields are free'd. Fix this by not free'ing the dma_buf if the ivp allocation fails. Signed-off-by: Colin Ian King Reviewed-by: Julian Calaby Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/mcu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index fbb1986eda3c..91c4b3427965 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -362,7 +362,9 @@ mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw) int i, ret; ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); - if (!ivb || mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) { + if (!ivb) + return -ENOMEM; + if (mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) { ret = -ENOMEM; goto error; } -- cgit v1.2.3 From 73fb270592164b1917442f8bff4c791d095ee2ef Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 25 Feb 2016 11:03:01 -0600 Subject: rtlwifi: Fix size of wireless mode variable Smatch reports the following warning: CHECK drivers/net/wireless/realtek/rtlwifi/rc.c drivers/net/wireless/realtek/rtlwifi/rc.c:144 _rtl_rc_rate_set_series() warn: impossible condition '(wireless_mode == 256) => (0-255 == 256)' This warning arises because commit acc6907b87a9 ("rtlwifi: Fix warning from ieee80211_get_tx_rates() when using 5G") now checks the wireless mode for WIRELESS_MODE_AC_ONLY (BIT(8)) in _rtl_rc_rate_set_series(). As a result, all quantities used to store the wireless mode must be u16. This patch also reorders struct rtl_sta_info to save a little space. Fixes: d76d65fd2695 ("rtlwifi: fix broken VHT support") Reported-by: Dan Williams Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rc.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/wifi.h | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c index 28f7010e7108..1aca77719521 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rc.c @@ -41,7 +41,7 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_sta_info *sta_entry = NULL; - u8 wireless_mode = 0; + u16 wireless_mode = 0; /* *this rate is no use for true rate, firmware @@ -99,7 +99,7 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, { struct rtl_mac *mac = rtl_mac(rtlpriv); struct rtl_sta_info *sta_entry = NULL; - u8 wireless_mode = 0; + u16 wireless_mode = 0; u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0; if (sta) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 5da9bd0e5002..fe900badd468 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -3837,7 +3837,7 @@ void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u8 wireless_mode = mac->mode; + u16 wireless_mode = mac->mode; u8 sifs_timer, r2t_sifs; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index b07b364b93ab..554d81420f19 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1318,14 +1318,13 @@ struct rtl_tid_data { struct rtl_sta_info { struct list_head list; - u8 ratr_index; - u8 wireless_mode; - u8 mimo_ps; - u8 mac_addr[ETH_ALEN]; struct rtl_tid_data tids[MAX_TID_COUNT]; - /* just used for ap adhoc or mesh*/ struct rssi_sta rssi_stat; + u16 wireless_mode; + u8 ratr_index; + u8 mimo_ps; + u8 mac_addr[ETH_ALEN]; } __packed; struct rtl_priv; -- cgit v1.2.3 From 836856e3bd61d0644e5178a2c1b51d90459e2788 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 2 Mar 2016 16:59:02 +0100 Subject: wireless: cw1200: use __maybe_unused to hide pm functions_ The cw1200 uses #ifdef to check for CONFIG_PM, but then uses SIMPLE_DEV_PM_OPS, which leaves the references out when CONFIG_PM_SLEEP is not defined, so we get a warning with PM=y && PM_SLEEP=n: drivers/net/wireless/st/cw1200/cw1200_spi.c:450:12: error: 'cw1200_spi_suspend' defined but not used [-Werror=unused-function] This removes the incorrect #ifdef and instead uses a __maybe_unused annotation to let the compiler know it can silently drop the function definition. For the DEV_PM_OPS definition, we can use an IS_ENABLED() check to avoid defining the structure when CONFIG_PM is not set without the #ifdef. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/cw1200_spi.c | 9 ++------- drivers/net/wireless/st/cw1200/pm.h | 9 +++++++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index a740083634d8..63f95e9c2992 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -446,8 +446,7 @@ static int cw1200_spi_disconnect(struct spi_device *func) return 0; } -#ifdef CONFIG_PM -static int cw1200_spi_suspend(struct device *dev) +static int __maybe_unused cw1200_spi_suspend(struct device *dev) { struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); @@ -460,16 +459,12 @@ static int cw1200_spi_suspend(struct device *dev) static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL); -#endif - static struct spi_driver spi_driver = { .probe = cw1200_spi_probe, .remove = cw1200_spi_disconnect, .driver = { .name = "cw1200_wlan_spi", -#ifdef CONFIG_PM - .pm = &cw1200_pm_ops, -#endif + .pm = IS_ENABLED(CONFIG_PM) ? &cw1200_pm_ops : NULL, }, }; diff --git a/drivers/net/wireless/st/cw1200/pm.h b/drivers/net/wireless/st/cw1200/pm.h index 3ed90ff22bb8..534548470ebc 100644 --- a/drivers/net/wireless/st/cw1200/pm.h +++ b/drivers/net/wireless/st/cw1200/pm.h @@ -31,13 +31,18 @@ int cw1200_pm_init(struct cw1200_pm_state *pm, void cw1200_pm_deinit(struct cw1200_pm_state *pm); int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); -int cw1200_wow_resume(struct ieee80211_hw *hw); int cw1200_can_suspend(struct cw1200_common *priv); +int cw1200_wow_resume(struct ieee80211_hw *hw); void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, unsigned long tmo); #else static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, - unsigned long tmo) { + unsigned long tmo) +{ +} +static inline int cw1200_can_suspend(struct cw1200_common *priv) +{ + return 0; } #endif #endif -- cgit v1.2.3 From 00f481bd895a826058d301b3093e86e819497b51 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Wed, 24 Feb 2016 12:19:22 +0200 Subject: iwlwifi: mvm: add ctdp operations to debugfs Add debugfs entries to get the ctdp budget average and to stop ctdp. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 42 +++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 78 +++++++++++++----------- 2 files changed, 86 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 56e6b0b8b9cc..a43b3921c4c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -73,6 +73,44 @@ #include "debugfs.h" #include "iwl-fw-error-dump.h" +static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + char buf[16]; + int pos, budget; + + if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + return -EIO; + + mutex_lock(&mvm->mutex); + budget = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_REPORT, 0); + mutex_unlock(&mvm->mutex); + + if (budget < 0) + return budget; + + pos = scnprintf(buf, sizeof(buf), "%d\n", budget); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + int ret; + + if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + return -EIO; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_STOP, 0); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { @@ -1493,6 +1531,8 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ +MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget); +MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8); MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8); @@ -1542,6 +1582,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 0a02e9835d6b..ce0c6fd183bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -510,6 +510,50 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = { .support_tx_backoff = true, }; +int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget) +{ + struct iwl_mvm_ctdp_cmd cmd = { + .operation = cpu_to_le32(op), + .budget = cpu_to_le32(budget), + .window_size = 0, + }; + int ret; + u32 status; + + lockdep_assert_held(&mvm->mutex); + + ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP, + CTDP_CONFIG_CMD), + sizeof(cmd), &cmd, &status); + + if (ret) { + IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret); + return ret; + } + + switch (op) { + case CTDP_CMD_OPERATION_START: +#ifdef CONFIG_THERMAL + mvm->cooling_dev.cur_state = budget; +#endif /* CONFIG_THERMAL */ + break; + case CTDP_CMD_OPERATION_REPORT: + IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status); + /* when the function is called with CTDP_CMD_OPERATION_REPORT + * option the function should return the average budget value + * that is received from the FW. + * The budget can't be less or equal to 0, so it's possible + * to distinguish between error values and budgets. + */ + return status; + case CTDP_CMD_OPERATION_STOP: + IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n"); + break; + } + + return 0; +} + #ifdef CONFIG_THERMAL static int compare_temps(const void *a, const void *b) { @@ -738,40 +782,6 @@ static const u32 iwl_mvm_cdev_budgets[] = { 150, /* cooling state 19 */ }; -int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget) -{ - struct iwl_mvm_ctdp_cmd cmd = { - .operation = cpu_to_le32(op), - .budget = cpu_to_le32(budget), - .window_size = 0, - }; - int ret; - u32 status; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP, - CTDP_CONFIG_CMD), - sizeof(cmd), &cmd, &status); - - if (ret) { - IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret); - return ret; - } - - /* can happen if the registration failed */ - if (!mvm->cooling_dev.cdev) - return -EINVAL; - - if (op == CTDP_CMD_OPERATION_START) - mvm->cooling_dev.cur_state = budget; - - else if (op == CTDP_CMD_OPERATION_REPORT) - IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status); - - return 0; -} - static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { -- cgit v1.2.3 From 62d23403d4a201db117975d46c1889c79987069e Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 6 Mar 2016 09:51:29 +0200 Subject: iwlwifi: mvm: turn off AMSDU bit in QoS control for de-aggregated AMSDUs Our hardware de-aggregates AMSDUs but copies the mac header as it to the de-aggregated MPDUs. We need to turn off the AMSDU bit in the QoS control ourselves. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index cd6ca374e5d3..9a54f2d2a66b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -519,6 +519,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rcu_read_unlock(); return; } + + /* + * Our hardware de-aggregates AMSDUs but copies the mac header + * as it to the de-aggregated MPDUs. We need to turn off the + * AMSDU bit in the QoS control ourselves. + */ + if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && + !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + + *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + } } /* -- cgit v1.2.3 From 5151ad953c68f2af0b50cf8d074a902ccf001ae0 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Wed, 9 Mar 2016 14:46:28 +0200 Subject: iwlwifi: mvm: ROC: cleanup time event info on FW failure Currently when the FW sends start/stop aux roc time event notification with an error status, the driver returns an error value, but does not remove the time event, and does not notify the stack above that the time event is over. This causes problems that the stack above assumes we are still in the middle of a time event, and therefore can block different events, such as scanning. On FW failure notification, cleanup the time event parameters and notify the stack above that the time event is over. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 924dd6a41626..2c12789e7550 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -371,20 +371,13 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, iwl_mvm_te_check_trigger(mvm, notif, te_data); - if (!le32_to_cpu(notif->status)) { - IWL_DEBUG_TE(mvm, - "ERROR: Aux ROC Time Event %s notification failure\n", - (le32_to_cpu(notif->action) & - TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end"); - return -EINVAL; - } - IWL_DEBUG_TE(mvm, - "Aux ROC time event notification - UID = 0x%x action %d\n", + "Aux ROC time event notification - UID = 0x%x action %d (error = %d)\n", le32_to_cpu(notif->unique_id), - le32_to_cpu(notif->action)); + le32_to_cpu(notif->action), le32_to_cpu(notif->status)); - if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) { + if (!le32_to_cpu(notif->status) || + le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) { /* End TE, notify mac80211 */ ieee80211_remain_on_channel_expired(mvm->hw); iwl_mvm_roc_finished(mvm); /* flush aux queue */ -- cgit v1.2.3 From c9cb14a64c32f890d5a0649cb7d81dbfece33056 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Thu, 3 Mar 2016 15:35:34 +0200 Subject: iwlwifi: mvm: add support for async rx handler without hold the mutex When running async rx handler the framework holds the mvm->mutex before starting the async handler, that might cause a deadlock in case the handler calls to ops that lock the mutex as well. Add support for running async rx handler without hold the mutex before activating the handler. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 114 +++++++++++++++++---------- 1 file changed, 73 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4322e8ed1159..5e8ab796d5bc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -205,79 +205,107 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } +/** + * enum iwl_rx_handler_context context for Rx handler + * @RX_HANDLER_SYNC : this means that it will be called in the Rx path + * which can't acquire mvm->mutex. + * @RX_HANDLER_ASYNC_LOCKED : If the handler needs to hold mvm->mutex + * (and only in this case!), it should be set as ASYNC. In that case, + * it will be called from a worker with mvm->mutex held. + * @RX_HANDLER_ASYNC_UNLOCKED : in case the handler needs to lock the + * mutex itself, it will be called from a worker without mvm->mutex held. + */ +enum iwl_rx_handler_context { + RX_HANDLER_SYNC, + RX_HANDLER_ASYNC_LOCKED, + RX_HANDLER_ASYNC_UNLOCKED, +}; + +/** + * struct iwl_rx_handlers handler for FW notification + * @cmd_id: command id + * @context: see &iwl_rx_handler_context + * @fn: the function is called when notification is received + */ struct iwl_rx_handlers { u16 cmd_id; - bool async; + enum iwl_rx_handler_context context; void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; -#define RX_HANDLER(_cmd_id, _fn, _async) \ - { .cmd_id = _cmd_id , .fn = _fn , .async = _async } -#define RX_HANDLER_GRP(_grp, _cmd, _fn, _async) \ - { .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .async = _async } +#define RX_HANDLER(_cmd_id, _fn, _context) \ + { .cmd_id = _cmd_id, .fn = _fn, .context = _context } +#define RX_HANDLER_GRP(_grp, _cmd, _fn, _context) \ + { .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .context = _context } /* * Handlers for fw notifications * Convention: RX_HANDLER(CMD_NAME, iwl_mvm_rx_CMD_NAME * This list should be in order of frequency for performance purposes. * - * The handler can be SYNC - this means that it will be called in the Rx path - * which can't acquire mvm->mutex. If the handler needs to hold mvm->mutex (and - * only in this case!), it should be set as ASYNC. In that case, it will be - * called from a worker with mvm->mutex held. + * The handler can be one from three contexts, see &iwl_rx_handler_context */ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { - RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), - RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), - - RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), - RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, true), - RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), + RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, RX_HANDLER_SYNC), + RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, RX_HANDLER_SYNC), + + RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, + RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, + RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, + RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, - iwl_mvm_rx_ant_coupling_notif, true), + iwl_mvm_rx_ant_coupling_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(BA_WINDOW_STATUS_NOTIFICATION_ID, - iwl_mvm_window_status_notif, false), + iwl_mvm_window_status_notif, RX_HANDLER_SYNC), - RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), - RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true), + RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, + RX_HANDLER_SYNC), + RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, + RX_HANDLER_ASYNC_LOCKED), - RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), + RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, RX_HANDLER_SYNC), RX_HANDLER(SCAN_ITERATION_COMPLETE, - iwl_mvm_rx_lmac_scan_iter_complete_notif, false), + iwl_mvm_rx_lmac_scan_iter_complete_notif, RX_HANDLER_SYNC), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, - iwl_mvm_rx_lmac_scan_complete_notif, true), + iwl_mvm_rx_lmac_scan_complete_notif, + RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_match_found, - false), + RX_HANDLER_SYNC), RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif, - true), + RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(SCAN_ITERATION_COMPLETE_UMAC, - iwl_mvm_rx_umac_scan_iter_complete_notif, false), + iwl_mvm_rx_umac_scan_iter_complete_notif, RX_HANDLER_SYNC), - RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), + RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, + RX_HANDLER_SYNC), RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif, - false), + RX_HANDLER_SYNC), - RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), + RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, RX_HANDLER_SYNC), RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, - iwl_mvm_power_uapsd_misbehaving_ap_notif, false), - RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true), + iwl_mvm_power_uapsd_misbehaving_ap_notif, RX_HANDLER_SYNC), + RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, + RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_GRP(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE, - iwl_mvm_temp_notif, true), + iwl_mvm_temp_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_GRP(PHY_OPS_GROUP, CT_KILL_NOTIFICATION, - iwl_mvm_ct_kill_notif, false), + iwl_mvm_ct_kill_notif, RX_HANDLER_SYNC), RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, - true), - RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), - RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true), + RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, + RX_HANDLER_SYNC), + RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, + RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, - iwl_mvm_rx_stored_beacon_notif, false), + iwl_mvm_rx_stored_beacon_notif, RX_HANDLER_SYNC), RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF, - iwl_mvm_mu_mimo_grp_notif, false), - + iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -743,6 +771,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) struct iwl_async_handler_entry { struct list_head list; struct iwl_rx_cmd_buffer rxb; + enum iwl_rx_handler_context context; void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; @@ -769,7 +798,6 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk) INIT_LIST_HEAD(&local_list); /* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */ - mutex_lock(&mvm->mutex); /* * Sync with Rx path with a lock. Remove all the entries from this list, @@ -780,12 +808,15 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk) spin_unlock_bh(&mvm->async_handlers_lock); list_for_each_entry_safe(entry, tmp, &local_list, list) { + if (entry->context == RX_HANDLER_ASYNC_LOCKED) + mutex_lock(&mvm->mutex); entry->fn(mvm, &entry->rxb); iwl_free_rxb(&entry->rxb); list_del(&entry->list); + if (entry->context == RX_HANDLER_ASYNC_LOCKED) + mutex_unlock(&mvm->mutex); kfree(entry); } - mutex_unlock(&mvm->mutex); } static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, @@ -842,7 +873,7 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm, if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) continue; - if (!rx_h->async) { + if (rx_h->context == RX_HANDLER_SYNC) { rx_h->fn(mvm, rxb); return; } @@ -856,6 +887,7 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm, entry->rxb._offset = rxb->_offset; entry->rxb._rx_page_order = rxb->_rx_page_order; entry->fn = rx_h->fn; + entry->context = rx_h->context; spin_lock(&mvm->async_handlers_lock); list_add_tail(&entry->list, &mvm->async_handlers_list); spin_unlock(&mvm->async_handlers_lock); -- cgit v1.2.3 From 7b5424361ec9270f40c3e23cb747cc8b9ee66235 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 1 Feb 2016 13:46:06 +0200 Subject: iwlwifi: pcie: fine tune number of rxbs We kick the allocator when we have 2 RBDs that don't have attached RBs, and the allocator allocates 8 RBs meaning that it needs another 6 RBDs to attach the RBs to. The design is that allocator should always have enough RBDs to fulfill requests, so we give in advance 6 RBDs to the allocator so that when it is kicked, it gets additional 2 RBDs and has enough RBDs. These RBDs were taken from the Rx queue itself, meaning that each Rx queue didn't have the maximal number of RBDs, but MAX - 6. Change initial number of RBDs in the system to include both queue size and allocator reserves. Note the multi-queue is always 511 instead of 512 to avoid a full queue since we cannot detect this state easily enough in the 9000 arch. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 9 ++++++--- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 11 ++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 8af818b10e71..582008a66069 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -511,9 +511,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) */ #define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) -#define MQ_RX_TABLE_SIZE 512 -#define MQ_RX_TABLE_MASK (MQ_RX_TABLE_SIZE - 1) -#define MQ_RX_POOL_SIZE MQ_RX_TABLE_MASK +#define MQ_RX_TABLE_SIZE 512 +#define MQ_RX_TABLE_MASK (MQ_RX_TABLE_SIZE - 1) +#define MQ_RX_NUM_RBDS (MQ_RX_TABLE_SIZE - 1) +#define RX_POOL_SIZE (MQ_RX_NUM_RBDS + \ + IWL_MAX_RX_HW_QUEUES * \ + (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC)) #define RX_QUEUE_SIZE 256 #define RX_QUEUE_MASK 255 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 6677f3122226..dadafbdef9d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -347,7 +347,7 @@ struct iwl_tso_hdr_page { */ struct iwl_trans_pcie { struct iwl_rxq *rxq; - struct iwl_rx_mem_buffer rx_pool[MQ_RX_POOL_SIZE]; + struct iwl_rx_mem_buffer rx_pool[RX_POOL_SIZE]; struct iwl_rx_mem_buffer *global_table[MQ_RX_TABLE_SIZE]; struct iwl_rb_allocator rba; struct iwl_trans *trans; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 509f79003241..98524a006f7a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -434,7 +434,7 @@ static void iwl_pcie_free_rbs_pool(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i; - for (i = 0; i < MQ_RX_POOL_SIZE; i++) { + for (i = 0; i < RX_POOL_SIZE; i++) { if (!trans_pcie->rx_pool[i].page) continue; dma_unmap_page(trans->dev, trans_pcie->rx_pool[i].page_dma, @@ -835,7 +835,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *def_rxq; struct iwl_rb_allocator *rba = &trans_pcie->rba; - int i, err, num_rbds, allocator_pool_size; + int i, err, queue_size, allocator_pool_size, num_alloc; if (!trans_pcie->rxq) { err = iwl_pcie_rx_alloc(trans); @@ -887,11 +887,12 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) } /* move the pool to the default queue and allocator ownerships */ - num_rbds = trans->cfg->mq_rx_supported ? - MQ_RX_POOL_SIZE : RX_QUEUE_SIZE; + queue_size = trans->cfg->mq_rx_supported ? + MQ_RX_NUM_RBDS : RX_QUEUE_SIZE; allocator_pool_size = trans->num_rx_queues * (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC); - for (i = 0; i < num_rbds; i++) { + num_alloc = queue_size + allocator_pool_size; + for (i = 0; i < num_alloc; i++) { struct iwl_rx_mem_buffer *rxb = &trans_pcie->rx_pool[i]; if (i < allocator_pool_size) -- cgit v1.2.3 From 17c867bfe89bd2e089752ac938468900387acbe2 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 7 Mar 2016 14:18:29 +0200 Subject: iwlwifi: add support for getting HW address from CSR From 9000 family on, we need to get HW address from host CSR registers. OEM can override it by fusing the override registers - read those first, and if those are 0 - read the OTP registers instead. In addition - bail out if no valid mac address is present. Make it shared for all NICs. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 + drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 10 +++ drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 75 ++++++++++++++++------ 4 files changed, 68 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 8e32a57dda0f..318b1dc171f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -140,7 +140,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { .thermal_params = &iwl9000_tt_params, \ .apmg_not_supported = true, \ .mq_rx_supported = true, \ - .vht_mu_mimo_supported = true + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = true const struct iwl_cfg iwl9260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9260", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 4f2b57e8bbc7..3e4d346be350 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff { * @host_interrupt_operation_mode: device needs host interrupt operation * mode set * @nvm_hw_section_num: the ID of the HW NVM section + * @mac_addr_from_csr: read HW address from CSR registers * @features: hw features, any combination of feature_whitelist * @pwr_tx_backoffs: translation table between power limits and backoffs * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response @@ -345,6 +346,7 @@ struct iwl_cfg { const bool host_interrupt_operation_mode; bool high_temp; u8 nvm_hw_section_num; + bool mac_addr_from_csr; bool lp_xtal_workaround; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; bool no_power_up_nic_in_init; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index a79c4f61a851..b978f6cae55c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -598,4 +598,14 @@ enum msix_hw_int_causes { #define MSIX_AUTO_CLEAR_CAUSE 0 #define MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) +/***************************************************************************** + * HW address related registers * + *****************************************************************************/ + +#define CSR_ADDR_BASE (0x380) +#define CSR_MAC_ADDR0_OTP (CSR_ADDR_BASE) +#define CSR_MAC_ADDR1_OTP (CSR_ADDR_BASE + 4) +#define CSR_MAC_ADDR0_STRAP (CSR_ADDR_BASE + 8) +#define CSR_MAC_ADDR1_STRAP (CSR_ADDR_BASE + 0xC) + #endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 5e6b90da3179..93a689583dff 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -71,6 +71,8 @@ #include "iwl-modparams.h" #include "iwl-nvm-parse.h" #include "iwl-prph.h" +#include "iwl-io.h" +#include "iwl-csr.h" /* NVM offsets (in words) definitions */ enum wkp_nvm_offsets { @@ -524,6 +526,36 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); } +static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) +{ + const u8 *hw_addr; + + hw_addr = (const u8 *)&mac_addr0; + dest[0] = hw_addr[3]; + dest[1] = hw_addr[2]; + dest[2] = hw_addr[1]; + dest[3] = hw_addr[0]; + + hw_addr = (const u8 *)&mac_addr1; + dest[4] = hw_addr[1]; + dest[5] = hw_addr[0]; +} + +static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, + struct iwl_nvm_data *data) +{ + __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP)); + __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); + + /* If OEM did not fuse address - get it from OTP */ + if (!mac_addr0 && !mac_addr1) { + mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP)); + mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP)); + } + + iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); +} + static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, @@ -564,21 +596,8 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, WFMP_MAC_ADDR_0)); __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans, WFMP_MAC_ADDR_1)); - /* read the MAC address from HW resisters */ - hw_addr = (const u8 *)&mac_addr0; - data->hw_addr[0] = hw_addr[3]; - data->hw_addr[1] = hw_addr[2]; - data->hw_addr[2] = hw_addr[1]; - data->hw_addr[3] = hw_addr[0]; - - hw_addr = (const u8 *)&mac_addr1; - data->hw_addr[4] = hw_addr[1]; - data->hw_addr[5] = hw_addr[0]; - - if (!is_valid_ether_addr(data->hw_addr)) - IWL_ERR(trans, - "mac address (%pM) from hw section is not valid\n", - data->hw_addr); + + iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); return; } @@ -586,12 +605,14 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, IWL_ERR(trans, "mac address is not found\n"); } -static void iwl_set_hw_address(struct iwl_trans *trans, - const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, const __le16 *nvm_hw, - const __le16 *mac_override) +static int iwl_set_hw_address(struct iwl_trans *trans, + const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, const __le16 *nvm_hw, + const __le16 *mac_override) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (cfg->mac_addr_from_csr) { + iwl_set_hw_address_from_csr(trans, data); + } else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR); /* The byte order is little endian 16 bit, meaning 214365 */ @@ -605,6 +626,13 @@ static void iwl_set_hw_address(struct iwl_trans *trans, iwl_set_hw_address_family_8000(trans, cfg, data, mac_override, nvm_hw); } + + if (!is_valid_ether_addr(data->hw_addr)) { + IWL_ERR(trans, "no valid mac address was found\n"); + return -EINVAL; + } + + return 0; } struct iwl_nvm_data * @@ -680,7 +708,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, ch_section = regulatory; } - iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override); + /* If no valid mac address was found - bail out */ + if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) { + kfree(data); + return NULL; + } + iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains, lar_fw_supported && lar_enabled); data->calib_version = 255; -- cgit v1.2.3 From 532beba378d26d5bd9bbb1b485e969c13bf72009 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 7 Mar 2016 22:23:52 +0200 Subject: iwlwifi: mvm: don't let NDPs mess the packet tracking We need to track the next packet that we will reclaim in order to know when the Tx queues are empty. This is useful when we open or tear down an A-MPDU session which requires to switch queue. The next packet being reclaimed is identified by its WiFi sequence number and this is relevant only when we use QoS. QoS NDPs do have a TID but have a meaningless sequence number. The spec mandates the receiver to ignore the sequence number in this case, allowing the transmitter to put any sequence number. Our implementation leaves it 0. When we reclaim a QoS NDP, we can't update the next_relcaim counter since the sequence number of the QoS NDP itself is invalid. We used to update the next_reclaim based on the sequence number of the QoS NDP which reset it to 1 (0 + 1) and because of this, we never knew when the queue got empty. This had to sad consequence to stuck the A-MPDU state machine in a transient state. To fix this, don't update next_reclaim when we reclaim a QoS NDP. Alesya saw this bug when testing u-APSD. Because the A-MPDU state machine was stuck in EMPTYING_DELBA, we updated mac80211 that we still have frames for that station when it got back to sleep. mac80211 then wrongly set the TIM bit in the beacon and requested to release non-existent frames from the A-MPDU queue. This led to a situation where the client was trying to poll frames but we had no frames to send. Reported-by: Alesya Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 271e8da6d140..75870e68a7c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -963,6 +964,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, struct sk_buff_head skbs; u8 skb_freed = 0; u16 next_reclaimed, seq_ctl; + bool is_ndp = false; __skb_queue_head_init(&skbs); @@ -1016,6 +1018,20 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, seq_ctl = le16_to_cpu(hdr->seq_ctrl); } + if (unlikely(!seq_ctl)) { + struct ieee80211_hdr *hdr = (void *)skb->data; + + /* + * If it is an NDP, we can't update next_reclaim since + * its sequence control is 0. Note that for that same + * reason, NDPs are never sent to A-MPDU'able queues + * so that we can never have more than one freed frame + * for a single Tx resonse (see WARN_ON below). + */ + if (ieee80211_is_qos_nullfunc(hdr->frame_control)) + is_ndp = true; + } + /* * TODO: this is not accurate if we are freeing more than one * packet. @@ -1079,9 +1095,16 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, bool send_eosp_ndp = false; spin_lock_bh(&mvmsta->lock); - tid_data->next_reclaimed = next_reclaimed; - IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", - next_reclaimed); + if (!is_ndp) { + tid_data->next_reclaimed = next_reclaimed; + IWL_DEBUG_TX_REPLY(mvm, + "Next reclaimed packet:%d\n", + next_reclaimed); + } else { + IWL_DEBUG_TX_REPLY(mvm, + "NDP - don't update next_reclaimed\n"); + } + iwl_mvm_check_ratid_empty(mvm, sta, tid); if (mvmsta->sleep_tx_count) { -- cgit v1.2.3 From 416cb2467bba25a6729b95e1ada0254a9477a360 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 8 Mar 2016 13:53:05 +0200 Subject: iwlwifi: mvm: remove RRM advertisement mac80211 advertises this feature for all its drivers. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3590835a308f..39b9c383c272 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -610,8 +610,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES; - wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_RRM); - mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From b358993b3f582f43a6098028b5b08d084dff4d24 Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Sun, 14 Feb 2016 14:03:10 +0200 Subject: iwlwifi: mvm: return the cooling state index instead of the budget iwl_mvm_tcool_get_cur_state is the function that returns the cooling state index to the sysfs handler. This function returns mvm->cooling_dev.cur_state but that variable was set to the budget and not the cooling state index. Fix that. Add a missing blank line while at it. Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 56 ++++++++++++++-------------- 2 files changed, 31 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b869db9afc52..9abbc93e3c06 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -543,8 +543,8 @@ struct iwl_mvm_thermal_device { }; /* - * iwl_mvm_cooling_device - * @cur_state: current state in milliwatts + * struct iwl_mvm_cooling_device + * @cur_state: current state * @cdev: struct thermal cooling device */ struct iwl_mvm_cooling_device { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index ce0c6fd183bb..f1f28255a3a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -510,11 +510,35 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = { .support_tx_backoff = true, }; -int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget) +/* budget in mWatt */ +static const u32 iwl_mvm_cdev_budgets[] = { + 2000, /* cooling state 0 */ + 1800, /* cooling state 1 */ + 1600, /* cooling state 2 */ + 1400, /* cooling state 3 */ + 1200, /* cooling state 4 */ + 1000, /* cooling state 5 */ + 900, /* cooling state 6 */ + 800, /* cooling state 7 */ + 700, /* cooling state 8 */ + 650, /* cooling state 9 */ + 600, /* cooling state 10 */ + 550, /* cooling state 11 */ + 500, /* cooling state 12 */ + 450, /* cooling state 13 */ + 400, /* cooling state 14 */ + 350, /* cooling state 15 */ + 300, /* cooling state 16 */ + 250, /* cooling state 17 */ + 200, /* cooling state 18 */ + 150, /* cooling state 19 */ +}; + +int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state) { struct iwl_mvm_ctdp_cmd cmd = { .operation = cpu_to_le32(op), - .budget = cpu_to_le32(budget), + .budget = cpu_to_le32(iwl_mvm_cdev_budgets[state]), .window_size = 0, }; int ret; @@ -534,7 +558,7 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget) switch (op) { case CTDP_CMD_OPERATION_START: #ifdef CONFIG_THERMAL - mvm->cooling_dev.cur_state = budget; + mvm->cooling_dev.cur_state = state; #endif /* CONFIG_THERMAL */ break; case CTDP_CMD_OPERATION_REPORT: @@ -759,29 +783,6 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) mvm->tz_device.temp_trips[i] = S16_MIN; } -static const u32 iwl_mvm_cdev_budgets[] = { - 2000, /* cooling state 0 */ - 1800, /* cooling state 1 */ - 1600, /* cooling state 2 */ - 1400, /* cooling state 3 */ - 1200, /* cooling state 4 */ - 1000, /* cooling state 5 */ - 900, /* cooling state 6 */ - 800, /* cooling state 7 */ - 700, /* cooling state 8 */ - 650, /* cooling state 9 */ - 600, /* cooling state 10 */ - 550, /* cooling state 11 */ - 500, /* cooling state 12 */ - 450, /* cooling state 13 */ - 400, /* cooling state 14 */ - 350, /* cooling state 15 */ - 300, /* cooling state 16 */ - 250, /* cooling state 17 */ - 200, /* cooling state 18 */ - 150, /* cooling state 19 */ -}; - static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { @@ -799,6 +800,7 @@ static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev, return -EBUSY; *state = mvm->cooling_dev.cur_state; + return 0; } @@ -822,7 +824,7 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, } ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, - iwl_mvm_cdev_budgets[new_state]); + new_state); unlock: mutex_unlock(&mvm->mutex); -- cgit v1.2.3 From e0e168dc8c4e41bab6ab94a838cfee50dd2b5f25 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 29 Feb 2016 15:34:25 +0200 Subject: iwlwifi: pcie: avoid restocks inside rx loop if not emergency When trying to reach high Rx throughput of more than 500Mbps on a device with a relatively weak CPU (Atom x5-Z8500), CPU utilization may become a bottleneck. Analysis showed that we are looping in iwl_pcie_rx_handle for very long periods which led to starvation of other threads (iwl_pcie_rx_handle runs with _bh disabled). We were handling Rx and allocating new buffers and the new buffers were ready quickly enough to be available before we had finished handling all the buffers available in the hardware. As a consequence, we called iwl_pcie_rxq_restock to refill the hardware with the new buffers, and start again handling new buffers without exiting the function. Since we read the hardware pointer again when we goto restart, new buffers were handled immediately instead of exiting the function. This patch avoids refilling RBs inside rx handling loop, unless an emergency situation is reached. It also doesn't read the hardware pointer again unless we are in an emergency (unlikely) case. This significantly reduce the maximal time we spend in iwl_pcie_rx_handle with _bh disabled. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 59 ++++++++++++++++------------ 1 file changed, 33 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 98524a006f7a..4be3c35afd19 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -231,6 +231,9 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) } } +/* + * iwl_pcie_rxq_mq_restock - restock implementation for multi-queue rx + */ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) { @@ -277,17 +280,10 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, } /* - * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool - * - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can, pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. + * iwl_pcie_rxq_sq_restock - restock implementation for single queue rx */ -static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) +static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans, + struct iwl_rxq *rxq) { struct iwl_rx_mem_buffer *rxb; @@ -331,6 +327,26 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) } } +/* + * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can, pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +static +void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) +{ + if (trans->cfg->mq_rx_supported) + iwl_pcie_rxq_mq_restock(trans, rxq); + else + iwl_pcie_rxq_sq_restock(trans, rxq); +} + /* * iwl_pcie_rx_alloc_page - allocates and returns a page. * @@ -907,7 +923,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) if (trans->cfg->mq_rx_supported) { iwl_pcie_rx_mq_hw_init(trans); } else { - iwl_pcie_rxq_restock(trans, def_rxq); + iwl_pcie_rxq_sq_restock(trans, def_rxq); iwl_pcie_rx_hw_init(trans, def_rxq); } @@ -1222,24 +1238,13 @@ restart: count = 0; if (rxq->used_count < rxq->queue_size / 3) emergency = false; + + rxq->read = i; spin_unlock(&rxq->lock); iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); - spin_lock(&rxq->lock); - } - } - /* handle restock for three cases, can be all of them at once: - * - we just pulled buffers from the allocator - * - we have 8+ unstolen pages accumulated - * - we are in emergency and allocated buffers - */ - if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) { - rxq->read = i; - spin_unlock(&rxq->lock); - if (trans->cfg->mq_rx_supported) - iwl_pcie_rxq_mq_restock(trans, rxq); - else iwl_pcie_rxq_restock(trans, rxq); - goto restart; + goto restart; + } } } out: @@ -1264,6 +1269,8 @@ out: if (rxq->napi.poll) napi_gro_flush(&rxq->napi, false); + + iwl_pcie_rxq_restock(trans, rxq); } static struct iwl_trans_pcie *iwl_pcie_get_trans_pcie(struct msix_entry *entry) -- cgit v1.2.3 From 7d3ca7f4b1d5a43a1e0dbd112bb4c3bcf9a81fab Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 7 Mar 2016 10:16:38 +0200 Subject: iwlwifi: mvm: adapt the firmware assert log to new firmware Newer firmware versions put different data in the memory which is read by the driver upon firmware crash. Just change the variable names in the code and the name of the data in the log that we print withouth any functional change. On older firmware, there will be a mismatch between the names that are printed and the content itself, but that's harmless. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 +++---- .../wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 27 ++++++++++----------- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 28 +++++++++++----------- 3 files changed, 30 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index f62c2d727ddb..85628127947f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1652,10 +1652,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, table.data1, table.data2, table.line, - table.blink1, table.blink2, table.ilink1, - table.ilink2, table.bcon_time, table.gp1, - table.gp2, table.gp3, table.ucode_ver, - table.hw_ver, 0, table.brd_ver); + table.blink2, table.ilink1, table.ilink2, + table.bcon_time, table.gp1, table.gp2, + table.gp3, table.ucode_ver, table.hw_ver, + 0, table.brd_ver); IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); IWL_ERR(priv, "0x%08X | uPc\n", table.pc); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index 2a0703fcec56..f02e2c89abbb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -2,6 +2,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -121,13 +122,12 @@ TRACE_EVENT(iwlwifi_dev_tx, TRACE_EVENT(iwlwifi_dev_ucode_error, TP_PROTO(const struct device *dev, u32 desc, u32 tsf_low, - u32 data1, u32 data2, u32 line, u32 blink1, - u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time, - u32 gp1, u32 gp2, u32 gp3, u32 major, u32 minor, u32 hw_ver, - u32 brd_ver), + u32 data1, u32 data2, u32 line, u32 blink2, u32 ilink1, + u32 ilink2, u32 bcon_time, u32 gp1, u32 gp2, u32 rev_type, + u32 major, u32 minor, u32 hw_ver, u32 brd_ver), TP_ARGS(dev, desc, tsf_low, data1, data2, line, - blink1, blink2, ilink1, ilink2, bcon_time, gp1, gp2, - gp3, major, minor, hw_ver, brd_ver), + blink2, ilink1, ilink2, bcon_time, gp1, gp2, + rev_type, major, minor, hw_ver, brd_ver), TP_STRUCT__entry( DEV_ENTRY __field(u32, desc) @@ -135,14 +135,13 @@ TRACE_EVENT(iwlwifi_dev_ucode_error, __field(u32, data1) __field(u32, data2) __field(u32, line) - __field(u32, blink1) __field(u32, blink2) __field(u32, ilink1) __field(u32, ilink2) __field(u32, bcon_time) __field(u32, gp1) __field(u32, gp2) - __field(u32, gp3) + __field(u32, rev_type) __field(u32, major) __field(u32, minor) __field(u32, hw_ver) @@ -155,29 +154,27 @@ TRACE_EVENT(iwlwifi_dev_ucode_error, __entry->data1 = data1; __entry->data2 = data2; __entry->line = line; - __entry->blink1 = blink1; __entry->blink2 = blink2; __entry->ilink1 = ilink1; __entry->ilink2 = ilink2; __entry->bcon_time = bcon_time; __entry->gp1 = gp1; __entry->gp2 = gp2; - __entry->gp3 = gp3; + __entry->rev_type = rev_type; __entry->major = major; __entry->minor = minor; __entry->hw_ver = hw_ver; __entry->brd_ver = brd_ver; ), TP_printk("[%s] #%02d %010u data 0x%08X 0x%08X line %u, " - "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X " - "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X major 0x%08X " + "blink2 0x%05X ilink 0x%05X 0x%05X " + "bcon_tm %010u gp 0x%08X 0x%08X rev_type 0x%08X major 0x%08X " "minor 0x%08X hw 0x%08X brd 0x%08X", __get_str(dev), __entry->desc, __entry->tsf_low, - __entry->data1, - __entry->data2, __entry->line, __entry->blink1, + __entry->data1, __entry->data2, __entry->line, __entry->blink2, __entry->ilink1, __entry->ilink2, __entry->bcon_time, __entry->gp1, __entry->gp2, - __entry->gp3, __entry->major, __entry->minor, + __entry->rev_type, __entry->major, __entry->minor, __entry->hw_ver, __entry->brd_ver) ); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 59453c176580..53cdc5760f68 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -376,8 +376,8 @@ struct iwl_error_event_table_v1 { struct iwl_error_event_table { u32 valid; /* (nonzero) valid, (0) log is empty */ u32 error_id; /* type of error */ - u32 pc; /* program counter */ - u32 blink1; /* branch link */ + u32 trm_hw_status0; /* TRM HW status */ + u32 trm_hw_status1; /* TRM HW status */ u32 blink2; /* branch link */ u32 ilink1; /* interrupt link */ u32 ilink2; /* interrupt link */ @@ -389,7 +389,7 @@ struct iwl_error_event_table { u32 tsf_hi; /* network timestamp function timer */ u32 gp1; /* GP1 timer register */ u32 gp2; /* GP2 timer register */ - u32 gp3; /* GP3 timer register */ + u32 fw_rev_type; /* firmware revision type */ u32 major; /* uCode version major */ u32 minor; /* uCode version minor */ u32 hw_ver; /* HW Silicon version */ @@ -408,7 +408,7 @@ struct iwl_error_event_table { * time_flag */ u32 isr4; /* isr status register LMPM_NIC_ISR4: * wico interrupt */ - u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 last_cmd_id; /* last HCMD id handled by the firmware */ u32 wait_event; /* wait event() caller address */ u32 l2p_control; /* L2pControlField */ u32 l2p_duration; /* L2pDurationField */ @@ -419,7 +419,7 @@ struct iwl_error_event_table { u32 u_timestamp; /* indicate when the date and time of the * compilation */ u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_2 */; +} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; /* * UMAC error struct - relevant starting from family 8000 chip. @@ -529,9 +529,9 @@ static void iwl_mvm_dump_nic_error_log_old(struct iwl_mvm *mvm) trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, table.data1, table.data2, table.data3, - table.blink1, table.blink2, table.ilink1, - table.ilink2, table.bcon_time, table.gp1, - table.gp2, table.gp3, table.ucode_ver, 0, + table.blink2, table.ilink1, table.ilink2, + table.bcon_time, table.gp1, table.gp2, + table.gp3, table.ucode_ver, 0, table.hw_ver, table.brd_ver); IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); @@ -615,14 +615,14 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, table.data1, table.data2, table.data3, - table.blink1, table.blink2, table.ilink1, + table.blink2, table.ilink1, table.ilink2, table.bcon_time, table.gp1, - table.gp2, table.gp3, table.major, + table.gp2, table.fw_rev_type, table.major, table.minor, table.hw_ver, table.brd_ver); IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); - IWL_ERR(mvm, "0x%08X | uPc\n", table.pc); - IWL_ERR(mvm, "0x%08X | branchlink1\n", table.blink1); + IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); + IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2); IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1); IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2); @@ -634,7 +634,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi); IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1); IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(mvm, "0x%08X | time gp3\n", table.gp3); + IWL_ERR(mvm, "0x%08X | uCode revision type\n", table.fw_rev_type); IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major); IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor); IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver); @@ -645,7 +645,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2); IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3); IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4); - IWL_ERR(mvm, "0x%08X | isr_pref\n", table.isr_pref); + IWL_ERR(mvm, "0x%08X | last cmd Id\n", table.last_cmd_id); IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event); IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control); IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration); -- cgit v1.2.3 From 81279c49ce472bf5900ef8b19bf91e2ad6bd1c34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Mar 2016 14:58:47 +0100 Subject: iwlwifi: mvm: don't try to offload AES-CMAC in AP/IBSS modes The firmware/hardware only supports checking AES-CMAC on RX, not using it on TX. For station mode this is fine, since it's the only thing it will ever do. For AP mode, it never receives such frames, but must be able to transmit them. This is currently broken since we try to enable them for hardware crypto (for RX only) and then treat them as TX_CMD_SEC_EXT, leading to FIFO underruns during TX so the frames never go out to the air. To fix this, simply use software on TX in AP (and IBSS) mode. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 39b9c383c272..76e649c680a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2686,8 +2686,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, * GTK on AP interface is a TX-only key, return 0; * on IBSS they're per-station and because we're lazy * we don't support them for RX, so do the same. + * CMAC in AP/IBSS modes must be done in software. */ - ret = 0; + if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) + ret = -EOPNOTSUPP; + else + ret = 0; key->hw_key_idx = STA_KEY_IDX_INVALID; break; } -- cgit v1.2.3 From 5ed47226e06195935c5a2b88604b340a4364867e Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Wed, 3 Feb 2016 15:36:52 +0200 Subject: iwlwifi: mvm: update GSCAN capabilities Gscan capabilities were updated with new capabilities supported by the device. While at it, simplify the firmware support conditional and move both conditions into the WARN() to make it easier to undertand and use the unlikely() for both. Signed-off-by: Ayala Beker Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 38 +++++++++++++++--------- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 11 +++++++ drivers/net/wireless/intel/iwlwifi/iwl-fw.h | 13 ++++++++ 3 files changed, 48 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 184c0fef37c0..f899666acb41 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -7,6 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -374,15 +376,12 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len) return 0; } -static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, - const u32 len) +static void iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, + const u32 len) { struct iwl_fw_gscan_capabilities *fw_capa = (void *)data; struct iwl_gscan_capabilities *capa = &fw->gscan_capa; - if (len < sizeof(*fw_capa)) - return -EINVAL; - capa->max_scan_cache_size = le32_to_cpu(fw_capa->max_scan_cache_size); capa->max_scan_buckets = le32_to_cpu(fw_capa->max_scan_buckets); capa->max_ap_cache_per_scan = @@ -395,7 +394,15 @@ static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, le32_to_cpu(fw_capa->max_significant_change_aps); capa->max_bssid_history_entries = le32_to_cpu(fw_capa->max_bssid_history_entries); - return 0; + capa->max_hotlist_ssids = le32_to_cpu(fw_capa->max_hotlist_ssids); + capa->max_number_epno_networks = + le32_to_cpu(fw_capa->max_number_epno_networks); + capa->max_number_epno_networks_by_ssid = + le32_to_cpu(fw_capa->max_number_epno_networks_by_ssid); + capa->max_number_of_white_listed_ssid = + le32_to_cpu(fw_capa->max_number_of_white_listed_ssid); + capa->max_number_of_black_listed_ssid = + le32_to_cpu(fw_capa->max_number_of_black_listed_ssid); } /* @@ -1023,8 +1030,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, le32_to_cpup((__le32 *)tlv_data); break; case IWL_UCODE_TLV_FW_GSCAN_CAPA: - if (iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len)) - goto invalid_tlv_len; + /* + * Don't return an error in case of a shorter tlv_len + * to enable loading of FW that has an old format + * of GSCAN capabilities TLV. + */ + if (tlv_len < sizeof(struct iwl_fw_gscan_capabilities)) + break; + + iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len); gscan_capa = true; break; default: @@ -1046,12 +1060,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, return -EINVAL; } - /* - * If ucode advertises that it supports GSCAN but GSCAN - * capabilities TLV is not present, warn and continue without GSCAN. - */ - if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) && - WARN(!gscan_capa, + if (WARN(fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) && + !gscan_capa, "GSCAN is supported but capabilities TLV is unavailable\n")) __clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT, capa->_capa); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 5f69bf5e04c7..15ec4e2907d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -809,6 +809,12 @@ struct iwl_fw_dbg_conf_tlv { * change APs. * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can * hold. + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs. + * @max_number_epno_networks: max number of epno entries. + * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is + * specified. + * @max_number_of_white_listed_ssid: max number of white listed SSIDs. + * @max_number_of_black_listed_ssid: max number of black listed SSIDs. */ struct iwl_fw_gscan_capabilities { __le32 max_scan_cache_size; @@ -819,6 +825,11 @@ struct iwl_fw_gscan_capabilities { __le32 max_hotlist_aps; __le32 max_significant_change_aps; __le32 max_bssid_history_entries; + __le32 max_hotlist_ssids; + __le32 max_number_epno_networks; + __le32 max_number_epno_networks_by_ssid; + __le32 max_number_of_white_listed_ssid; + __le32 max_number_of_black_listed_ssid; } __packed; #endif /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h index 85d6d6d55e2f..2942571c613f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h @@ -7,6 +7,7 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -205,6 +207,12 @@ struct iwl_fw_cscheme_list { * change APs. * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can * hold. + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs. + * @max_number_epno_networks: max number of epno entries. + * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is + * specified. + * @max_number_of_white_listed_ssid: max number of white listed SSIDs. + * @max_number_of_black_listed_ssid: max number of black listed SSIDs. */ struct iwl_gscan_capabilities { u32 max_scan_cache_size; @@ -215,6 +223,11 @@ struct iwl_gscan_capabilities { u32 max_hotlist_aps; u32 max_significant_change_aps; u32 max_bssid_history_entries; + u32 max_hotlist_ssids; + u32 max_number_epno_networks; + u32 max_number_epno_networks_by_ssid; + u32 max_number_of_white_listed_ssid; + u32 max_number_of_black_listed_ssid; }; /** -- cgit v1.2.3 From 3691ac4a9c957c2896f8ebfb8a92081301f1682e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 8 Mar 2016 15:04:08 +0300 Subject: libertas: fix an error code in probe We accidentally return success instead of a negative error code. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index b35b8bcce24c..8541cbed786d 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -1118,7 +1118,8 @@ int lbs_start_card(struct lbs_private *priv) else pr_info("%s: mesh disabled\n", dev->name); - if (lbs_cfg_register(priv)) { + ret = lbs_cfg_register(priv); + if (ret) { pr_err("cannot register device\n"); goto done; } -- cgit v1.2.3 From 107b87133361aa5502d7d3c82cdfff77bf8ebe18 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 9 Mar 2016 15:25:26 +0800 Subject: brcmfmac: Remove waitqueue_active check We met a problem of pm_suspend when repeated closing/opening the lid on a Lenovo laptop (1/20 reproduce rate), below is the log: [ 199.735876] PM: Entering mem sleep [ 199.750516] e1000e: EEE TX LPI TIMER: 00000011 [ 199.856638] Trying to free nonexistent resource <000000000000d000-000000000000d0ff> [ 201.753566] brcmfmac: brcmf_pcie_suspend: Timeout on response for entering D3 substate [ 201.753581] pci_legacy_suspend(): brcmf_pcie_suspend+0x0/0x1f0 [brcmfmac] returns -5 [ 201.753585] dpm_run_callback(): pci_pm_suspend+0x0/0x160 returns -5 [ 201.753589] PM: Device 0000:04:00.0 failed to suspend async: error -5 Through debugging, we found when problem happens, it is not the device fails to enter D3, but the signal D3_ACK comes too early to pass the waitqueue_active() check. Just like this: brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM); // signal is triggered here wait_event_timeout(devinfo->mbdata_resp_wait, devinfo->mbdata_completed, BRCMF_PCIE_MBDATA_TIMEOUT); So far I think it is safe to remove waitqueue_active check since there is only one place to trigger this signal (sending BRCMF_H2D_HOST_D3_INFORM). And it is not a problem calling wake_up event earlier than calling wait_event. Cc: Brett Rudley Cc: Hante Meuleman Cc: Franky (Zhenhui) Lin Cc: Pieter-Paul Giesberts Cc: Arend van Spriel Signed-off-by: Hui Wang Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 52fef5e1d615..0af8db82da0c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -677,10 +677,8 @@ static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo) brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP EXIT\n"); if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) { brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n"); - if (waitqueue_active(&devinfo->mbdata_resp_wait)) { - devinfo->mbdata_completed = true; - wake_up(&devinfo->mbdata_resp_wait); - } + devinfo->mbdata_completed = true; + wake_up(&devinfo->mbdata_resp_wait); } } -- cgit v1.2.3 From 54f008497b9f09f0880dd84ce5608be4ad7cff13 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 9 Mar 2016 04:21:11 -0800 Subject: mwifiex: Empty Tx queue during suspend In cfg80211 suspend handler, stop the netif queue and wait until all the Tx queues become empty. Start the queues in resume handler. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 28 ++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 29b7f6eed240..bb7235e1b9d1 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -20,6 +20,7 @@ #include "cfg80211.h" #include "main.h" #include "11n.h" +#include "wmm.h" static char *reg_alpha2; module_param(reg_alpha2, charp, 0); @@ -3259,7 +3260,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_ds_hs_cfg hs_cfg; - int i, ret = 0; + int i, ret = 0, retry_num = 10; struct mwifiex_private *priv; for (i = 0; i < adapter->priv_num; i++) { @@ -3269,6 +3270,21 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mwifiex_cancel_all_pending_cmd(adapter); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv && priv->netdev) + mwifiex_stop_net_dev_queue(priv->netdev, adapter); + } + + for (i = 0; i < retry_num; i++) { + if (!mwifiex_wmm_lists_empty(adapter) || + !mwifiex_bypass_txlist_empty(adapter) || + !skb_queue_empty(&adapter->tx_data_q)) + usleep_range(10000, 15000); + else + break; + } + if (!wowlan) { mwifiex_dbg(adapter, ERROR, "None of the WOWLAN triggers enabled\n"); @@ -3321,12 +3337,18 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, static int mwifiex_cfg80211_resume(struct wiphy *wiphy) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + struct mwifiex_private *priv; struct mwifiex_ds_wakeup_reason wakeup_reason; struct cfg80211_wowlan_wakeup wakeup_report; int i; + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv && priv->netdev) + mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); + } + + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); mwifiex_get_wakeup_reason(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD, &wakeup_reason); memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup)); -- cgit v1.2.3 From 87cba1696045cbf963d09c82ceca98db92b7ace9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 7 Mar 2016 00:28:08 +0200 Subject: wlcore: don't WARN_ON in case of existing ROC When working with AP + P2P, it's possible to get into a state when the AP is in ROC (due to assiciating station) while trying to ROC on the P2P interface. Replace the WARN_ON with wl1271_error to avoid warnings in this case. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 45662cf3169f..dde36203ca42 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5495,7 +5495,7 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271 *wl = hw->priv; - int channel, ret = 0; + int channel, active_roc, ret = 0; channel = ieee80211_frequency_to_channel(chan->center_freq); @@ -5508,9 +5508,9 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, goto out; /* return EBUSY if we can't ROC right now */ - if (WARN_ON(wl->roc_vif || - find_first_bit(wl->roc_map, - WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) { + active_roc = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES); + if (wl->roc_vif || active_roc < WL12XX_MAX_ROLES) { + wl1271_warning("active roc on role %d", active_roc); ret = -EBUSY; goto out; } -- cgit v1.2.3 From 8cf77e176f921d20a1e61d288eaee74a2d1d2ae1 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 7 Mar 2016 00:28:09 +0200 Subject: wlcore/wl18xx: add radar_debug_mode handling Add debugfs key (under CFG80211_CERTIFICATION_ONUS configuration) to set/clear radar_debug_mode. In this mode, the driver simply ignores radar events (but prints them). The fw is notified about this mode through a special generic_cfg_feature command. This mode is relevant only for ap mode. look for it when initializing ap vif. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/debugfs.c | 66 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/event.c | 3 +- drivers/net/wireless/ti/wlcore/init.c | 5 +++ drivers/net/wireless/ti/wlcore/wlcore.h | 1 + 4 files changed, 74 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 4edfe28395f0..86ccf84ea0c6 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -345,6 +345,69 @@ static const struct file_operations dynamic_fw_traces_ops = { .llseek = default_llseek, }; +#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS +static ssize_t radar_debug_mode_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + struct wl12xx_vif *wlvif; + unsigned long value; + int ret; + + ret = kstrtoul_from_user(user_buf, count, 10, &value); + if (ret < 0) { + wl1271_warning("illegal radar_debug_mode value!"); + return -EINVAL; + } + + /* valid values: 0/1 */ + if (!(value == 0 || value == 1)) { + wl1271_warning("value is not in valid!"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + wl->radar_debug_mode = value; + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_for_each_wlvif_ap(wl, wlvif) { + wlcore_cmd_generic_cfg(wl, wlvif, + WLCORE_CFG_FEATURE_RADAR_DEBUG, + wl->radar_debug_mode, 0); + } + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static ssize_t radar_debug_mode_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + + return wl1271_format_buffer(userbuf, count, ppos, + "%d\n", wl->radar_debug_mode); +} + +static const struct file_operations radar_debug_mode_ops = { + .write = radar_debug_mode_write, + .read = radar_debug_mode_read, + .open = simple_open, + .llseek = default_llseek, +}; +#endif /* CFG80211_CERTIFICATION_ONUS */ + int wl18xx_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -510,6 +573,9 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(conf, moddir); DEBUGFS_ADD(radar_detection, moddir); +#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS + DEBUGFS_ADD(radar_debug_mode, moddir); +#endif DEBUGFS_ADD(dynamic_fw_traces, moddir); return 0; diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index 719907a0a2c2..ff6e46dd61f8 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -146,7 +146,8 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) mbox->radar_channel, wl18xx_radar_type_decode(mbox->radar_type)); - ieee80211_radar_detected(wl->hw); + if (!wl->radar_debug_mode) + ieee80211_radar_detected(wl->hw); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index e92f2639af2c..d0b7734030ef 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -558,6 +558,11 @@ static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (ret < 0) return ret; + if (wl->radar_debug_mode) + wlcore_cmd_generic_cfg(wl, wlvif, + WLCORE_CFG_FEATURE_RADAR_DEBUG, + wl->radar_debug_mode, 0); + return 0; } diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index dda01b118c26..72c31a8edcfb 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -463,6 +463,7 @@ struct wl1271 { /* the current dfs region */ enum nl80211_dfs_regions dfs_region; + bool radar_debug_mode; /* size of the private FW status data */ size_t fw_status_len; -- cgit v1.2.3 From 3307d84024d2ed9c8aee0a4bfa694319613734bf Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:03:59 -0500 Subject: rtl8xxxu: Add initial code to parse rtl8192eu efuse This is the start of 8192eu support. For now just detect the device and parse the efuse. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 80 +++++++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 50 ++++++++++++++- 2 files changed, 124 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e654bd33b434..bb95d00f0565 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -42,7 +42,7 @@ #define DRIVER_NAME "rtl8xxxu" -static int rtl8xxxu_debug; +static int rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE; static bool rtl8xxxu_ht40_2g; MODULE_AUTHOR("Jes Sorensen "); @@ -1890,6 +1890,53 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) #endif +static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) +{ + int i; + + if (priv->efuse_wifi.efuse8192eu.rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192eu.mac_addr); + + memcpy(priv->cck_tx_power_index_A, + priv->efuse_wifi.efuse8192eu.cck_tx_power_index_A, + sizeof(priv->cck_tx_power_index_A)); + memcpy(priv->cck_tx_power_index_B, + priv->efuse_wifi.efuse8192eu.cck_tx_power_index_B, + sizeof(priv->cck_tx_power_index_B)); + + memcpy(priv->ht40_1s_tx_power_index_A, + priv->efuse_wifi.efuse8192eu.ht40_1s_tx_power_index_A, + sizeof(priv->ht40_1s_tx_power_index_A)); + memcpy(priv->ht40_1s_tx_power_index_B, + priv->efuse_wifi.efuse8192eu.ht40_1s_tx_power_index_B, + sizeof(priv->ht40_1s_tx_power_index_B)); + + dev_info(&priv->udev->dev, "Vendor: %.7s\n", + priv->efuse_wifi.efuse8192eu.vendor_name); + dev_info(&priv->udev->dev, "Product: %.11s\n", + priv->efuse_wifi.efuse8192eu.device_name); + dev_info(&priv->udev->dev, "Serial: %.11s\n", + priv->efuse_wifi.efuse8192eu.serial); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { + unsigned char *raw = priv->efuse_wifi.raw; + + dev_info(&priv->udev->dev, + "%s: dumping efuse (0x%02zx bytes):\n", + __func__, sizeof(struct rtl8192eu_efuse)); + for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8) { + dev_info(&priv->udev->dev, "%02x: " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, + raw[i], raw[i + 1], raw[i + 2], + raw[i + 3], raw[i + 4], raw[i + 5], + raw[i + 6], raw[i + 7]); + } + } + return -EINVAL; +} + static int rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data) { @@ -1973,7 +2020,7 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) } /* Default value is 0xff */ - memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN_8723A); + memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN); efuse_addr = 0; while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) { @@ -2005,7 +2052,7 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) /* We have 8 bits to indicate validity */ map_addr = offset * 8; - if (map_addr >= EFUSE_MAP_LEN_8723A) { + if (map_addr >= EFUSE_MAP_LEN) { dev_warn(dev, "%s: Illegal map_addr (%04x), " "efuse corrupt!\n", __func__, map_addr); @@ -2286,6 +2333,24 @@ static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) #endif +static int rtl8192eu_load_firmware(struct rtl8xxxu_priv *priv) +{ + char *fw_name; + int ret; + + return -EBUSY; + if (!priv->vendor_umc) + fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; + else if (priv->chip_cut || priv->rtlchip == 0x8192c) + fw_name = "rtlwifi/rtl8192cufw_B.bin"; + else + fw_name = "rtlwifi/rtl8192cufw_A.bin"; + + ret = rtl8xxxu_load_firmware(priv, fw_name); + + return ret; +} + static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv) { u16 val16; @@ -5863,6 +5928,13 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { #endif +static struct rtl8xxxu_fileops rtl8192eu_fops = { + .parse_efuse = rtl8192eu_parse_efuse, + .load_firmware = rtl8192eu_load_firmware, + .power_on = rtl8192cu_power_on, + .writeN_block_size = 128, +}; + static struct usb_device_id dev_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8723au_fops}, @@ -5870,6 +5942,8 @@ static struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8723au_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0724, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8723au_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192eu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index bbd0f6b76b82..8168a35c314c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -55,8 +55,8 @@ #define RTL8723A_MAX_RF_PATHS 2 #define RF6052_MAX_TX_PWR 0x3f -#define EFUSE_MAP_LEN_8723A 256 -#define EFUSE_MAX_SECTION_8723A 32 +#define EFUSE_MAP_LEN 512 +#define EFUSE_MAX_SECTION_8723A 64 #define EFUSE_REAL_CONTENT_LEN_8723A 512 #define EFUSE_BT_MAP_LEN_8723A 1024 #define EFUSE_MAX_WORD_UNIT 4 @@ -500,6 +500,49 @@ struct rtl8192cu_efuse { u8 customer_id; }; +struct rtl8192eu_efuse { + __le16 rtl_id; + u8 res0[0x0e]; + u8 cck_tx_power_index_A[3]; /* 0x10 */ + u8 cck_tx_power_index_B[3]; + u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ + u8 ht40_1s_tx_power_index_B[3]; + u8 res1[0x9c]; + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 pa_type; /* 0xbc */ + u8 lna_type_2g; /* 0xbd */ + u8 res2[1]; + u8 lna_type_5g; /* 0xbf */ + u8 res13[1]; + u8 rf_board_option; + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; + u8 res3[3]; + u8 rf_antenna_option; /* 0xc9 */ + u8 res4[6]; + u8 vid; /* 0xd0 */ + u8 res5[1]; + u8 pid; /* 0xd2 */ + u8 res6[1]; + u8 usb_optional_function; + u8 res7[2]; + u8 mac_addr[ETH_ALEN]; /* 0xd7 */ + u8 res8[2]; + u8 vendor_name[7]; + u8 res9[2]; + u8 device_name[0x0b]; /* 0xe8 */ + u8 res10[2]; + u8 serial[0x0b]; /* 0xf5 */ + u8 res11[0x30]; + u8 unknown[0x0d]; /* 0x130 */ + u8 res12[0xc3]; +}; + struct rtl8xxxu_reg8val { u16 reg; u8 val; @@ -643,9 +686,10 @@ struct rtl8xxxu_priv { u8 val8; } usb_buf; union { - u8 raw[EFUSE_MAP_LEN_8723A]; + u8 raw[EFUSE_MAP_LEN]; struct rtl8723au_efuse efuse8723; struct rtl8192cu_efuse efuse8192; + struct rtl8192eu_efuse efuse8192eu; } efuse_wifi; u32 adda_backup[RTL8XXXU_ADDA_REGS]; u32 mac_backup[RTL8XXXU_MAC_REGS]; -- cgit v1.2.3 From 0e5d435a619fadb475f3a260eda2252acd1662f0 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:00 -0500 Subject: rtl8xxxu: Identify chip vendors correctly This identifies the chip vendors correctly and also picks the correct firmware for rtl8192eu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 73 +++++++++++++++++----- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 4 ++ 3 files changed, 64 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index bb95d00f0565..745942299f41 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1662,16 +1662,24 @@ static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv) case 1: cut = "B"; break; + case 2: + cut = "C"; + break; + case 3: + cut = "D"; + break; + case 4: + cut = "E"; + break; default: cut = "unknown"; } dev_info(dev, "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", - priv->chip_name, cut, priv->vendor_umc ? "UMC" : "TSMC", - priv->tx_paths, priv->rx_paths, priv->ep_tx_count, - priv->has_wifi, priv->has_bluetooth, priv->has_gps, - priv->hi_pa); + priv->chip_name, cut, priv->chip_vendor, priv->tx_paths, + priv->rx_paths, priv->ep_tx_count, priv->has_wifi, + priv->has_bluetooth, priv->has_gps, priv->hi_pa); dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr); } @@ -1708,7 +1716,21 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) } else if (val32 & SYS_CFG_TYPE_ID) { bonding = rtl8xxxu_read32(priv, REG_HPON_FSM); bonding &= HPON_FSM_BONDING_MASK; - if (bonding == HPON_FSM_BONDING_1T2R) { + if (priv->chip_cut >= 3) { + if (bonding == HPON_FSM_BONDING_1T2R) { + sprintf(priv->chip_name, "8191EU"); + priv->rf_paths = 2; + priv->rx_paths = 2; + priv->tx_paths = 1; + priv->rtlchip = 0x8191e; + } else { + sprintf(priv->chip_name, "8192EU"); + priv->rf_paths = 2; + priv->rx_paths = 2; + priv->tx_paths = 2; + priv->rtlchip = 0x8192e; + } + } else if (bonding == HPON_FSM_BONDING_1T2R) { sprintf(priv->chip_name, "8191CU"); priv->rf_paths = 2; priv->rx_paths = 2; @@ -1731,8 +1753,34 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->has_wifi = 1; } - if (val32 & SYS_CFG_VENDOR_ID) - priv->vendor_umc = 1; + switch (priv->rtlchip) { + case 0x8188e: + case 0x8192e: + case 0x8723b: + switch (val32 & SYS_CFG_VENDOR_EXT_MASK) { + case SYS_CFG_VENDOR_ID_TSMC: + sprintf(priv->chip_vendor, "TSMC"); + break; + case SYS_CFG_VENDOR_ID_SMIC: + sprintf(priv->chip_vendor, "SMIC"); + priv->vendor_smic = 1; + break; + case SYS_CFG_VENDOR_ID_UMC: + sprintf(priv->chip_vendor, "UMC"); + priv->vendor_umc = 1; + break; + default: + sprintf(priv->chip_vendor, "unknown"); + } + break; + default: + if (val32 & SYS_CFG_VENDOR_ID) { + sprintf(priv->chip_vendor, "UMC"); + priv->vendor_umc = 1; + } else { + sprintf(priv->chip_vendor, "TSMC"); + } + } val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28; @@ -1934,7 +1982,7 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) raw[i + 6], raw[i + 7]); } } - return -EINVAL; + return 0; } static int @@ -2269,6 +2317,7 @@ static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) signature = le16_to_cpu(priv->fw_data->signature); switch (signature & 0xfff0) { + case 0x92e0: case 0x92c0: case 0x88c0: case 0x2300: @@ -2338,13 +2387,7 @@ static int rtl8192eu_load_firmware(struct rtl8xxxu_priv *priv) char *fw_name; int ret; - return -EBUSY; - if (!priv->vendor_umc) - fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; - else if (priv->chip_cut || priv->rtlchip == 0x8192c) - fw_name = "rtlwifi/rtl8192cufw_B.bin"; - else - fw_name = "rtlwifi/rtl8192cufw_A.bin"; + fw_name = "rtlwifi/rtl8192eu_nic.bin"; ret = rtl8xxxu_load_firmware(priv, fw_name); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 8168a35c314c..0d4ff80f0ab1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -625,6 +625,7 @@ struct rtl8xxxu_priv { u8 mac_addr[ETH_ALEN]; char chip_name[8]; + char chip_vendor[8]; u8 cck_tx_power_index_A[3]; /* 0x10 */ u8 cck_tx_power_index_B[3]; u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ @@ -647,6 +648,7 @@ struct rtl8xxxu_priv { u32 has_gps:1; u32 hi_pa:1; u32 vendor_umc:1; + u32 vendor_smic:1; u32 has_polarity_ctrl:1; u32 has_eeprom:1; u32 boot_eeprom:1; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 8f6c9c6c7c09..a934c0de197b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -222,6 +222,10 @@ #define SYS_CFG_CHIP_VER (BIT(12) | BIT(13) | BIT(14) | BIT(15)) #define SYS_CFG_BT_FUNC BIT(16) #define SYS_CFG_VENDOR_ID BIT(19) +#define SYS_CFG_VENDOR_EXT_MASK (BIT(18) | BIT(19)) +#define SYS_CFG_VENDOR_ID_TSMC 0 +#define SYS_CFG_VENDOR_ID_SMIC BIT(18) +#define SYS_CFG_VENDOR_ID_UMC BIT(19) #define SYS_CFG_PAD_HWPD_IDN BIT(22) #define SYS_CFG_TRP_VAUX_EN BIT(23) #define SYS_CFG_TRP_BT_EN BIT(24) -- cgit v1.2.3 From 4a82ffe3f8040c5b3dd50888e00077d1cc8cbf29 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:01 -0500 Subject: rtl8xxxu: Use 1024 byte block loads for 8192eu firmware The rtl8192eu can handle 1024 byte block writes, unlike it's predecessors (8192cu/8188cu). Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 745942299f41..35c0625141f1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5975,7 +5975,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .parse_efuse = rtl8192eu_parse_efuse, .load_firmware = rtl8192eu_load_firmware, .power_on = rtl8192cu_power_on, - .writeN_block_size = 128, + .writeN_block_size = 1024, }; static struct usb_device_id dev_table[] = { -- cgit v1.2.3 From b001e086c4c8a5e60a2a28d40ded47ab124458f6 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:02 -0500 Subject: rtl8xxxu: Add rtl8192eu_nic.bin to the MODULE_FIRMWARE list Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 35c0625141f1..e48815f25c8a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -54,6 +54,7 @@ MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192eu_nic.bin"); module_param_named(debug, rtl8xxxu_debug, int, 0600); MODULE_PARM_DESC(debug, "Set debug mask"); -- cgit v1.2.3 From c05a9dbfb2b1f30b13126b0901fe4f1bdaf37406 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:03 -0500 Subject: rtl8xxxu: Implment rtl8192eu_power_on() This implements the rtl8192eu power on sequence, and splits it off from the rtl8192cu/rtl8723au power on sequence. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 133 ++++++++++++++++++++- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 6 + 2 files changed, 133 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e48815f25c8a..55d12fbb0345 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -3791,7 +3791,7 @@ exit: return ret; } -static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv) +static void rtl8723a_disabled_to_emu(struct rtl8xxxu_priv *priv) { u8 val8; @@ -3811,7 +3811,82 @@ static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); } -static int rtl8xxxu_emu_to_active(struct rtl8xxxu_priv *priv) +static void rtl8192e_disabled_to_emu(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + /* Clear suspend enable and power down enable*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~(BIT(3) | BIT(4)); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); +} + +static int rtl8192e_emu_to_active(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u32 val32; + int count, ret = 0; + + /* disable HWPDN 0x04[15]=0*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~BIT(7); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* disable SW LPS 0x04[10]= 0 */ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~BIT(2); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* disable WL suspend*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~(BIT(3) | BIT(4)); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* wait till 0x04[17] = 1 power ready*/ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if (val32 & BIT(17)) + break; + + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* We should be able to optimize the following three entries into one */ + + /* release WLON reset 0x04[16]= 1*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2); + val8 |= BIT(0); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8); + + /* set, then poll until 0 */ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 |= APS_FSMCO_MAC_ENABLE; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) { + ret = 0; + break; + } + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + +exit: + return ret; +} + +static int rtl8723a_emu_to_active(struct rtl8xxxu_priv *priv) { u8 val8; u32 val32; @@ -3940,9 +4015,9 @@ static int rtl8723au_power_on(struct rtl8xxxu_priv *priv) */ rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0); - rtl8xxxu_disabled_to_emu(priv); + rtl8723a_disabled_to_emu(priv); - ret = rtl8xxxu_emu_to_active(priv); + ret = rtl8723a_emu_to_active(priv); if (ret) goto exit; @@ -4081,6 +4156,52 @@ static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv) #endif +static int rtl8192eu_power_on(struct rtl8xxxu_priv *priv) +{ + u16 val16; + u32 val32; + int ret; + + ret = 0; + + val32 = rtl8xxxu_read32(priv, REG_SYS_CFG); + if (val32 & SYS_CFG_SPS_LDO_SEL) { + rtl8xxxu_write8(priv, REG_LDO_SW_CTRL, 0xc3); + } else { + /* + * Raise 1.2V voltage + */ + val32 = rtl8xxxu_read32(priv, REG_8192E_LDOV12_CTRL); + val32 &= 0xff0fffff; + val32 |= 0x00500000; + rtl8xxxu_write32(priv, REG_8192E_LDOV12_CTRL, val32); + rtl8xxxu_write8(priv, REG_LDO_SW_CTRL, 0x83); + } + + rtl8192e_disabled_to_emu(priv); + + ret = rtl8192e_emu_to_active(priv); + if (ret) + goto exit; + + rtl8xxxu_write16(priv, REG_CR, 0x0000); + + /* + * Enable MAC DMA/WMAC/SCHEDULE/SEC block + * Set CR bit10 to enable 32k calibration. + */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | + CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE | + CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE | + CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + +exit: + return ret; +} + static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) { u8 val8; @@ -5975,8 +6096,8 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { static struct rtl8xxxu_fileops rtl8192eu_fops = { .parse_efuse = rtl8192eu_parse_efuse, .load_firmware = rtl8192eu_load_firmware, - .power_on = rtl8192cu_power_on, - .writeN_block_size = 1024, + .power_on = rtl8192eu_power_on, + .writeN_block_size = 128, }; static struct usb_device_id dev_table[] = { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index a934c0de197b..02c7d6c6f62d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -72,6 +72,7 @@ #define REG_AFE_MISC 0x0010 #define REG_SPS0_CTRL 0x0011 #define REG_SPS_OCP_CFG 0x0018 +#define REG_8192E_LDOV12_CTRL 0x0014 #define REG_RSV_CTRL 0x001c #define REG_RF_CTRL 0x001f @@ -178,6 +179,8 @@ control */ #define MULTI_GPS_FUNC_EN BIT(22) /* GPS function enable */ +#define REG_LDO_SW_CTRL 0x007c /* 8192eu */ + #define REG_MCU_FW_DL 0x0080 #define MCU_FW_DL_ENABLE BIT(0) #define MCU_FW_DL_READY BIT(1) @@ -229,6 +232,7 @@ #define SYS_CFG_PAD_HWPD_IDN BIT(22) #define SYS_CFG_TRP_VAUX_EN BIT(23) #define SYS_CFG_TRP_BT_EN BIT(24) +#define SYS_CFG_SPS_LDO_SEL BIT(24) /* 8192eu */ #define SYS_CFG_BD_PKG_SEL BIT(25) #define SYS_CFG_BD_HCI_SEL BIT(26) #define SYS_CFG_TYPE_ID BIT(27) @@ -261,6 +265,8 @@ #define GPIO_USB_SUSEN BIT(23) #define GPIO_RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) +#define REG_SYS_CFG2 0x00fc /* 8192eu */ + /* 0x0100 ~ 0x01FF MACTOP General Configuration */ #define REG_CR 0x0100 #define CR_HCI_TXDMA_ENABLE BIT(0) -- cgit v1.2.3 From 74b99bed874f5a17336515b63f776a8cbbbceb93 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:04 -0500 Subject: rtl8xxxu: Add rtl8xxxu_auto_llt_table() Newer chips can auto load the LLT table, it is no longer necessary to build it manually in the driver. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 33 +++++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 3 ++ 3 files changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 55d12fbb0345..b2e4eac4d14f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2774,6 +2774,34 @@ exit: return ret; } +static int rtl8xxxu_auto_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page) +{ + u32 val32; + int ret = 0; + int i; + + val32 = rtl8xxxu_read32(priv, REG_AUTO_LLT); + pr_info("AUTO_LLT = %08x\n", val32); + val32 |= AUTO_LLT_INIT_LLT; + rtl8xxxu_write32(priv, REG_AUTO_LLT, val32); + + for (i = 500; i; i--) { + val32 = rtl8xxxu_read32(priv, REG_AUTO_LLT); + if (!(val32 & AUTO_LLT_INIT_LLT)) + break; + usleep_range(2, 4); + } + + if (i) { + ret = -EBUSY; + dev_warn(&priv->udev->dev, "LLT table init failed\n"); + } + else + dev_warn(&priv->udev->dev, "LLT table init success\n"); + + return ret; +} + static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv) { u16 val16, hi, lo; @@ -4287,7 +4315,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); if (!macpower) { - ret = rtl8xxxu_init_llt_table(priv, TX_TOTAL_PAGE_NUM); + ret = priv->fops->llt_init(priv, TX_TOTAL_PAGE_NUM); if (ret) { dev_warn(dev, "%s: LLT table init failed\n", __func__); goto exit; @@ -6079,6 +6107,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .parse_efuse = rtl8723au_parse_efuse, .load_firmware = rtl8723au_load_firmware, .power_on = rtl8723au_power_on, + .llt_init = rtl8xxxu_init_llt_table, .writeN_block_size = 1024, }; @@ -6088,6 +6117,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .parse_efuse = rtl8192cu_parse_efuse, .load_firmware = rtl8192cu_load_firmware, .power_on = rtl8192cu_power_on, + .llt_init = rtl8xxxu_init_llt_table, .writeN_block_size = 128, }; @@ -6097,6 +6127,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .parse_efuse = rtl8192eu_parse_efuse, .load_firmware = rtl8192eu_load_firmware, .power_on = rtl8192eu_power_on, + .llt_init = rtl8xxxu_auto_llt_table, .writeN_block_size = 128, }; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 0d4ff80f0ab1..56c4e0a7c07d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -718,5 +718,6 @@ struct rtl8xxxu_fileops { int (*parse_efuse) (struct rtl8xxxu_priv *priv); int (*load_firmware) (struct rtl8xxxu_priv *priv); int (*power_on) (struct rtl8xxxu_priv *priv); + int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); int writeN_block_size; }; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 02c7d6c6f62d..b83bd34bdd76 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -372,6 +372,9 @@ #define RQPN_NPQ_SHIFT 0 #define RQPN_EPQ_SHIFT 16 +#define REG_AUTO_LLT 0x0224 +#define AUTO_LLT_INIT_LLT BIT(16) + /* 0x0280 ~ 0x02FF RXDMA Configuration */ #define REG_RXDMA_AGG_PG_TH 0x0280 #define REG_RXPKT_NUM 0x0284 -- cgit v1.2.3 From 07bb46be5306d27c8d8ce7b287688554b9ca1569 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:05 -0500 Subject: rtl8xxxu: Init page boundaries before starting the firmware This reorganizes the device initialization to init page boundaries before starting the firmware. This matches the flow in the 8192eu vendor driver. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 68 ++++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index b2e4eac4d14f..65994e938a17 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4313,6 +4313,40 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) goto exit; } + dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); + if (!macpower) { + if (priv->ep_tx_normal_queue) + val8 = TX_PAGE_NUM_NORM_PQ; + else + val8 = 0; + + rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8); + + val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD; + + if (priv->ep_tx_high_queue) + val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT); + if (priv->ep_tx_low_queue) + val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT); + + rtl8xxxu_write32(priv, REG_RQPN, val32); + + /* + * Set TX buffer boundary + */ + val8 = TX_TOTAL_PAGE_NUM + 1; + rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8); + rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8); + rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8); + rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8); + rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8); + } + + ret = rtl8xxxu_init_queue_priority(priv); + dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret); + if (ret) + goto exit; + dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); if (!macpower) { ret = priv->fops->llt_init(priv, TX_TOTAL_PAGE_NUM); @@ -4392,40 +4426,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG); - dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); - if (!macpower) { - if (priv->ep_tx_normal_queue) - val8 = TX_PAGE_NUM_NORM_PQ; - else - val8 = 0; - - rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8); - - val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD; - - if (priv->ep_tx_high_queue) - val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT); - if (priv->ep_tx_low_queue) - val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT); - - rtl8xxxu_write32(priv, REG_RQPN, val32); - - /* - * Set TX buffer boundary - */ - val8 = TX_TOTAL_PAGE_NUM + 1; - rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8); - rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8); - rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8); - rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8); - rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8); - } - - ret = rtl8xxxu_init_queue_priority(priv); - dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret); - if (ret) - goto exit; - /* * Set RX page boundary */ -- cgit v1.2.3 From a47b9d477c792f8c0c9b6419a25528566260916a Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:06 -0500 Subject: rtl8xxxu: Init the LLT after we start the firmware To match the flow of the vendor driver, move the LLT init to after the firmware is started. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 65994e938a17..ad5b15cb07b6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4342,6 +4342,15 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8); } + ret = rtl8xxxu_download_firmware(priv); + dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret); + if (ret) + goto exit; + ret = rtl8xxxu_start_firmware(priv); + dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret); + if (ret) + goto exit; + ret = rtl8xxxu_init_queue_priority(priv); dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret); if (ret) @@ -4356,15 +4365,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) } } - ret = rtl8xxxu_download_firmware(priv); - dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret); - if (ret) - goto exit; - ret = rtl8xxxu_start_firmware(priv); - dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret); - if (ret) - goto exit; - ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); dev_dbg(dev, "%s: init_mac %i\n", __func__, ret); if (ret) -- cgit v1.2.3 From 4de24819192eb507525fa24182c86c2073accd12 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:07 -0500 Subject: rtl8xxxu: Fix incorrect test for auto LLT failure The logic for testing auto load failure in rtl8xxxu_auto_llt_table() was inverted. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ad5b15cb07b6..68d6bb89f719 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2781,7 +2781,6 @@ static int rtl8xxxu_auto_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page) int i; val32 = rtl8xxxu_read32(priv, REG_AUTO_LLT); - pr_info("AUTO_LLT = %08x\n", val32); val32 |= AUTO_LLT_INIT_LLT; rtl8xxxu_write32(priv, REG_AUTO_LLT, val32); @@ -2792,12 +2791,10 @@ static int rtl8xxxu_auto_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page) usleep_range(2, 4); } - if (i) { + if (!i) { ret = -EBUSY; dev_warn(&priv->udev->dev, "LLT table init failed\n"); } - else - dev_warn(&priv->udev->dev, "LLT table init success\n"); return ret; } -- cgit v1.2.3 From b63d0aaca62be6eed15d3829174307ac2d608623 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:08 -0500 Subject: rtl8xxxu: Kludge to drop incorrect USB OUT EP for 8192EU The 8192eu (and some other parts) will report an incorrect USB OUT EP. This tells the chip to drop it - as per the vendor driver. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 6 ++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 1 + 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 68d6bb89f719..b6d8014b8335 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4362,6 +4362,12 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) } } + if (priv->rtlchip == 0x8192e) { + val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK); + val32 |= TXDMA_OFFSET_DROP_DATA_EN; + rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); + } + ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); dev_dbg(dev, "%s: init_mac %i\n", __func__, ret); if (ret) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index b83bd34bdd76..226a1fa7d8b9 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -367,6 +367,7 @@ #define REG_FIFOPAGE 0x0204 #define REG_TDECTRL 0x0208 #define REG_TXDMA_OFFSET_CHK 0x020c +#define TXDMA_OFFSET_DROP_DATA_EN BIT(9) #define REG_TXDMA_STATUS 0x0210 #define REG_RQPN_NPQ 0x0214 #define RQPN_NPQ_SHIFT 0 -- cgit v1.2.3 From 99ad16cbea15a6e61acca5662eff8d195cc6fbf6 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:09 -0500 Subject: rtl8xxxu: Init REG_HIMR[01] for 8192eu parts The newer generation chips have different interrupt registers. Initialize this correct registers on 8192eu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 3 +++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index b6d8014b8335..e4d81277a3b0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4366,6 +4366,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK); val32 |= TXDMA_OFFSET_DROP_DATA_EN; rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); + + rtl8xxxu_write32(priv, REG_HIMR0, 0x00); + rtl8xxxu_write32(priv, REG_HIMR1, 0x00); } ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 226a1fa7d8b9..3cbb54956e79 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -196,6 +196,10 @@ #define REG_HMBOX_EXT_1 0x008a #define REG_HMBOX_EXT_2 0x008c #define REG_HMBOX_EXT_3 0x008e +/* Interrupt registers for 8192e/8812 */ +#define REG_HIMR0 0x00b0 +#define REG_HIMR1 0x00b8 + /* Host suspend counter on FPGA platform */ #define REG_HOST_SUSP_CNT 0x00bc /* Efuse access protection for RTL8723 */ -- cgit v1.2.3 From 35a741febfae3cfc2a27d3b4935e255585ecfd81 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:10 -0500 Subject: rtl8xxxu: Initial rtl8723bu chip identification This provides initial detection of 8723bu devices, and selects the correct firmware image to load. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 40 ++++++++++++++++++++++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 +- 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e4d81277a3b0..729f6d2d9d97 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -55,6 +55,8 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192eu_nic.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723bu_nic.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723bu_bt.bin"); module_param_named(debug, rtl8xxxu_debug, int, 0600); MODULE_PARM_DESC(debug, "Set debug mask"); @@ -1700,11 +1702,17 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) } if (val32 & SYS_CFG_BT_FUNC) { - sprintf(priv->chip_name, "8723AU"); + if (priv->chip_cut >= 3) { + sprintf(priv->chip_name, "8723BU"); + priv->rtlchip = 0x8723b; + } else { + sprintf(priv->chip_name, "8723AU"); + priv->rtlchip = 0x8723a; + } + priv->rf_paths = 1; priv->rx_paths = 1; priv->tx_paths = 1; - priv->rtlchip = 0x8723a; val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL); if (val32 & MULTI_WIFI_FUNC_EN) @@ -1807,6 +1815,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) */ if (!priv->ep_tx_count) { switch (priv->nr_out_eps) { + case 4: case 3: priv->ep_tx_low_queue = 1; priv->ep_tx_count++; @@ -2321,6 +2330,7 @@ static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) case 0x92e0: case 0x92c0: case 0x88c0: + case 0x5300: case 0x2300: break; default: @@ -2362,6 +2372,20 @@ static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv) return ret; } +static int rtl8723bu_load_firmware(struct rtl8xxxu_priv *priv) +{ + char *fw_name; + int ret; + + if (priv->enable_bluetooth) + fw_name = "rtlwifi/rtl8723bu_bt.bin"; + else + fw_name = "rtlwifi/rtl8723bu_nic.bin"; + + ret = rtl8xxxu_load_firmware(priv, fw_name); + return ret; +} + #ifdef CONFIG_RTL8XXXU_UNTESTED static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) @@ -2587,7 +2611,7 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) else rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table); - if (priv->rtlchip == 0x8723a && + if ((priv->rtlchip == 0x8723a || priv->rtlchip == 0x8723b) && priv->efuse_wifi.efuse8723.version >= 0x01) { val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL); @@ -6117,6 +6141,14 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .writeN_block_size = 1024, }; +static struct rtl8xxxu_fileops rtl8723bu_fops = { + .parse_efuse = rtl8723au_parse_efuse, + .load_firmware = rtl8723bu_load_firmware, + .power_on = rtl8723au_power_on, + .llt_init = rtl8xxxu_auto_llt_table, + .writeN_block_size = 128, +}; + #ifdef CONFIG_RTL8XXXU_UNTESTED static struct rtl8xxxu_fileops rtl8192cu_fops = { @@ -6146,6 +6178,8 @@ static struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8723au_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818b, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192eu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xb720, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8723bu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 56c4e0a7c07d..dd4c56379d50 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -34,7 +34,7 @@ #define RTL8XXXU_MAX_REG_POLL 500 #define USB_INTR_CONTENT_LENGTH 56 -#define RTL8XXXU_OUT_ENDPOINTS 3 +#define RTL8XXXU_OUT_ENDPOINTS 4 #define REALTEK_USB_READ 0xc0 #define REALTEK_USB_WRITE 0x40 -- cgit v1.2.3 From 3c836d6014e5057fc5845829ae762190008bded4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:11 -0500 Subject: rtl8xxxu: Add rtl8723bu_parse_efuse() and 8723bu efuse definition Implement first stab at parsing the 8723bu's efuse. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 47 +++++++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 42 +++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 729f6d2d9d97..255300c912d4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1877,6 +1877,51 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) return 0; } +static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) +{ + if (priv->efuse_wifi.efuse8723bu.rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723bu.mac_addr); + + memcpy(priv->cck_tx_power_index_A, + priv->efuse_wifi.efuse8723bu.cck_tx_power_index_A, + sizeof(priv->cck_tx_power_index_A)); + memcpy(priv->cck_tx_power_index_B, + priv->efuse_wifi.efuse8723bu.cck_tx_power_index_B, + sizeof(priv->cck_tx_power_index_B)); + + memcpy(priv->ht40_1s_tx_power_index_A, + priv->efuse_wifi.efuse8723bu.ht40_1s_tx_power_index_A, + sizeof(priv->ht40_1s_tx_power_index_A)); + memcpy(priv->ht40_1s_tx_power_index_B, + priv->efuse_wifi.efuse8723bu.ht40_1s_tx_power_index_B, + sizeof(priv->ht40_1s_tx_power_index_B)); + + dev_info(&priv->udev->dev, "Vendor: %.7s\n", + priv->efuse_wifi.efuse8723bu.vendor_name); + dev_info(&priv->udev->dev, "Product: %.41s\n", + priv->efuse_wifi.efuse8723bu.device_name); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { + int i; + unsigned char *raw = priv->efuse_wifi.raw; + + dev_info(&priv->udev->dev, + "%s: dumping efuse (0x%02zx bytes):\n", + __func__, sizeof(struct rtl8723bu_efuse)); + for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8) { + dev_info(&priv->udev->dev, "%02x: " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, + raw[i], raw[i + 1], raw[i + 2], + raw[i + 3], raw[i + 4], raw[i + 5], + raw[i + 6], raw[i + 7]); + } + } + + return 0; +} + #ifdef CONFIG_RTL8XXXU_UNTESTED static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) @@ -6142,7 +6187,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { }; static struct rtl8xxxu_fileops rtl8723bu_fops = { - .parse_efuse = rtl8723au_parse_efuse, + .parse_efuse = rtl8723bu_parse_efuse, .load_firmware = rtl8723bu_load_firmware, .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_auto_llt_table, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index dd4c56379d50..bf424db90901 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -500,6 +500,47 @@ struct rtl8192cu_efuse { u8 customer_id; }; +struct rtl8723bu_efuse { + __le16 rtl_id; + u8 res0[0x0e]; + u8 cck_tx_power_index_A[3]; /* 0x10 */ + u8 cck_tx_power_index_B[3]; + u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ + u8 ht40_1s_tx_power_index_B[3]; + u8 res1[0x9c]; + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 pa_type; /* 0xbc */ + u8 lna_type_2g; /* 0xbd */ + u8 res2[3]; + u8 rf_board_option; + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; + u8 res3[2]; + u8 tx_pwr_calibrate_rate; + u8 rf_antenna_option; /* 0xc9 */ + u8 rfe_option; + u8 res4[9]; + u8 usb_optional_function; + u8 res5[0x1e]; + u8 res6[2]; + u8 serial[0x0b]; /* 0xf5 */ + u8 vid; /* 0x100 */ + u8 res7; + u8 pid; + u8 res8[4]; + u8 mac_addr[ETH_ALEN]; /* 0x107 */ + u8 res9[2]; + u8 vendor_name[0x07]; + u8 res10[2]; + u8 device_name[0x14]; /* 0xe8 */ + u8 res11[0xd4]; +}; + struct rtl8192eu_efuse { __le16 rtl_id; u8 res0[0x0e]; @@ -690,6 +731,7 @@ struct rtl8xxxu_priv { union { u8 raw[EFUSE_MAP_LEN]; struct rtl8723au_efuse efuse8723; + struct rtl8723bu_efuse efuse8723bu; struct rtl8192cu_efuse efuse8192; struct rtl8192eu_efuse efuse8192eu; } efuse_wifi; -- cgit v1.2.3 From adfc01243f0fc891c630f27ef45320fea71bb98e Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:12 -0500 Subject: rtl8xxxu: Use 1024 byte writes for writing 8723bu firmware The 8723bu, like the 8192eu, can also handle 1024 byte block writes. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 255300c912d4..93f6b714d98b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6191,7 +6191,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .load_firmware = rtl8723bu_load_firmware, .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_auto_llt_table, - .writeN_block_size = 128, + .writeN_block_size = 1024, }; #ifdef CONFIG_RTL8XXXU_UNTESTED -- cgit v1.2.3 From 0e28b9753a9cf462a535c56e2d31ee17521a4b73 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:13 -0500 Subject: rtl8xxxu: Only setup USB interrupts for parts which support it Only 1st generation chips do provide USB interrupts, so do not try to setup interrupts for newer chips (8192eu and 8723bu). Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 18 +++++++++++++----- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 93f6b714d98b..467c0bcaadb1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1707,6 +1707,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->rtlchip = 0x8723b; } else { sprintf(priv->chip_name, "8723AU"); + priv->usb_interrupts = 1; priv->rtlchip = 0x8723a; } @@ -1744,12 +1745,14 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->rf_paths = 2; priv->rx_paths = 2; priv->tx_paths = 1; + priv->usb_interrupts = 1; priv->rtlchip = 0x8191c; } else { sprintf(priv->chip_name, "8192CU"); priv->rf_paths = 2; priv->rx_paths = 2; priv->tx_paths = 2; + priv->usb_interrupts = 1; priv->rtlchip = 0x8192c; } priv->has_wifi = 1; @@ -1759,6 +1762,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) priv->rx_paths = 1; priv->tx_paths = 1; priv->rtlchip = 0x8188c; + priv->usb_interrupts = 1; priv->has_wifi = 1; } @@ -5825,9 +5829,11 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) init_usb_anchor(&priv->int_anchor); rtl8723a_enable_rf(priv); - ret = rtl8xxxu_submit_int_urb(hw); - if (ret) - goto exit; + if (priv->usb_interrupts) { + ret = rtl8xxxu_submit_int_urb(hw); + if (ret) + goto exit; + } for (i = 0; i < RTL8XXXU_TX_URBS; i++) { tx_urb = kmalloc(sizeof(struct rtl8xxxu_tx_urb), GFP_KERNEL); @@ -5902,14 +5908,16 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) usb_kill_anchored_urbs(&priv->rx_anchor); usb_kill_anchored_urbs(&priv->tx_anchor); - usb_kill_anchored_urbs(&priv->int_anchor); + if (priv->usb_interrupts) + usb_kill_anchored_urbs(&priv->int_anchor); rtl8723a_disable_rf(priv); /* * Disable interrupts */ - rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + if (priv->usb_interrupts) + rtl8xxxu_write32(priv, REG_USB_HIMR, 0); rtl8xxxu_free_rx_resources(priv); rtl8xxxu_free_tx_resources(priv); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index bf424db90901..205504848558 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -693,6 +693,7 @@ struct rtl8xxxu_priv { u32 has_polarity_ctrl:1; u32 has_eeprom:1; u32 boot_eeprom:1; + u32 usb_interrupts:1; u32 ep_tx_high_queue:1; u32 ep_tx_normal_queue:1; u32 ep_tx_low_queue:1; -- cgit v1.2.3 From 36c32588c83df156e80e485e48a827cd57589620 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:14 -0500 Subject: rtl8xxxu: Add rtl8723b_phy_1t_init_table This adds the 8723bu PHY 1T init table. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 103 +++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 467c0bcaadb1..cc91247f7341 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -251,6 +251,107 @@ static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = { {0xffff, 0xffffffff}, }; +static struct rtl8xxxu_reg32val rtl8723b_phy_1t_init_table[] = { + {0x800, 0x80040000}, {0x804, 0x00000003}, + {0x808, 0x0000fc00}, {0x80c, 0x0000000a}, + {0x810, 0x10001331}, {0x814, 0x020c3d10}, + {0x818, 0x02200385}, {0x81c, 0x00000000}, + {0x820, 0x01000100}, {0x824, 0x00190204}, + {0x828, 0x00000000}, {0x82c, 0x00000000}, + {0x830, 0x00000000}, {0x834, 0x00000000}, + {0x838, 0x00000000}, {0x83c, 0x00000000}, + {0x840, 0x00010000}, {0x844, 0x00000000}, + {0x848, 0x00000000}, {0x84c, 0x00000000}, + {0x850, 0x00000000}, {0x854, 0x00000000}, + {0x858, 0x569a11a9}, {0x85c, 0x01000014}, + {0x860, 0x66f60110}, {0x864, 0x061f0649}, + {0x868, 0x00000000}, {0x86c, 0x27272700}, + {0x870, 0x07000760}, {0x874, 0x25004000}, + {0x878, 0x00000808}, {0x87c, 0x00000000}, + {0x880, 0xb0000c1c}, {0x884, 0x00000001}, + {0x888, 0x00000000}, {0x88c, 0xccc000c0}, + {0x890, 0x00000800}, {0x894, 0xfffffffe}, + {0x898, 0x40302010}, {0x89c, 0x00706050}, + {0x900, 0x00000000}, {0x904, 0x00000023}, + {0x908, 0x00000000}, {0x90c, 0x81121111}, + {0x910, 0x00000002}, {0x914, 0x00000201}, + {0xa00, 0x00d047c8}, {0xa04, 0x80ff800c}, + {0xa08, 0x8c838300}, {0xa0c, 0x2e7f120f}, + {0xa10, 0x9500bb78}, {0xa14, 0x1114d028}, + {0xa18, 0x00881117}, {0xa1c, 0x89140f00}, + {0xa20, 0x1a1b0000}, {0xa24, 0x090e1317}, + {0xa28, 0x00000204}, {0xa2c, 0x00d30000}, + {0xa70, 0x101fbf00}, {0xa74, 0x00000007}, + {0xa78, 0x00000900}, {0xa7c, 0x225b0606}, + {0xa80, 0x21806490}, {0xb2c, 0x00000000}, + {0xc00, 0x48071d40}, {0xc04, 0x03a05611}, + {0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c}, + {0xc10, 0x08800000}, {0xc14, 0x40000100}, + {0xc18, 0x08800000}, {0xc1c, 0x40000100}, + {0xc20, 0x00000000}, {0xc24, 0x00000000}, + {0xc28, 0x00000000}, {0xc2c, 0x00000000}, + {0xc30, 0x69e9ac44}, {0xc34, 0x469652af}, + {0xc38, 0x49795994}, {0xc3c, 0x0a97971c}, + {0xc40, 0x1f7c403f}, {0xc44, 0x000100b7}, + {0xc48, 0xec020107}, {0xc4c, 0x007f037f}, + {0xc50, 0x69553420}, {0xc54, 0x43bc0094}, + {0xc58, 0x00013149}, {0xc5c, 0x00250492}, + {0xc60, 0x00000000}, {0xc64, 0x7112848b}, + {0xc68, 0x47c00bff}, {0xc6c, 0x00000036}, + {0xc70, 0x2c7f000d}, {0xc74, 0x020610db}, + {0xc78, 0x0000001f}, {0xc7c, 0x00b91612}, + {0xc80, 0x390000e4}, {0xc84, 0x20f60000}, + {0xc88, 0x40000100}, {0xc8c, 0x20200000}, + {0xc90, 0x00020e1a}, {0xc94, 0x00000000}, + {0xc98, 0x00020e1a}, {0xc9c, 0x00007f7f}, + {0xca0, 0x00000000}, {0xca4, 0x000300a0}, + {0xca8, 0x00000000}, {0xcac, 0x00000000}, + {0xcb0, 0x00000000}, {0xcb4, 0x00000000}, + {0xcb8, 0x00000000}, {0xcbc, 0x28000000}, + {0xcc0, 0x00000000}, {0xcc4, 0x00000000}, + {0xcc8, 0x00000000}, {0xccc, 0x00000000}, + {0xcd0, 0x00000000}, {0xcd4, 0x00000000}, + {0xcd8, 0x64b22427}, {0xcdc, 0x00766932}, + {0xce0, 0x00222222}, {0xce4, 0x00000000}, + {0xce8, 0x37644302}, {0xcec, 0x2f97d40c}, + {0xd00, 0x00000740}, {0xd04, 0x40020401}, + {0xd08, 0x0000907f}, {0xd0c, 0x20010201}, + {0xd10, 0xa0633333}, {0xd14, 0x3333bc53}, + {0xd18, 0x7a8f5b6f}, {0xd2c, 0xcc979975}, + {0xd30, 0x00000000}, {0xd34, 0x80608000}, + {0xd38, 0x00000000}, {0xd3c, 0x00127353}, + {0xd40, 0x00000000}, {0xd44, 0x00000000}, + {0xd48, 0x00000000}, {0xd4c, 0x00000000}, + {0xd50, 0x6437140a}, {0xd54, 0x00000000}, + {0xd58, 0x00000282}, {0xd5c, 0x30032064}, + {0xd60, 0x4653de68}, {0xd64, 0x04518a3c}, + {0xd68, 0x00002101}, {0xd6c, 0x2a201c16}, + {0xd70, 0x1812362e}, {0xd74, 0x322c2220}, + {0xd78, 0x000e3c24}, {0xe00, 0x2d2d2d2d}, + {0xe04, 0x2d2d2d2d}, {0xe08, 0x0390272d}, + {0xe10, 0x2d2d2d2d}, {0xe14, 0x2d2d2d2d}, + {0xe18, 0x2d2d2d2d}, {0xe1c, 0x2d2d2d2d}, + {0xe28, 0x00000000}, {0xe30, 0x1000dc1f}, + {0xe34, 0x10008c1f}, {0xe38, 0x02140102}, + {0xe3c, 0x681604c2}, {0xe40, 0x01007c00}, + {0xe44, 0x01004800}, {0xe48, 0xfb000000}, + {0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f}, + {0xe54, 0x10008c1f}, {0xe58, 0x02140102}, + {0xe5c, 0x28160d05}, {0xe60, 0x00000008}, + {0xe68, 0x001b2556}, {0xe6c, 0x00c00096}, + {0xe70, 0x00c00096}, {0xe74, 0x01000056}, + {0xe78, 0x01000014}, {0xe7c, 0x01000056}, + {0xe80, 0x01000014}, {0xe84, 0x00c00096}, + {0xe88, 0x01000056}, {0xe8c, 0x00c00096}, + {0xed0, 0x00c00096}, {0xed4, 0x00c00096}, + {0xed8, 0x00c00096}, {0xedc, 0x000000d6}, + {0xee0, 0x000000d6}, {0xeec, 0x01c00016}, + {0xf14, 0x00000003}, {0xf4c, 0x00000000}, + {0xf00, 0x00000300}, + {0x820, 0x01000100}, {0x800, 0x83040000}, + {0xffff, 0xffffffff}, +}; + static struct rtl8xxxu_reg32val rtl8192cu_phy_2t_init_table[] = { {0x024, 0x0011800f}, {0x028, 0x00ffdb83}, {0x800, 0x80040002}, {0x804, 0x00000003}, @@ -2589,6 +2690,8 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table); else if (priv->tx_paths == 2) rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table); + else if (priv->rtlchip == 0x8723b) + rtl8xxxu_init_phy_regs(priv, rtl8723b_phy_1t_init_table); else rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table); -- cgit v1.2.3 From 22a31d455ce20737e647f8c9cc37ac9080deee96 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:15 -0500 Subject: rtl8xxxu: Add rtl8723bu_radioa_1t_init_table Add 8723bu 1T radio init table. The vendor driver indicates that some registers need special treatment for TFBGA90, TFBGA80, and TFBGA79 packaging. However the vendor driver never actually checks the package type, so just stick to default values here. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 78 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 6 +- 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index cc91247f7341..7d62440ec893 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -792,6 +792,75 @@ static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = { {0xff, 0xffffffff} }; +static struct rtl8xxxu_rfregval rtl8723bu_radioa_1t_init_table[] = { + {0x00, 0x00010000}, {0xb0, 0x000dffe0}, + {0xfe, 0x00000000}, {0xfe, 0x00000000}, + {0xfe, 0x00000000}, {0xb1, 0x00000018}, + {0xfe, 0x00000000}, {0xfe, 0x00000000}, + {0xfe, 0x00000000}, {0xb2, 0x00084c00}, + {0xb5, 0x0000d2cc}, {0xb6, 0x000925aa}, + {0xb7, 0x00000010}, {0xb8, 0x0000907f}, + {0x5c, 0x00000002}, {0x7c, 0x00000002}, + {0x7e, 0x00000005}, {0x8b, 0x0006fc00}, + {0xb0, 0x000ff9f0}, {0x1c, 0x000739d2}, + {0x1e, 0x00000000}, {0xdf, 0x00000780}, + {0x50, 0x00067435}, + /* + * The 8723bu vendor driver indicates that bit 8 should be set in + * 0x51 for package types TFBGA90, TFBGA80, and TFBGA79. However + * they never actually check the package type - and just default + * to not setting it. + */ + {0x51, 0x0006b04e}, + {0x52, 0x000007d2}, {0x53, 0x00000000}, + {0x54, 0x00050400}, {0x55, 0x0004026e}, + {0xdd, 0x0000004c}, {0x70, 0x00067435}, + /* + * 0x71 has same package type condition as for register 0x51 + */ + {0x71, 0x0006b04e}, + {0x72, 0x000007d2}, {0x73, 0x00000000}, + {0x74, 0x00050400}, {0x75, 0x0004026e}, + {0xef, 0x00000100}, {0x34, 0x0000add7}, + {0x35, 0x00005c00}, {0x34, 0x00009dd4}, + {0x35, 0x00005000}, {0x34, 0x00008dd1}, + {0x35, 0x00004400}, {0x34, 0x00007dce}, + {0x35, 0x00003800}, {0x34, 0x00006cd1}, + {0x35, 0x00004400}, {0x34, 0x00005cce}, + {0x35, 0x00003800}, {0x34, 0x000048ce}, + {0x35, 0x00004400}, {0x34, 0x000034ce}, + {0x35, 0x00003800}, {0x34, 0x00002451}, + {0x35, 0x00004400}, {0x34, 0x0000144e}, + {0x35, 0x00003800}, {0x34, 0x00000051}, + {0x35, 0x00004400}, {0xef, 0x00000000}, + {0xef, 0x00000100}, {0xed, 0x00000010}, + {0x44, 0x0000add7}, {0x44, 0x00009dd4}, + {0x44, 0x00008dd1}, {0x44, 0x00007dce}, + {0x44, 0x00006cc1}, {0x44, 0x00005cce}, + {0x44, 0x000044d1}, {0x44, 0x000034ce}, + {0x44, 0x00002451}, {0x44, 0x0000144e}, + {0x44, 0x00000051}, {0xef, 0x00000000}, + {0xed, 0x00000000}, {0x7f, 0x00020080}, + {0xef, 0x00002000}, {0x3b, 0x000380ef}, + {0x3b, 0x000302fe}, {0x3b, 0x00028ce6}, + {0x3b, 0x000200bc}, {0x3b, 0x000188a5}, + {0x3b, 0x00010fbc}, {0x3b, 0x00008f71}, + {0x3b, 0x00000900}, {0xef, 0x00000000}, + {0xed, 0x00000001}, {0x40, 0x000380ef}, + {0x40, 0x000302fe}, {0x40, 0x00028ce6}, + {0x40, 0x000200bc}, {0x40, 0x000188a5}, + {0x40, 0x00010fbc}, {0x40, 0x00008f71}, + {0x40, 0x00000900}, {0xed, 0x00000000}, + {0x82, 0x00080000}, {0x83, 0x00008000}, + {0x84, 0x00048d80}, {0x85, 0x00068000}, + {0xa2, 0x00080000}, {0xa3, 0x00008000}, + {0xa4, 0x00048d80}, {0xa5, 0x00068000}, + {0xed, 0x00000002}, {0xef, 0x00000002}, + {0x56, 0x00000032}, {0x76, 0x00000032}, + {0x01, 0x00000780}, + {0xff, 0xffffffff} +}; + static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = { {0x00, 0x00030159}, {0x01, 0x00031284}, {0x02, 0x00098000}, {0x03, 0x00018c63}, @@ -1270,6 +1339,11 @@ static u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv, return retval; } +/* + * The RTL8723BU driver indicates that registers 0xb2 and 0xb6 can + * have write issues in high temperature conditions. We may have to + * retry writing them. + */ static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv, enum rtl8xxxu_rfpath path, u8 reg, u32 data) { @@ -4562,6 +4636,10 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rftable = rtl8723au_radioa_1t_init_table; ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); break; + case 0x8723b: + rftable = rtl8723bu_radioa_1t_init_table; + ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); + break; case 0x8188c: if (priv->hi_pa) rftable = rtl8188ru_radioa_1t_highpa_table; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 205504848558..326fda5e810b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -537,8 +537,10 @@ struct rtl8723bu_efuse { u8 res9[2]; u8 vendor_name[0x07]; u8 res10[2]; - u8 device_name[0x14]; /* 0xe8 */ - u8 res11[0xd4]; + u8 device_name[0x14]; + u8 res11[0xcf]; + u8 package_type; /* 0x1fb */ + u8 res12[0x4]; }; struct rtl8192eu_efuse { -- cgit v1.2.3 From f0d9f5e90717a5e1ab014d63590d10c806ab15b0 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:16 -0500 Subject: rtl8xxxu: Add rtl8723bu_phy_init_antenna_selection() So far this is just for 8723BU. It includes writing to a number of registers I have seen no description for so far. 0x0064 0x0930 0x0944 Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 36 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 37 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 7d62440ec893..c55193bd35b4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2670,6 +2670,38 @@ static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv) } } +static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + val32 = rtl8xxxu_read32(priv, 0x64); + val32 &= ~(BIT(20) | BIT(24)); + rtl8xxxu_write32(priv, 0x64, val32); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_MUXCFG); + val32 &= ~BIT(4); + val32 |= BIT(3); + rtl8xxxu_write32(priv, REG_GPIO_MUXCFG, val32); + + val32 = rtl8xxxu_read32(priv, REG_LEDCFG0); + val32 &= ~BIT(23); + val32 |= BIT(24); + rtl8xxxu_write32(priv, REG_LEDCFG0, val32); + + val32 = rtl8xxxu_read32(priv, 0x0944); + val32 |= (BIT(0) | BIT(1)); + rtl8xxxu_write32(priv, 0x0944, val32); + + val32 = rtl8xxxu_read32(priv, 0x0930); + val32 &= 0xffffff00; + val32 |= 0x77; + rtl8xxxu_write32(priv, 0x0930, val32); + + val32 = rtl8xxxu_read32(priv, REG_PWR_DATA); + val32 |= BIT(11); + rtl8xxxu_write32(priv, REG_PWR_DATA, val32); +} + static int rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array) { @@ -4621,6 +4653,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_HIMR1, 0x00); } + if (priv->fops->phy_init_antenna_selection) + priv->fops->phy_init_antenna_selection(priv); + ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); dev_dbg(dev, "%s: init_mac %i\n", __func__, ret); if (ret) @@ -6380,6 +6415,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .load_firmware = rtl8723bu_load_firmware, .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_auto_llt_table, + .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .writeN_block_size = 1024, }; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 326fda5e810b..43300bd8b575 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -764,5 +764,6 @@ struct rtl8xxxu_fileops { int (*load_firmware) (struct rtl8xxxu_priv *priv); int (*power_on) (struct rtl8xxxu_priv *priv); int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); + void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); int writeN_block_size; }; -- cgit v1.2.3 From b7dd8ff916574f77d40914321c08b7d78f101530 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:17 -0500 Subject: rtl8xxxu: Add rtl8723b_mac_init_table Newer chips seem to have some different mac registers, requiring a different init table. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 37 +++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index c55193bd35b4..813aadb3e473 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -153,6 +153,37 @@ static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = { {0x70a, 0x65}, {0x70b, 0x87}, {0xffff, 0xff}, }; +static struct rtl8xxxu_reg8val rtl8723b_mac_init_table[] = { + {0x02f, 0x30}, {0x035, 0x00}, {0x039, 0x08}, {0x04e, 0xe0}, + {0x064, 0x00}, {0x067, 0x20}, {0x428, 0x0a}, {0x429, 0x10}, + {0x430, 0x00}, {0x431, 0x00}, + {0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05}, + {0x436, 0x07}, {0x437, 0x08}, {0x43c, 0x04}, {0x43d, 0x05}, + {0x43e, 0x07}, {0x43f, 0x08}, {0x440, 0x5d}, {0x441, 0x01}, + {0x442, 0x00}, {0x444, 0x10}, {0x445, 0x00}, {0x446, 0x00}, + {0x447, 0x00}, {0x448, 0x00}, {0x449, 0xf0}, {0x44a, 0x0f}, + {0x44b, 0x3e}, {0x44c, 0x10}, {0x44d, 0x00}, {0x44e, 0x00}, + {0x44f, 0x00}, {0x450, 0x00}, {0x451, 0xf0}, {0x452, 0x0f}, + {0x453, 0x00}, {0x456, 0x5e}, {0x460, 0x66}, {0x461, 0x66}, + {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff}, + {0x4cd, 0xff}, {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2}, + {0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3}, + {0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4}, + {0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4}, + {0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a}, + {0x516, 0x0a}, {0x525, 0x4f}, + {0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, {0x55c, 0x50}, + {0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a}, + {0x620, 0xff}, {0x621, 0xff}, {0x622, 0xff}, {0x623, 0xff}, + {0x624, 0xff}, {0x625, 0xff}, {0x626, 0xff}, {0x627, 0xff}, + {0x638, 0x50}, {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e}, + {0x63f, 0x0e}, {0x640, 0x40}, {0x642, 0x40}, {0x643, 0x00}, + {0x652, 0xc8}, {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43}, + {0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43}, + {0x70a, 0x65}, {0x70b, 0x87}, {0x765, 0x18}, {0x76e, 0x04}, + {0xffff, 0xff}, +}; + static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = { {0x800, 0x80040000}, {0x804, 0x00000003}, {0x808, 0x0000fc00}, {0x80c, 0x0000000a}, @@ -4656,7 +4687,11 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (priv->fops->phy_init_antenna_selection) priv->fops->phy_init_antenna_selection(priv); - ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); + if (priv->rtlchip == 0x8723b) + ret = rtl8xxxu_init_mac(priv, rtl8723b_mac_init_table); + else + ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); + dev_dbg(dev, "%s: init_mac %i\n", __func__, ret); if (ret) goto exit; -- cgit v1.2.3 From b9f498e11fe9ae508c716d5cb4e468cf176018f2 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:18 -0500 Subject: rtl8xxxu: Add 8723by AGC table The different RF module seems to require a different AGC table as well Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 75 +++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 813aadb3e473..89c66a2e49c1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -748,6 +748,77 @@ static struct rtl8xxxu_reg32val rtl8xxx_agc_highpa_table[] = { {0xffff, 0xffffffff} }; +static struct rtl8xxxu_reg32val rtl8xxx_agc_8723bu_table[] = { + {0xc78, 0xfd000001}, {0xc78, 0xfc010001}, + {0xc78, 0xfb020001}, {0xc78, 0xfa030001}, + {0xc78, 0xf9040001}, {0xc78, 0xf8050001}, + {0xc78, 0xf7060001}, {0xc78, 0xf6070001}, + {0xc78, 0xf5080001}, {0xc78, 0xf4090001}, + {0xc78, 0xf30a0001}, {0xc78, 0xf20b0001}, + {0xc78, 0xf10c0001}, {0xc78, 0xf00d0001}, + {0xc78, 0xef0e0001}, {0xc78, 0xee0f0001}, + {0xc78, 0xed100001}, {0xc78, 0xec110001}, + {0xc78, 0xeb120001}, {0xc78, 0xea130001}, + {0xc78, 0xe9140001}, {0xc78, 0xe8150001}, + {0xc78, 0xe7160001}, {0xc78, 0xe6170001}, + {0xc78, 0xe5180001}, {0xc78, 0xe4190001}, + {0xc78, 0xe31a0001}, {0xc78, 0xa51b0001}, + {0xc78, 0xa41c0001}, {0xc78, 0xa31d0001}, + {0xc78, 0x671e0001}, {0xc78, 0x661f0001}, + {0xc78, 0x65200001}, {0xc78, 0x64210001}, + {0xc78, 0x63220001}, {0xc78, 0x4a230001}, + {0xc78, 0x49240001}, {0xc78, 0x48250001}, + {0xc78, 0x47260001}, {0xc78, 0x46270001}, + {0xc78, 0x45280001}, {0xc78, 0x44290001}, + {0xc78, 0x432a0001}, {0xc78, 0x422b0001}, + {0xc78, 0x292c0001}, {0xc78, 0x282d0001}, + {0xc78, 0x272e0001}, {0xc78, 0x262f0001}, + {0xc78, 0x0a300001}, {0xc78, 0x09310001}, + {0xc78, 0x08320001}, {0xc78, 0x07330001}, + {0xc78, 0x06340001}, {0xc78, 0x05350001}, + {0xc78, 0x04360001}, {0xc78, 0x03370001}, + {0xc78, 0x02380001}, {0xc78, 0x01390001}, + {0xc78, 0x013a0001}, {0xc78, 0x013b0001}, + {0xc78, 0x013c0001}, {0xc78, 0x013d0001}, + {0xc78, 0x013e0001}, {0xc78, 0x013f0001}, + {0xc78, 0xfc400001}, {0xc78, 0xfb410001}, + {0xc78, 0xfa420001}, {0xc78, 0xf9430001}, + {0xc78, 0xf8440001}, {0xc78, 0xf7450001}, + {0xc78, 0xf6460001}, {0xc78, 0xf5470001}, + {0xc78, 0xf4480001}, {0xc78, 0xf3490001}, + {0xc78, 0xf24a0001}, {0xc78, 0xf14b0001}, + {0xc78, 0xf04c0001}, {0xc78, 0xef4d0001}, + {0xc78, 0xee4e0001}, {0xc78, 0xed4f0001}, + {0xc78, 0xec500001}, {0xc78, 0xeb510001}, + {0xc78, 0xea520001}, {0xc78, 0xe9530001}, + {0xc78, 0xe8540001}, {0xc78, 0xe7550001}, + {0xc78, 0xe6560001}, {0xc78, 0xe5570001}, + {0xc78, 0xe4580001}, {0xc78, 0xe3590001}, + {0xc78, 0xa65a0001}, {0xc78, 0xa55b0001}, + {0xc78, 0xa45c0001}, {0xc78, 0xa35d0001}, + {0xc78, 0x675e0001}, {0xc78, 0x665f0001}, + {0xc78, 0x65600001}, {0xc78, 0x64610001}, + {0xc78, 0x63620001}, {0xc78, 0x62630001}, + {0xc78, 0x61640001}, {0xc78, 0x48650001}, + {0xc78, 0x47660001}, {0xc78, 0x46670001}, + {0xc78, 0x45680001}, {0xc78, 0x44690001}, + {0xc78, 0x436a0001}, {0xc78, 0x426b0001}, + {0xc78, 0x286c0001}, {0xc78, 0x276d0001}, + {0xc78, 0x266e0001}, {0xc78, 0x256f0001}, + {0xc78, 0x24700001}, {0xc78, 0x09710001}, + {0xc78, 0x08720001}, {0xc78, 0x07730001}, + {0xc78, 0x06740001}, {0xc78, 0x05750001}, + {0xc78, 0x04760001}, {0xc78, 0x03770001}, + {0xc78, 0x02780001}, {0xc78, 0x01790001}, + {0xc78, 0x017a0001}, {0xc78, 0x017b0001}, + {0xc78, 0x017c0001}, {0xc78, 0x017d0001}, + {0xc78, 0x017e0001}, {0xc78, 0x017f0001}, + {0xc50, 0x69553422}, + {0xc50, 0x69553420}, + {0x824, 0x00390204}, + {0xffff, 0xffffffff} +}; + static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = { {0x00, 0x00030159}, {0x01, 0x00031284}, {0x02, 0x00098000}, {0x03, 0x00039c63}, @@ -2895,7 +2966,9 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_TX_TO_TX, val32); } - if (priv->hi_pa) + if (priv->rtlchip == 0x8723b) + rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_8723bu_table); + else if (priv->hi_pa) rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table); else rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table); -- cgit v1.2.3 From ed35d09469e55b3324ef85b33e0355bd86cdd066 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:19 -0500 Subject: rtl8xxxu: Handle 32 bit mailbox extension regs found on 8723bu/8192eu/8812 Gen1 chips use a 16 bit mailbox extension register, for upto 48 bit mailbox commands. The newer generation chips use a 32 bit mailbox extension register instead, for upto 64 bit mailbox commands. Handle writing the larger mailboxes. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 29 +++++++++++++++++++----- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 ++++++- 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 89c66a2e49c1..eb70fa270ca3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1482,7 +1482,8 @@ static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c) mbox_nr = priv->next_mbox; mbox_reg = REG_HMBOX_0 + (mbox_nr * 4); - mbox_ext_reg = REG_HMBOX_EXT_0 + (mbox_nr * 2); + mbox_ext_reg = priv->fops->mbox_ext_reg + + (mbox_nr * priv->fops->mbox_ext_width); /* * MBOX ready? @@ -1504,11 +1505,19 @@ static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c) * Need to swap as it's being swapped again by rtl8xxxu_write16/32() */ if (h2c->cmd.cmd & H2C_EXT) { - rtl8xxxu_write16(priv, mbox_ext_reg, - le16_to_cpu(h2c->raw.ext)); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C) - dev_info(dev, "H2C_EXT %04x\n", - le16_to_cpu(h2c->raw.ext)); + if (priv->fops->mbox_ext_width == 4) { + rtl8xxxu_write32(priv, mbox_ext_reg, + le32_to_cpu(h2c->raw_wide.ext)); + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C) + dev_info(dev, "H2C_EXT %08x\n", + le32_to_cpu(h2c->raw_wide.ext)); + } else { + rtl8xxxu_write16(priv, mbox_ext_reg, + le16_to_cpu(h2c->raw.ext)); + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C) + dev_info(dev, "H2C_EXT %04x\n", + le16_to_cpu(h2c->raw.ext)); + } } rtl8xxxu_write32(priv, mbox_reg, le32_to_cpu(h2c->raw.data)); if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C) @@ -6516,6 +6525,8 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_init_llt_table, .writeN_block_size = 1024, + .mbox_ext_reg = REG_HMBOX_EXT_0, + .mbox_ext_width = 2, }; static struct rtl8xxxu_fileops rtl8723bu_fops = { @@ -6525,6 +6536,8 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .llt_init = rtl8xxxu_auto_llt_table, .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .writeN_block_size = 1024, + .mbox_ext_reg = REG_HMBOX_EXT0_8723B, + .mbox_ext_width = 4, }; #ifdef CONFIG_RTL8XXXU_UNTESTED @@ -6535,6 +6548,8 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .power_on = rtl8192cu_power_on, .llt_init = rtl8xxxu_init_llt_table, .writeN_block_size = 128, + .mbox_ext_reg = REG_HMBOX_EXT_0, + .mbox_ext_width = 2, }; #endif @@ -6545,6 +6560,8 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .power_on = rtl8192eu_power_on, .llt_init = rtl8xxxu_auto_llt_table, .writeN_block_size = 128, + .mbox_ext_reg = REG_HMBOX_EXT0_8723B, + .mbox_ext_width = 4, }; static struct usb_device_id dev_table[] = { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 43300bd8b575..7aed304712e7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -628,12 +628,16 @@ struct h2c_cmd { union { struct { u8 cmd; - u8 data[5]; + u8 data[7]; } __packed cmd; struct { __le32 data; __le16 ext; } __packed raw; + struct { + __le32 data; + __le32 ext; + } __packed raw_wide; struct { u8 cmd; u8 data; @@ -766,4 +770,6 @@ struct rtl8xxxu_fileops { int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); int writeN_block_size; + u16 mbox_ext_reg; + char mbox_ext_width; }; -- cgit v1.2.3 From 14d8856082c5fdb320b108af690c79d4d560d9b2 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:20 -0500 Subject: rtl8xxxu: Add some missing register definitions for 8723bu This introduces additional register definitions for newer generation chips. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 3cbb54956e79..f1375b8904da 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -155,6 +155,8 @@ /* RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */ #define REG_GPIO_IO_SEL_2 0x0062 +/* RTL8723B */ +#define REG_PAD_CTRL1 0x0064 /* RTL8723 only WIFI/BT/GPS Multi-Function control source. */ #define REG_MULTI_FUNC_CTRL 0x0068 @@ -196,9 +198,11 @@ #define REG_HMBOX_EXT_1 0x008a #define REG_HMBOX_EXT_2 0x008c #define REG_HMBOX_EXT_3 0x008e -/* Interrupt registers for 8192e/8812 */ +/* Interrupt registers for 8192e/8723bu/8812 */ #define REG_HIMR0 0x00b0 +#define REG_HISR0 0x00b4 #define REG_HIMR1 0x00b8 +#define REG_HISR1 0x00bc /* Host suspend counter on FPGA platform */ #define REG_HOST_SUSP_CNT 0x00bc @@ -337,6 +341,8 @@ #define REG_MBIST_DONE 0x0178 #define REG_MBIST_FAIL 0x017c #define REG_C2HEVT_MSG_NORMAL 0x01a0 +/* 8192EU/8723BU/8812 */ +#define REG_C2HEVT_CMD_ID_8723B 0x01ae #define REG_C2HEVT_CLEAR 0x01af #define REG_C2HEVT_MSG_TEST 0x01b8 #define REG_MCUTST_1 0x01c0 -- cgit v1.2.3 From 6431ea00dfc5a7a3cdca1320034f20b69846a432 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:21 -0500 Subject: rtl8xxxu: Group USB fixups together for all chips In addition do not apply fixups for 8188/8191/8192 A-cut UMC parts. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 57 +++++++++++++----------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index eb70fa270ca3..be95ef349d78 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4757,11 +4757,42 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) } } - if (priv->rtlchip == 0x8192e) { + /* Fix USB interface interference issue */ + if (priv->rtlchip == 0x8723a) { + rtl8xxxu_write8(priv, 0xfe40, 0xe0); + rtl8xxxu_write8(priv, 0xfe41, 0x8d); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320); + } else { val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK); val32 |= TXDMA_OFFSET_DROP_DATA_EN; rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); + } + /* Solve too many protocol error on USB bus */ + /* Can't do this for 8188/8192 UMC A cut parts */ + if (priv->rtlchip == 0x8723a || + ((priv->rtlchip == 0x8192c || priv->rtlchip == 0x8191c || + priv->rtlchip == 0x8188c) && + (priv->chip_cut || !priv->vendor_umc))) { + rtl8xxxu_write8(priv, 0xfe40, 0xe6); + rtl8xxxu_write8(priv, 0xfe41, 0x94); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + rtl8xxxu_write8(priv, 0xfe40, 0xe0); + rtl8xxxu_write8(priv, 0xfe41, 0x19); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + rtl8xxxu_write8(priv, 0xfe40, 0xe5); + rtl8xxxu_write8(priv, 0xfe41, 0x91); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + rtl8xxxu_write8(priv, 0xfe40, 0xe2); + rtl8xxxu_write8(priv, 0xfe41, 0x81); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + } + + if (priv->rtlchip == 0x8192e || priv->rtlchip == 0x8723b) { rtl8xxxu_write32(priv, REG_HIMR0, 0x00); rtl8xxxu_write32(priv, REG_HIMR1, 0x00); } @@ -4968,30 +4999,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8723a_phy_lc_calibrate(priv); - /* fix USB interface interference issue */ - rtl8xxxu_write8(priv, 0xfe40, 0xe0); - rtl8xxxu_write8(priv, 0xfe41, 0x8d); - rtl8xxxu_write8(priv, 0xfe42, 0x80); - rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320); - - /* Solve too many protocol error on USB bus */ - /* Can't do this for 8188/8192 UMC A cut parts */ - rtl8xxxu_write8(priv, 0xfe40, 0xe6); - rtl8xxxu_write8(priv, 0xfe41, 0x94); - rtl8xxxu_write8(priv, 0xfe42, 0x80); - - rtl8xxxu_write8(priv, 0xfe40, 0xe0); - rtl8xxxu_write8(priv, 0xfe41, 0x19); - rtl8xxxu_write8(priv, 0xfe42, 0x80); - - rtl8xxxu_write8(priv, 0xfe40, 0xe5); - rtl8xxxu_write8(priv, 0xfe41, 0x91); - rtl8xxxu_write8(priv, 0xfe42, 0x80); - - rtl8xxxu_write8(priv, 0xfe40, 0xe2); - rtl8xxxu_write8(priv, 0xfe41, 0x81); - rtl8xxxu_write8(priv, 0xfe42, 0x80); - /* Init BT hw config. */ rtl8xxxu_init_bt(priv); -- cgit v1.2.3 From d940c247adbd44c885777099e3e6c64b7ca2d078 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:22 -0500 Subject: rtl8xxxu: Add definitions for new generation h2c commands The larger mailboxes also use a different set of mailbox commands. This provides a list of the 64 bit commands. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 87 ++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 7aed304712e7..198b1d874551 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -617,12 +617,91 @@ struct rtl8xxxu_rfregs { #define H2C_MAX_MBOX 4 #define H2C_EXT BIT(7) -#define H2C_SET_POWER_MODE 1 -#define H2C_JOIN_BSS_REPORT 2 #define H2C_JOIN_BSS_DISCONNECT 0 #define H2C_JOIN_BSS_CONNECT 1 -#define H2C_SET_RSSI 5 -#define H2C_SET_RATE_MASK (6 | H2C_EXT) + +/* + * H2C (firmware) commands differ between the older generation chips + * 8188[cr]u, 819[12]cu, and 8723au, and the more recent chips 8723bu, + * 8192[de]u, 8192eu, and 8812. + */ +enum h2c_cmd_8723a { + H2C_SET_POWER_MODE = 1, + H2C_JOIN_BSS_REPORT = 2, + H2C_SET_RSSI = 5, + H2C_SET_RATE_MASK = (6 | H2C_EXT), +}; + +enum h2c_cmd_8723b { + /* + * Common Class: 000 + */ + H2C_8723B_RSVD_PAGE = 0x00, + H2C_8723B_MEDIA_STATUS_RPT = 0x01, + H2C_8723B_SCAN_ENABLE = 0x02, + H2C_8723B_KEEP_ALIVE = 0x03, + H2C_8723B_DISCON_DECISION = 0x04, + H2C_8723B_PSD_OFFLOAD = 0x05, + H2C_8723B_AP_OFFLOAD = 0x08, + H2C_8723B_BCN_RSVDPAGE = 0x09, + H2C_8723B_PROBERSP_RSVDPAGE = 0x0A, + H2C_8723B_FCS_RSVDPAGE = 0x10, + H2C_8723B_FCS_INFO = 0x11, + H2C_8723B_AP_WOW_GPIO_CTRL = 0x13, + + /* + * PoweSave Class: 001 + */ + H2C_8723B_SET_PWR_MODE = 0x20, + H2C_8723B_PS_TUNING_PARA = 0x21, + H2C_8723B_PS_TUNING_PARA2 = 0x22, + H2C_8723B_P2P_LPS_PARAM = 0x23, + H2C_8723B_P2P_PS_OFFLOAD = 0x24, + H2C_8723B_PS_SCAN_ENABLE = 0x25, + H2C_8723B_SAP_PS_ = 0x26, + H2C_8723B_INACTIVE_PS_ = 0x27, + H2C_8723B_FWLPS_IN_IPS_ = 0x28, + + /* + * Dynamic Mechanism Class: 010 + */ + H2C_8723B_MACID_CFG = 0x40, + H2C_8723B_TXBF = 0x41, + H2C_8723B_RSSI_SETTING = 0x42, + H2C_8723B_AP_REQ_TXRPT = 0x43, + H2C_8723B_INIT_RATE_COLLECT = 0x44, + + /* + * BT Class: 011 + */ + H2C_8723B_B_TYPE_TDMA = 0x60, + H2C_8723B_BT_INFO = 0x61, + H2C_8723B_FORCE_BT_TXPWR = 0x62, + H2C_8723B_BT_IGNORE_WLANACT = 0x63, + H2C_8723B_DAC_SWING_VALUE = 0x64, + H2C_8723B_ANT_SEL_RSV = 0x65, + H2C_8723B_WL_OPMODE = 0x66, + H2C_8723B_BT_MP_OPER = 0x67, + H2C_8723B_BT_CONTROL = 0x68, + H2C_8723B_BT_WIFI_CTRL = 0x69, + H2C_8723B_BT_FW_PATCH = 0x6A, + H2C_8723B_BT_WLAN_CALIBRATION = 0x6D, + + /* + * WOWLAN Class: 100 + */ + H2C_8723B_WOWLAN = 0x80, + H2C_8723B_REMOTE_WAKE_CTRL = 0x81, + H2C_8723B_AOAC_GLOBAL_INFO = 0x82, + H2C_8723B_AOAC_RSVD_PAGE = 0x83, + H2C_8723B_AOAC_RSVD_PAGE2 = 0x84, + H2C_8723B_D0_SCAN_OFFLOAD_CTRL = 0x85, + H2C_8723B_D0_SCAN_OFFLOAD_INFO = 0x86, + H2C_8723B_CHNL_SWITCH_OFFLOAD = 0x87, + + H2C_8723B_RESET_TSF = 0xC0, +}; + struct h2c_cmd { union { -- cgit v1.2.3 From f6c47702ede3edc1dbf73355c134d7e33d9c86ca Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Mon, 29 Feb 2016 17:04:23 -0500 Subject: rtl8xxxu: Don't check for illegal offset when reading from efuse It is enough to check for either illegal offset or illegal map address because map address is a value derived from an offset: map_addr = offset * 8 EFUSE_MAP_LEN = EFUSE_MAX_SECTION_8723A * 8 Leave just the check for an illegal map address because its upper bound (EFUSE_MAP_LEN) is used also in a couple other places. Signed-off-by: Jakub Sitnicki Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 63 +++++++++++------------- 1 file changed, 28 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index be95ef349d78..c279d6d04eb4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2417,6 +2417,8 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) efuse_addr = 0; while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) { + u16 map_addr; + ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &header); if (ret || header == 0xff) goto exit; @@ -2439,45 +2441,36 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) word_mask = header & 0x0f; } - if (offset < EFUSE_MAX_SECTION_8723A) { - u16 map_addr; - /* Get word enable value from PG header */ + /* Get word enable value from PG header */ - /* We have 8 bits to indicate validity */ - map_addr = offset * 8; - if (map_addr >= EFUSE_MAP_LEN) { - dev_warn(dev, "%s: Illegal map_addr (%04x), " - "efuse corrupt!\n", - __func__, map_addr); - ret = -EINVAL; - goto exit; - } - for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { - /* Check word enable condition in the section */ - if (!(word_mask & BIT(i))) { - ret = rtl8xxxu_read_efuse8(priv, - efuse_addr++, - &val8); - if (ret) - goto exit; - priv->efuse_wifi.raw[map_addr++] = val8; - - ret = rtl8xxxu_read_efuse8(priv, - efuse_addr++, - &val8); - if (ret) - goto exit; - priv->efuse_wifi.raw[map_addr++] = val8; - } else - map_addr += 2; - } - } else { - dev_warn(dev, - "%s: Illegal offset (%04x), efuse corrupt!\n", - __func__, offset); + /* We have 8 bits to indicate validity */ + map_addr = offset * 8; + if (map_addr >= EFUSE_MAP_LEN) { + dev_warn(dev, "%s: Illegal map_addr (%04x), " + "efuse corrupt!\n", + __func__, map_addr); ret = -EINVAL; goto exit; } + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + /* Check word enable condition in the section */ + if (!(word_mask & BIT(i))) { + ret = rtl8xxxu_read_efuse8(priv, + efuse_addr++, + &val8); + if (ret) + goto exit; + priv->efuse_wifi.raw[map_addr++] = val8; + + ret = rtl8xxxu_read_efuse8(priv, + efuse_addr++, + &val8); + if (ret) + goto exit; + priv->efuse_wifi.raw[map_addr++] = val8; + } else + map_addr += 2; + } } exit: -- cgit v1.2.3 From 32a39dd4b574abd32304857e8a5b24de113b81ee Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Mon, 29 Feb 2016 17:04:24 -0500 Subject: rtl8xxxu: Skip disabled efuse words early Avoid a negative conditional and an extra level of indentation in the bigger part of the loop body. Signed-off-by: Jakub Sitnicki Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 28 +++++++++++------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index c279d6d04eb4..7a1c094f1f88 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2454,22 +2454,20 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) } for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ - if (!(word_mask & BIT(i))) { - ret = rtl8xxxu_read_efuse8(priv, - efuse_addr++, - &val8); - if (ret) - goto exit; - priv->efuse_wifi.raw[map_addr++] = val8; - - ret = rtl8xxxu_read_efuse8(priv, - efuse_addr++, - &val8); - if (ret) - goto exit; - priv->efuse_wifi.raw[map_addr++] = val8; - } else + if (word_mask & BIT(i)) { map_addr += 2; + continue; + } + + ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &val8); + if (ret) + goto exit; + priv->efuse_wifi.raw[map_addr++] = val8; + + ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &val8); + if (ret) + goto exit; + priv->efuse_wifi.raw[map_addr++] = val8; } } -- cgit v1.2.3 From d38f1c3715d6de00d3b7a09254f9a0930d611bed Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Mon, 29 Feb 2016 17:04:25 -0500 Subject: rtl8xxxu: rtl8723au: Introduce a pointer to efuse Signed-off-by: Jakub Sitnicki Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 7a1c094f1f88..172d76c0dcb5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2127,43 +2127,45 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) { - if (priv->efuse_wifi.efuse8723.rtl_id != cpu_to_le16(0x8129)) + struct rtl8723au_efuse *efuse = &priv->efuse_wifi.efuse8723; + + if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; - ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723.mac_addr); + ether_addr_copy(priv->mac_addr, efuse->mac_addr); memcpy(priv->cck_tx_power_index_A, - priv->efuse_wifi.efuse8723.cck_tx_power_index_A, + efuse->cck_tx_power_index_A, sizeof(priv->cck_tx_power_index_A)); memcpy(priv->cck_tx_power_index_B, - priv->efuse_wifi.efuse8723.cck_tx_power_index_B, + efuse->cck_tx_power_index_B, sizeof(priv->cck_tx_power_index_B)); memcpy(priv->ht40_1s_tx_power_index_A, - priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_A, + efuse->ht40_1s_tx_power_index_A, sizeof(priv->ht40_1s_tx_power_index_A)); memcpy(priv->ht40_1s_tx_power_index_B, - priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_B, + efuse->ht40_1s_tx_power_index_B, sizeof(priv->ht40_1s_tx_power_index_B)); memcpy(priv->ht20_tx_power_index_diff, - priv->efuse_wifi.efuse8723.ht20_tx_power_index_diff, + efuse->ht20_tx_power_index_diff, sizeof(priv->ht20_tx_power_index_diff)); memcpy(priv->ofdm_tx_power_index_diff, - priv->efuse_wifi.efuse8723.ofdm_tx_power_index_diff, + efuse->ofdm_tx_power_index_diff, sizeof(priv->ofdm_tx_power_index_diff)); memcpy(priv->ht40_max_power_offset, - priv->efuse_wifi.efuse8723.ht40_max_power_offset, + efuse->ht40_max_power_offset, sizeof(priv->ht40_max_power_offset)); memcpy(priv->ht20_max_power_offset, - priv->efuse_wifi.efuse8723.ht20_max_power_offset, + efuse->ht20_max_power_offset, sizeof(priv->ht20_max_power_offset)); dev_info(&priv->udev->dev, "Vendor: %.7s\n", - priv->efuse_wifi.efuse8723.vendor_name); + efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.41s\n", - priv->efuse_wifi.efuse8723.device_name); + efuse->device_name); return 0; } -- cgit v1.2.3 From 4959444165523e68118035bebb727b9431746765 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Mon, 29 Feb 2016 17:04:26 -0500 Subject: rtl8xxxu: rtl8192cu: Introduce a pointer to efuse Signed-off-by: Jakub Sitnicki Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 29 ++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 172d76c0dcb5..fcae9f020f5c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2218,50 +2218,51 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) { + struct rtl8192cu_efuse *efuse = &priv->efuse_wifi.efuse8192; int i; - if (priv->efuse_wifi.efuse8192.rtl_id != cpu_to_le16(0x8129)) + if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; - ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192.mac_addr); + ether_addr_copy(priv->mac_addr, efuse->mac_addr); memcpy(priv->cck_tx_power_index_A, - priv->efuse_wifi.efuse8192.cck_tx_power_index_A, + efuse->cck_tx_power_index_A, sizeof(priv->cck_tx_power_index_A)); memcpy(priv->cck_tx_power_index_B, - priv->efuse_wifi.efuse8192.cck_tx_power_index_B, + efuse->cck_tx_power_index_B, sizeof(priv->cck_tx_power_index_B)); memcpy(priv->ht40_1s_tx_power_index_A, - priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_A, + efuse->ht40_1s_tx_power_index_A, sizeof(priv->ht40_1s_tx_power_index_A)); memcpy(priv->ht40_1s_tx_power_index_B, - priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_B, + efuse->ht40_1s_tx_power_index_B, sizeof(priv->ht40_1s_tx_power_index_B)); memcpy(priv->ht40_2s_tx_power_index_diff, - priv->efuse_wifi.efuse8192.ht40_2s_tx_power_index_diff, + efuse->ht40_2s_tx_power_index_diff, sizeof(priv->ht40_2s_tx_power_index_diff)); memcpy(priv->ht20_tx_power_index_diff, - priv->efuse_wifi.efuse8192.ht20_tx_power_index_diff, + efuse->ht20_tx_power_index_diff, sizeof(priv->ht20_tx_power_index_diff)); memcpy(priv->ofdm_tx_power_index_diff, - priv->efuse_wifi.efuse8192.ofdm_tx_power_index_diff, + efuse->ofdm_tx_power_index_diff, sizeof(priv->ofdm_tx_power_index_diff)); memcpy(priv->ht40_max_power_offset, - priv->efuse_wifi.efuse8192.ht40_max_power_offset, + efuse->ht40_max_power_offset, sizeof(priv->ht40_max_power_offset)); memcpy(priv->ht20_max_power_offset, - priv->efuse_wifi.efuse8192.ht20_max_power_offset, + efuse->ht20_max_power_offset, sizeof(priv->ht20_max_power_offset)); dev_info(&priv->udev->dev, "Vendor: %.7s\n", - priv->efuse_wifi.efuse8192.vendor_name); + efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.20s\n", - priv->efuse_wifi.efuse8192.device_name); + efuse->device_name); - if (priv->efuse_wifi.efuse8192.rf_regulatory & 0x20) { + if (efuse->rf_regulatory & 0x20) { sprintf(priv->chip_name, "8188RU"); priv->hi_pa = 1; } -- cgit v1.2.3 From b7dda34d1ecda7e3243137a6ffcb7e9173e5d651 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:27 -0500 Subject: rtl8xxxu: rtl8192eu_parse_efuse(): Use a pointer to the struct rtl8192eu_efuse Make the code easier to read and less error prone by using a pointer to the efuse. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 26 +++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index fcae9f020f5c..a8f1eae60815 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2288,33 +2288,27 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) { + struct rtl8192eu_efuse *efuse = &priv->efuse_wifi.efuse8192eu; int i; - if (priv->efuse_wifi.efuse8192eu.rtl_id != cpu_to_le16(0x8129)) + if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; - ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192eu.mac_addr); + ether_addr_copy(priv->mac_addr, efuse->mac_addr); - memcpy(priv->cck_tx_power_index_A, - priv->efuse_wifi.efuse8192eu.cck_tx_power_index_A, + memcpy(priv->cck_tx_power_index_A, efuse->cck_tx_power_index_A, sizeof(priv->cck_tx_power_index_A)); - memcpy(priv->cck_tx_power_index_B, - priv->efuse_wifi.efuse8192eu.cck_tx_power_index_B, + memcpy(priv->cck_tx_power_index_B, efuse->cck_tx_power_index_B, sizeof(priv->cck_tx_power_index_B)); - memcpy(priv->ht40_1s_tx_power_index_A, - priv->efuse_wifi.efuse8192eu.ht40_1s_tx_power_index_A, + memcpy(priv->ht40_1s_tx_power_index_A, efuse->ht40_1s_tx_power_index_A, sizeof(priv->ht40_1s_tx_power_index_A)); - memcpy(priv->ht40_1s_tx_power_index_B, - priv->efuse_wifi.efuse8192eu.ht40_1s_tx_power_index_B, + memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, sizeof(priv->ht40_1s_tx_power_index_B)); - dev_info(&priv->udev->dev, "Vendor: %.7s\n", - priv->efuse_wifi.efuse8192eu.vendor_name); - dev_info(&priv->udev->dev, "Product: %.11s\n", - priv->efuse_wifi.efuse8192eu.device_name); - dev_info(&priv->udev->dev, "Serial: %.11s\n", - priv->efuse_wifi.efuse8192eu.serial); + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); + dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); + dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { unsigned char *raw = priv->efuse_wifi.raw; -- cgit v1.2.3 From b8ba8602b81a019c67bc1f34b6b68e8965086532 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:28 -0500 Subject: rtl8xxxu: rtl8723bu_parse_efuse(): Use a pointer to the struct rtl8723bu_efuse Likewise for 8723bu, use a pointer to the efuse. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index a8f1eae60815..43bbbf00e1ac 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2171,29 +2171,25 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) { - if (priv->efuse_wifi.efuse8723bu.rtl_id != cpu_to_le16(0x8129)) + struct rtl8723bu_efuse *efuse = &priv->efuse_wifi.efuse8723bu; + + if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; - ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723bu.mac_addr); + ether_addr_copy(priv->mac_addr, efuse->mac_addr); - memcpy(priv->cck_tx_power_index_A, - priv->efuse_wifi.efuse8723bu.cck_tx_power_index_A, + memcpy(priv->cck_tx_power_index_A, efuse->cck_tx_power_index_A, sizeof(priv->cck_tx_power_index_A)); - memcpy(priv->cck_tx_power_index_B, - priv->efuse_wifi.efuse8723bu.cck_tx_power_index_B, + memcpy(priv->cck_tx_power_index_B, efuse->cck_tx_power_index_B, sizeof(priv->cck_tx_power_index_B)); - memcpy(priv->ht40_1s_tx_power_index_A, - priv->efuse_wifi.efuse8723bu.ht40_1s_tx_power_index_A, + memcpy(priv->ht40_1s_tx_power_index_A, efuse->ht40_1s_tx_power_index_A, sizeof(priv->ht40_1s_tx_power_index_A)); - memcpy(priv->ht40_1s_tx_power_index_B, - priv->efuse_wifi.efuse8723bu.ht40_1s_tx_power_index_B, + memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, sizeof(priv->ht40_1s_tx_power_index_B)); - dev_info(&priv->udev->dev, "Vendor: %.7s\n", - priv->efuse_wifi.efuse8723bu.vendor_name); - dev_info(&priv->udev->dev, "Product: %.41s\n", - priv->efuse_wifi.efuse8723bu.device_name); + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); + dev_info(&priv->udev->dev, "Product: %.41s\n", efuse->device_name); if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { int i; -- cgit v1.2.3 From 8da91571bb401a3b9ffa36d7c6ca9c2476777e4d Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:29 -0500 Subject: rtl8xxxu: rtl8xxxu_h2c_cmd(): Add size argument The firmware command API differs slightly between new and old devices. The new generation requires the size since there is no extension bit encoded into the command number. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 13 +++++++------ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 43bbbf00e1ac..b42d71b39c50 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1471,7 +1471,8 @@ static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv, return retval; } -static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c) +static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, + struct h2c_cmd *h2c, int len) { struct device *dev = &priv->udev->dev; int mbox_nr, retry, retval = 0; @@ -1504,7 +1505,7 @@ static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c) /* * Need to swap as it's being swapped again by rtl8xxxu_write16/32() */ - if (h2c->cmd.cmd & H2C_EXT) { + if (len > sizeof(u32)) { if (priv->fops->mbox_ext_width == 4) { rtl8xxxu_write32(priv, mbox_ext_reg, le32_to_cpu(h2c->raw_wide.ext)); @@ -5110,9 +5111,9 @@ static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, if (sgi) h2c.ramask.arg |= 0x20; - dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x\n", __func__, - ramask, h2c.ramask.arg); - rtl8723a_h2c_cmd(priv, &h2c); + dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x, size %li\n", + __func__, ramask, h2c.ramask.arg, sizeof(h2c.ramask)); + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ramask)); } static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) @@ -5200,7 +5201,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT; } h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT; - rtl8723a_h2c_cmd(priv, &h2c); + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.joinbss)); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 198b1d874551..47898ff49ffc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -720,7 +720,6 @@ struct h2c_cmd { struct { u8 cmd; u8 data; - u8 pad[4]; } __packed joinbss; struct { u8 cmd; -- cgit v1.2.3 From c7a5a190df232b833b7867ef1679dff561b73c84 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:30 -0500 Subject: rtl8xxxu: Do BT_WLAN_CALIBRATION before doing IQK calibration Newer generation chips require the firmware be notified before we start the IQK calibration. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 20 +++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index b42d71b39c50..e0653b217883 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1497,7 +1497,7 @@ static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, } while (retry--); if (!retry) { - dev_dbg(dev, "%s: Mailbox busy\n", __func__); + dev_info(dev, "%s: Mailbox busy\n", __func__); retval = -EBUSY; goto error; } @@ -3877,6 +3877,20 @@ static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, } } +static void rtl8xxxu_prepare_calibrate(struct rtl8xxxu_priv *priv, u8 start) +{ + struct h2c_cmd h2c; + + if (priv->fops->mbox_ext_width < 4) + return; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.bt_wlan_calibration.cmd = H2C_8723B_BT_WLAN_CALIBRATION; + h2c.bt_wlan_calibration.data = start; + + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_wlan_calibration)); +} + static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv) { struct device *dev = &priv->udev->dev; @@ -3888,6 +3902,8 @@ static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv) s32 reg_tmp = 0; bool simu; + rtl8xxxu_prepare_calibrate(priv, 1); + memset(result, 0, sizeof(result)); candidate = -1; @@ -3975,6 +3991,8 @@ static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv) rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg, priv->bb_recovery_backup, RTL8XXXU_BB_REGS); + + rtl8xxxu_prepare_calibrate(priv, 0); } static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 47898ff49ffc..07533acaa9c6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -727,6 +727,10 @@ struct h2c_cmd { u8 arg; __le16 mask_lo; } __packed ramask; + struct { + u8 cmd; + u8 data; + } __packed bt_wlan_calibration; }; }; -- cgit v1.2.3 From eaa4d14c97c1990327fd4e9fc49beca0ce7baa14 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:31 -0500 Subject: rtl8xxxu: Do not overwrite rtl8xxxu_debug for untested chips Fix a silly bug where the debug level was overwritten rather than amended for untested chips. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e0653b217883..cfea68b7eb4d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6391,7 +6391,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, } if (untested) { - rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE; + rtl8xxxu_debug |= RTL8XXXU_DEBUG_EFUSE; dev_info(&udev->dev, "This Realtek USB WiFi dongle (0x%04x:0x%04x) is untested!\n", id->idVendor, id->idProduct); -- cgit v1.2.3 From 7ff8c1ae610159fcb6e7188224520cf0f8b7a336 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:32 -0500 Subject: rtl8xxxu: Use correct formatting type to print sizeof() Usual gcc i386 issue reported by kbuildbot Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index cfea68b7eb4d..171e0388d5ec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5129,7 +5129,7 @@ static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, if (sgi) h2c.ramask.arg |= 0x20; - dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x, size %li\n", + dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x, size %zi\n", __func__, ramask, h2c.ramask.arg, sizeof(h2c.ramask)); rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ramask)); } -- cgit v1.2.3 From 8634af5e6a8dea0f7110f32c00ceffee71be8a80 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:33 -0500 Subject: rtl8xxxu: Make rtl8xxxu_add_path_on() use device specific init values rtl8192cu/rtl8188cu/rtl8723au use the same values, but 8723bu and 8192eu have their own. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 24 +++++++++++++++++++++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++++ 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 171e0388d5ec..a16dabfa713e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -3557,11 +3557,13 @@ static void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs, u32 path_on; int i; - path_on = path_a_on ? 0x04db25a4 : 0x0b1b25a4; if (priv->tx_paths == 1) { - path_on = 0x0bdb25a0; - rtl8xxxu_write32(priv, regs[0], 0x0b1b25a0); + path_on = priv->fops->adda_1t_path_on; + rtl8xxxu_write32(priv, regs[0], priv->fops->adda_1t_init); } else { + path_on = path_a_on ? priv->fops->adda_2t_path_on_a : + priv->fops->adda_2t_path_on_b; + rtl8xxxu_write32(priv, regs[0], path_on); } @@ -6537,6 +6539,10 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, + .adda_1t_init = 0x0b1b25a0, + .adda_1t_path_on = 0x0bdb25a0, + .adda_2t_path_on_a = 0x04db25a4, + .adda_2t_path_on_b = 0x0b1b25a4, }; static struct rtl8xxxu_fileops rtl8723bu_fops = { @@ -6548,6 +6554,10 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, + .adda_1t_init = 0x01c00014, + .adda_1t_path_on = 0x01c00014, + .adda_2t_path_on_a = 0x01c00014, + .adda_2t_path_on_b = 0x01c00014, }; #ifdef CONFIG_RTL8XXXU_UNTESTED @@ -6560,6 +6570,10 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, + .adda_1t_init = 0x0b1b25a0, + .adda_1t_path_on = 0x0bdb25a0, + .adda_2t_path_on_a = 0x04db25a4, + .adda_2t_path_on_b = 0x0b1b25a4, }; #endif @@ -6572,6 +6586,10 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, + .adda_1t_init = 0x0fc01616, + .adda_1t_path_on = 0x0fc01616, + .adda_2t_path_on_a = 0x0fc01616, + .adda_2t_path_on_b = 0x0fc01616, }; static struct usb_device_id dev_table[] = { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 07533acaa9c6..4b8431db38d2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -854,4 +854,8 @@ struct rtl8xxxu_fileops { int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; + u32 adda_1t_init; + u32 adda_1t_path_on; + u32 adda_2t_path_on_a; + u32 adda_2t_path_on_b; }; -- cgit v1.2.3 From c6594ffd46a4b26d2a2d59c54da399ec563b6b2f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:34 -0500 Subject: rtl8xxxu: Add a couple of new register definitions This adds some additional register definitions for 8723bu, as well as a bit define for USB RXDMA aggregation in REG_RXDMA_AGG_PG_TH. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index f1375b8904da..162a9e8e4cef 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -388,9 +388,14 @@ /* 0x0280 ~ 0x02FF RXDMA Configuration */ #define REG_RXDMA_AGG_PG_TH 0x0280 +#define RXDMA_USB_AGG_ENABLE BIT(31) #define REG_RXPKT_NUM 0x0284 #define REG_RXDMA_STATUS 0x0288 +/* Presumably only found on newer chips such as 8723bu */ +#define REG_RX_DMA_CTRL_8723B 0x0286 +#define REG_RX_DMA_MODE_CTRL_8723B 0x0290 + #define REG_RF_BB_CMD_ADDR 0x02c0 #define REG_RF_BB_CMD_DATA 0x02c4 @@ -473,6 +478,7 @@ #define REG_POWER_STATUS 0x04a4 #define REG_POWER_STAGE1 0x04b4 #define REG_POWER_STAGE2 0x04b8 +#define REG_AMPDU_BURST_MODE_8723B 0x04bc #define REG_PKT_VO_VI_LIFE_TIME 0x04c0 #define REG_PKT_BE_BK_LIFE_TIME 0x04c2 #define REG_STBC_SETTING 0x04c4 -- cgit v1.2.3 From e1547c535ede26c84b72d51e031dd57551037bec Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:35 -0500 Subject: rtl8xxxu: First stab at adding IQK calibration for 8723bu parts The 8723bu also has it's own IQK calibration process. This is similar in flow, but still different enough to warrent it's own implementation, at least for now. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 811 ++++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 17 + 3 files changed, 827 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index a16dabfa713e..a40ef21016e2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -3510,6 +3510,91 @@ static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, return false; } +static bool rtl8723bu_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2) +{ + u32 i, j, diff, simubitmap, bound = 0; + int candidate[2] = {-1, -1}; /* for path A and path B */ + int tmp1, tmp2; + bool retval = true; + + if (priv->tx_paths > 1) + bound = 8; + else + bound = 4; + + simubitmap = 0; + + for (i = 0; i < bound; i++) { + if (i & 1) { + if ((result[c1][i] & 0x00000200)) + tmp1 = result[c1][i] | 0xfffffc00; + else + tmp1 = result[c1][i]; + + if ((result[c2][i]& 0x00000200)) + tmp2 = result[c2][i] | 0xfffffc00; + else + tmp2 = result[c2][i]; + } else { + tmp1 = result[c1][i]; + tmp2 = result[c2][i]; + } + + diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1); + + if (diff > MAX_TOLERANCE) { + if ((i == 2 || i == 6) && !simubitmap) { + if (result[c1][i] + result[c1][i + 1] == 0) + candidate[(i / 4)] = c2; + else if (result[c2][i] + result[c2][i + 1] == 0) + candidate[(i / 4)] = c1; + else + simubitmap = simubitmap | (1 << i); + } else { + simubitmap = simubitmap | (1 << i); + } + } + } + + if (simubitmap == 0) { + for (i = 0; i < (bound / 4); i++) { + if (candidate[i] >= 0) { + for (j = i * 4; j < (i + 1) * 4 - 2; j++) + result[3][j] = result[candidate[i]][j]; + retval = false; + } + } + return retval; + } else { + if (!(simubitmap & 0x03)) { + /* path A TX OK */ + for (i = 0; i < 2; i++) + result[3][i] = result[c1][i]; + } + + if (!(simubitmap & 0x0c)) { + /* path A RX OK */ + for (i = 2; i < 4; i++) + result[3][i] = result[c1][i]; + } + + if (!(simubitmap & 0x30) && priv->tx_paths > 1) { + /* path B RX OK */ + for (i = 4; i < 6; i++) + result[3][i] = result[c1][i]; + } + + if (!(simubitmap & 0x30) && priv->tx_paths > 1) { + /* path B RX OK */ + for (i = 6; i < 8; i++) + result[3][i] = result[c1][i]; + } + } + + return false; +} + static void rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv, const u32 *reg, u32 *backup) { @@ -3677,6 +3762,369 @@ out: return result; } +static int rtl8723bu_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_e94, reg_e9c, path_sel, val32; + int result = 0; + + path_sel = rtl8xxxu_read32(priv, REG_S0S1_PATH_SWITCH); + + /* + * Leave IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* + * Enable path A PA in TX IQK mode + */ + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT); + val32 |= 0x80000; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x20000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0003f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xc7f87); + + /* + * Tx IQK setting + */ + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x18008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x821403ea); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28110000); + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82110000); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28110000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00462911); + + /* + * Enter IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + val32 |= 0x80800000; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* + * The vendor driver indicates the USB module is always using + * S0S1 path 1 for the 8723bu. This may be different for 8192eu + */ + if (priv->rf_paths > 1) + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00000000); + else + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00000280); + + /* + * Bit 12 seems to be BT_GRANT, and is only found in the 8723bu. + * No trace of this in the 8192eu or 8188eu vendor drivers. + */ + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, 0x00000800); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(1); + + /* Restore Ant Path */ + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, path_sel); +#ifdef RTL8723BU_BT + /* GNT_BT = 1 */ + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, 0x00001800); +#endif + + /* + * Leave IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + val32 = (reg_e9c >> 16) & 0x3ff; + if (val32 & 0x200) + val32 = 0x400 - val32; + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000) && + ((reg_e94 & 0x03ff0000) < 0x01100000) && + ((reg_e94 & 0x03ff0000) > 0x00f00000) && + val32 < 0xf) + result |= 0x01; + else /* If TX not OK, ignore RX */ + goto out; + +out: + return result; +} + +static int rtl8723bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_ea4, reg_eac, reg_e94, reg_e9c, path_sel, val32; + int result = 0; + + path_sel = rtl8xxxu_read32(priv, REG_S0S1_PATH_SWITCH); + + /* + * Leave IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* + * Enable path A PA in TX IQK mode + */ + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT); + val32 |= 0x80000; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0001f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7fb7); + + /* + * Tx IQK setting + */ + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x18008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160ff0); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28110000); + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82110000); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28110000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); + + /* + * Enter IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + val32 |= 0x80800000; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* + * The vendor driver indicates the USB module is always using + * S0S1 path 1 for the 8723bu. This may be different for 8192eu + */ + if (priv->rf_paths > 1) + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00000000); + else + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00000280); + + /* + * Bit 12 seems to be BT_GRANT, and is only found in the 8723bu. + * No trace of this in the 8192eu or 8188eu vendor drivers. + */ + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, 0x00000800); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(1); + + /* Restore Ant Path */ + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, path_sel); +#ifdef RTL8723BU_BT + /* GNT_BT = 1 */ + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, 0x00001800); +#endif + + /* + * Leave IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + val32 = (reg_e9c >> 16) & 0x3ff; + if (val32 & 0x200) + val32 = 0x400 - val32; + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000) && + ((reg_e94 & 0x03ff0000) < 0x01100000) && + ((reg_e94 & 0x03ff0000) > 0x00f00000) && + val32 < 0xf) + result |= 0x01; + else /* If TX not OK, ignore RX */ + goto out; + + val32 = 0x80007c00 | (reg_e94 &0x3ff0000) | + ((reg_e9c & 0x3ff0000) >> 16); + rtl8xxxu_write32(priv, REG_TX_IQK, val32); + + /* + * Modify RX IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT); + val32 |= 0x80000; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0001f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7d77); + + /* + * PA, PAD setting + */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0xf80); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_55, 0x4021f); + + /* + * RX IQK setting + */ + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x18008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82110000); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x2816001f); + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82110000); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28110000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a8d1); + + /* + * Enter IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + val32 |= 0x80800000; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + if (priv->rf_paths > 1) + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00000000); + else + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00000280); + + /* + * Disable BT + */ + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, 0x00000800); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(1); + + /* Restore Ant Path */ + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, path_sel); +#ifdef RTL8723BU_BT + /* GNT_BT = 1 */ + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, 0x00001800); +#endif + + /* + * Leave IQK mode + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x780); + + val32 = (reg_eac >> 16) & 0x3ff; + if (val32 & 0x200) + val32 = 0x400 - val32; + + if (!(reg_eac & BIT(27)) && + ((reg_ea4 & 0x03ff0000) != 0x01320000) && + ((reg_eac & 0x03ff0000) != 0x00360000) && + ((reg_ea4 & 0x03ff0000) < 0x01100000) && + ((reg_ea4 & 0x03ff0000) > 0x00f00000) && + val32 < 0xf) + result |= 0x02; + else /* If TX not OK, ignore RX */ + goto out; +out: + return result; +} + +#ifdef RTL8723BU_PATH_B +static int rtl8723bu_iqk_path_b(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc, path_sel; + int result = 0; + + path_sel = rtl8xxxu_read32(priv, REG_S0S1_PATH_SWITCH); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* One shot, path B LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002); + rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000); + + mdelay(1); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2); + reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2); + + if (!(reg_eac & BIT(31)) && + ((reg_eb4 & 0x03ff0000) != 0x01420000) && + ((reg_ebc & 0x03ff0000) != 0x00420000)) + result |= 0x01; + else + goto out; + + if (!(reg_eac & BIT(30)) && + (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) && + (((reg_ecc & 0x03ff0000) >> 16) != 0x36)) + result |= 0x02; + else + dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n", + __func__); +out: + return result; +} +#endif + static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, int result[][8], int t) { @@ -3879,6 +4327,234 @@ static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, } } +static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, + int result[][8], int t) +{ + struct device *dev = &priv->udev->dev; + u32 i, val32; + int path_a_ok /*, path_b_ok */; + int retry = 2; + const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, + REG_RX_WAIT_CCA, REG_TX_CCK_RFON, + REG_TX_CCK_BBON, REG_TX_OFDM_RFON, + REG_TX_OFDM_BBON, REG_TX_TO_RX, + REG_TX_TO_TX, REG_RX_CCK, + REG_RX_OFDM, REG_RX_WAIT_RIFS, + REG_RX_TO_RX, REG_STANDBY, + REG_SLEEP, REG_PMPD_ANAEN + }; + const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + REG_TXPAUSE, REG_BEACON_CTRL, + REG_BEACON_CTRL_1, REG_GPIO_MUXCFG + }; + const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, + REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, + REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE + }; + u8 xa_agc = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1) & 0xff; + u8 xb_agc = rtl8xxxu_read32(priv, REG_OFDM0_XB_AGC_CORE1) & 0xff; + + /* + * Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt + */ + + if (t == 0) { + /* Save ADDA parameters, turn Path A ADDA on */ + rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + rtl8xxxu_save_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + } + + rtl8xxxu_path_adda_on(priv, adda_regs, true); + + /* MAC settings */ + rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup); + + val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING); + val32 |= 0x0f000000; + rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32); + + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000); + +#ifdef RTL8723BU_PATH_B + /* Set RF mode to standby Path B */ + if (priv->tx_paths > 1) + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x10000); +#endif + +#if 0 + /* Page B init */ + rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x0f600000); + + if (priv->tx_paths > 1) + rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x0f600000); +#endif + + /* + * RX IQ calibration setting for 8723B D cut large current issue + * when leaving IPS + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT); + val32 |= 0x80000; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0001f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7fb7); + + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED); + val32 |= 0x20; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED, val32); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_43, 0x60fbd); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8723bu_iqk_path_a(priv); + if (path_a_ok == 0x01) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + +#if 0 /* Only needed in restore case, we may need this when going to suspend */ + priv->RFCalibrateInfo.TxLOK[RF_A] = + rtl8xxxu_read_rfreg(priv, RF_A, + RF6052_REG_TXM_IDAC); +#endif + + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_BEFORE_IQK_A); + result[t][0] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_AFTER_IQK_A); + result[t][1] = (val32 >> 16) & 0x3ff; + + break; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A TX IQK failed!\n", __func__); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8723bu_rx_iqk_path_a(priv); + if (path_a_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_BEFORE_IQK_A_2); + result[t][2] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_AFTER_IQK_A_2); + result[t][3] = (val32 >> 16) & 0x3ff; + + break; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A RX IQK failed!\n", __func__); + + if (priv->tx_paths > 1) { +#if 1 + dev_warn(dev, "%s: Path B not supported\n", __func__); +#else + + /* + * Path A into standby + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x10000); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + val32 |= 0x80800000; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* Turn Path B ADDA on */ + rtl8xxxu_path_adda_on(priv, adda_regs, false); + + for (i = 0; i < retry; i++) { + path_b_ok = rtl8xxxu_iqk_path_b(priv); + if (path_b_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + result[t][4] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + result[t][5] = (val32 >> 16) & 0x3ff; + break; + } + } + + if (!path_b_ok) + dev_dbg(dev, "%s: Path B IQK failed!\n", __func__); + + for (i = 0; i < retry; i++) { + path_b_ok = rtl8723bu_rx_iqk_path_b(priv); + if (path_a_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_BEFORE_IQK_B_2); + result[t][6] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_AFTER_IQK_B_2); + result[t][7] = (val32 >> 16) & 0x3ff; + break; + } + } + + if (!path_b_ok) + dev_dbg(dev, "%s: Path B RX IQK failed!\n", __func__); +#endif + } + + /* Back to BB mode, load original value */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 &= 0x000000ff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + if (t) { + /* Reload ADDA power saving parameters */ + rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + + /* Reload MAC parameters */ + rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + + /* Reload BB parameters */ + rtl8xxxu_restore_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + + /* Restore RX initial gain */ + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1); + val32 &= 0xffffff00; + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, val32 | 0x50); + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, val32 | xa_agc); + + if (priv->tx_paths > 1) { + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_AGC_CORE1); + val32 &= 0xffffff00; + rtl8xxxu_write32(priv, REG_OFDM0_XB_AGC_CORE1, + val32 | 0x50); + rtl8xxxu_write32(priv, REG_OFDM0_XB_AGC_CORE1, + val32 | xb_agc); + } + + /* Load 0xe30 IQC default value */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00); + } +} + static void rtl8xxxu_prepare_calibrate(struct rtl8xxxu_priv *priv, u8 start) { struct h2c_cmd h2c; @@ -3893,7 +4569,7 @@ static void rtl8xxxu_prepare_calibrate(struct rtl8xxxu_priv *priv, u8 start) rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_wlan_calibration)); } -static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv) +static void rtl8723au_phy_iq_calibrate(struct rtl8xxxu_priv *priv) { struct device *dev = &priv->udev->dev; int result[4][8]; /* last is final result */ @@ -3997,6 +4673,133 @@ static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv) rtl8xxxu_prepare_calibrate(priv, 0); } +static void rtl8723bu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + int result[4][8]; /* last is final result */ + int i, candidate; + bool path_a_ok, path_b_ok; + u32 reg_e94, reg_e9c, reg_ea4, reg_eac; + u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc; + u32 val32, bt_control; + s32 reg_tmp = 0; + bool simu; + + rtl8xxxu_prepare_calibrate(priv, 1); + + memset(result, 0, sizeof(result)); + candidate = -1; + + path_a_ok = false; + path_b_ok = false; + + bt_control = rtl8xxxu_read32(priv, REG_BT_CONTROL_8723BU); + + for (i = 0; i < 3; i++) { + rtl8723bu_phy_iqcalibrate(priv, result, i); + + if (i == 1) { + simu = rtl8723bu_simularity_compare(priv, result, 0, 1); + if (simu) { + candidate = 0; + break; + } + } + + if (i == 2) { + simu = rtl8723bu_simularity_compare(priv, result, 0, 2); + if (simu) { + candidate = 0; + break; + } + + simu = rtl8723bu_simularity_compare(priv, result, 1, 2); + if (simu) { + candidate = 1; + } else { + for (i = 0; i < 8; i++) + reg_tmp += result[3][i]; + + if (reg_tmp) + candidate = 3; + else + candidate = -1; + } + } + } + + for (i = 0; i < 4; i++) { + reg_e94 = result[i][0]; + reg_e9c = result[i][1]; + reg_ea4 = result[i][2]; + reg_eac = result[i][3]; + reg_eb4 = result[i][4]; + reg_ebc = result[i][5]; + reg_ec4 = result[i][6]; + reg_ecc = result[i][7]; + } + + if (candidate >= 0) { + reg_e94 = result[candidate][0]; + priv->rege94 = reg_e94; + reg_e9c = result[candidate][1]; + priv->rege9c = reg_e9c; + reg_ea4 = result[candidate][2]; + reg_eac = result[candidate][3]; + reg_eb4 = result[candidate][4]; + priv->regeb4 = reg_eb4; + reg_ebc = result[candidate][5]; + priv->regebc = reg_ebc; + reg_ec4 = result[candidate][6]; + reg_ecc = result[candidate][7]; + dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); + dev_dbg(dev, + "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x " + "ecc=%x\n ", __func__, reg_e94, reg_e9c, + reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc); + path_a_ok = true; + path_b_ok = true; + } else { + reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100; + reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0; + } + + if (reg_e94 && candidate >= 0) + rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result, + candidate, (reg_ea4 == 0)); + + if (priv->tx_paths > 1 && reg_eb4) + rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result, + candidate, (reg_ec4 == 0)); + + rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg, + priv->bb_recovery_backup, RTL8XXXU_BB_REGS); + + rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, bt_control); + + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT); + val32 |= 0x80000; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x18000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0001f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xe6177); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED); + val32 |= 0x20; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED, val32); + rtl8xxxu_write_rfreg(priv, RF_A, 0x43, 0x300bd); + + if (priv->rf_paths > 1) { + dev_dbg(dev, "%s: beware 2T not yet supported\n", __func__); +#ifdef RTL8723BU_PATH_B + if (RF_Path == 0x0) //S1 + ODM_SetIQCbyRFpath(pDM_Odm, 0); + else //S0 + ODM_SetIQCbyRFpath(pDM_Odm, 1); +#endif + } + rtl8xxxu_prepare_calibrate(priv, 0); +} + static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv) { u32 val32; @@ -4995,7 +5798,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); - rtl8723a_phy_iq_calibrate(priv); + priv->fops->phy_iq_calibrate(priv); /* * This should enable thermal meter @@ -6536,6 +7339,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .load_firmware = rtl8723au_load_firmware, .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_init_llt_table, + .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -6551,6 +7355,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_auto_llt_table, .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, + .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -6567,6 +7372,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .load_firmware = rtl8192cu_load_firmware, .power_on = rtl8192cu_power_on, .llt_init = rtl8xxxu_init_llt_table, + .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -6583,6 +7389,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .load_firmware = rtl8192eu_load_firmware, .power_on = rtl8192eu_power_on, .llt_init = rtl8xxxu_auto_llt_table, + .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 4b8431db38d2..76398de2b110 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -851,6 +851,7 @@ struct rtl8xxxu_fileops { int (*power_on) (struct rtl8xxxu_priv *priv); int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); + void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 162a9e8e4cef..499210f81845 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -708,6 +708,12 @@ #define REG_MACID1 0x0700 #define REG_BSSID1 0x0708 +/* + * This seems to be 8723bu specific + */ +#define REG_BT_CONTROL_8723BU 0x0764 +#define BT_CONTROL_BT_GRANT BIT(12) + #define REG_FPGA0_RF_MODE 0x0800 #define FPGA_RF_MODE BIT(0) #define FPGA_RF_MODE_JAPAN BIT(1) @@ -810,6 +816,7 @@ #define REG_RFE_CTRL_ANTA_SRC 0x0930 /* 8723BU */ #define REG_RFE_PATH_SELECT 0x0940 /* 8723BU */ #define REG_RFE_BUFFER 0x0944 /* 8723BU */ +#define REG_S0S1_PATH_SWITCH 0x0948 /* 8723BU */ #define REG_CCK0_SYSTEM 0x0a00 #define CCK0_SIDEBAND BIT(4) @@ -1050,3 +1057,13 @@ #define RF6052_REG_TXPA_G1 0x31 /* RF TX PA control */ #define RF6052_REG_TXPA_G2 0x32 /* RF TX PA control */ #define RF6052_REG_TXPA_G3 0x33 /* RF TX PA control */ + +/* + * NextGen regs: 8723BU + */ +#define RF6052_REG_UNKNOWN_43 0x43 +#define RF6052_REG_UNKNOWN_55 0x55 +#define RF6052_REG_S0S1 0xb0 +#define RF6052_REG_UNKNOWN_DF 0xdf +#define RF6052_REG_UNKNOWN_ED 0xed +#define RF6052_REG_WE_LUT 0xef -- cgit v1.2.3 From 0d698dec06f828480a95a0c7a91c13bc4ad374e4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:36 -0500 Subject: rtl8xxxu: Handle S0S1 register in lc_calibrate() Newer chips (8723bu/8192eu) has S0S1 settings which needs to be dealt with during LC calibration. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 7 +++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index a40ef21016e2..cfd016c5b7ef 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -4835,12 +4835,17 @@ static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv) } /* Start LC calibration */ + if (priv->fops->has_s0s1) + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_S0S1, 0xdfbe0); val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG); val32 |= 0x08000; rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32); msleep(100); + if (priv->fops->has_s0s1) + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_S0S1, 0xdffe0); + /* Restore original parameters */ if (lstf & OFDM_LSTF_MASK) { /* Path-A */ @@ -7359,6 +7364,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, + .has_s0s1 = 1, .adda_1t_init = 0x01c00014, .adda_1t_path_on = 0x01c00014, .adda_2t_path_on_a = 0x01c00014, @@ -7393,6 +7399,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, + .has_s0s1 = 1, .adda_1t_init = 0x0fc01616, .adda_1t_path_on = 0x0fc01616, .adda_2t_path_on_a = 0x0fc01616, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 76398de2b110..4a974a698dcc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -855,6 +855,7 @@ struct rtl8xxxu_fileops { int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; + char has_s0s1; u32 adda_1t_init; u32 adda_1t_path_on; u32 adda_2t_path_on_a; -- cgit v1.2.3 From fa0f2d481d178fa2bf44f9488a695ab56d4e78f6 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:37 -0500 Subject: rtl8xxxu: Do LC calibration before IQK calibration This matches the flow of the vendor driver for newer hardware, and doesn't seem to cause issues for the older parts. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index cfd016c5b7ef..62537bd824a5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5803,6 +5803,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); + rtl8723a_phy_lc_calibrate(priv); + priv->fops->phy_iq_calibrate(priv); /* @@ -5810,8 +5812,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) */ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60); - rtl8723a_phy_lc_calibrate(priv); - /* Init BT hw config. */ rtl8xxxu_init_bt(priv); -- cgit v1.2.3 From 60c76cbadb61084139d710ca710959274efdde5b Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:38 -0500 Subject: rtl8xxxu: Remove backing up certain registers, which was never used This was inspired by the vendor driver, but in the end never used for anything. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 14 -------------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 3 --- 2 files changed, 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 62537bd824a5..4579a3ea07c1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5815,20 +5815,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* Init BT hw config. */ rtl8xxxu_init_bt(priv); - /* - * Not sure if we really need to save these parameters, but the - * vendor driver does - */ - val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2); - if (val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR) - priv->path_a_hi_power = 1; - - val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); - priv->path_a_rf_paths = val32 & OFDM_RF_PATH_RX_MASK; - - val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1); - priv->path_a_ig_value = val32 & OFDM0_X_AGC_CORE1_IGI_MASK; - /* Set NAV_UPPER to 30000us */ val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT); rtl8xxxu_write8(priv, REG_NAV_UPPER, val8); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 4a974a698dcc..7b76e11519a6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -785,13 +785,10 @@ struct rtl8xxxu_priv { u32 ep_tx_high_queue:1; u32 ep_tx_normal_queue:1; u32 ep_tx_low_queue:1; - u32 path_a_hi_power:1; - u32 path_a_rf_paths:4; unsigned int pipe_interrupt; unsigned int pipe_in; unsigned int pipe_out[TXDESC_QUEUE_MAX]; u8 out_ep[RTL8XXXU_OUT_ENDPOINTS]; - u8 path_a_ig_value; u8 ep_tx_count; u8 rf_paths; u8 rx_paths; -- cgit v1.2.3 From e6f9a9c3b5235f31434a9de9034ea5eda1532113 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Mon, 29 Feb 2016 17:04:39 -0500 Subject: rtl8xxxu: rtl8192eu: Map out EFUSE TX power area TX power values are laid out differently in EFUSE found in RTL8192EU & RTL8188EU devices. TX power indices and differences for each RF path are not interleaved (A, B, A, B), as in other chips, but follow one another (A, B, C, D). Signed-off-by: Jakub Sitnicki Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 10 ---------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 22 +++++++++++++++++----- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4579a3ea07c1..4edd9c79f59b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2293,16 +2293,6 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) ether_addr_copy(priv->mac_addr, efuse->mac_addr); - memcpy(priv->cck_tx_power_index_A, efuse->cck_tx_power_index_A, - sizeof(priv->cck_tx_power_index_A)); - memcpy(priv->cck_tx_power_index_B, efuse->cck_tx_power_index_B, - sizeof(priv->cck_tx_power_index_B)); - - memcpy(priv->ht40_1s_tx_power_index_A, efuse->ht40_1s_tx_power_index_A, - sizeof(priv->ht40_1s_tx_power_index_A)); - memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, - sizeof(priv->ht40_1s_tx_power_index_B)); - dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 7b76e11519a6..6c6bac253473 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -543,14 +543,26 @@ struct rtl8723bu_efuse { u8 res12[0x4]; }; +struct rtl8192eu_efuse_tx_power { + u8 cck_base[6]; + u8 ht40_base[5]; + struct rtl8723au_idx ht20_ofdm_1s_diff; + struct rtl8723au_idx ht40_ht20_2s_diff; + struct rtl8723au_idx ofdm_cck_2s_diff; /* not used */ + struct rtl8723au_idx ht40_ht20_3s_diff; + struct rtl8723au_idx ofdm_cck_3s_diff; /* not used */ + struct rtl8723au_idx ht40_ht20_4s_diff; + struct rtl8723au_idx ofdm_cck_4s_diff; /* not used */ +}; + struct rtl8192eu_efuse { __le16 rtl_id; u8 res0[0x0e]; - u8 cck_tx_power_index_A[3]; /* 0x10 */ - u8 cck_tx_power_index_B[3]; - u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ - u8 ht40_1s_tx_power_index_B[3]; - u8 res1[0x9c]; + struct rtl8192eu_efuse_tx_power tx_power_index_A; /* 0x10 */ + struct rtl8192eu_efuse_tx_power tx_power_index_B; /* 0x22 */ + struct rtl8192eu_efuse_tx_power tx_power_index_C; /* 0x34 */ + struct rtl8192eu_efuse_tx_power tx_power_index_D; /* 0x46 */ + u8 res1[0x60]; u8 channel_plan; /* 0xb8 */ u8 xtal_k; u8 thermal_meter; -- cgit v1.2.3 From c3f9506f2374772e579e1c19b86d79f1da71dea2 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:40 -0500 Subject: rtl8xxxu: Initial implementation of rtl8723bu_config_channel() This is a first stab of implementing rtl8723bu_config_channel(). For now this will only do 20MHz channels. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 134 +++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 14 +++ 3 files changed, 149 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4edd9c79f59b..ada0f040f41a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1777,6 +1777,136 @@ static void rtl8723au_config_channel(struct ieee80211_hw *hw) } } +static void rtl8723bu_config_channel(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + u32 val32, rsr; + u8 val8, opmode, subchannel; + u16 rf_mode_bw; + bool ht = true; + int sec_ch_above, channel; + int i; + + rf_mode_bw = rtl8xxxu_read16(priv, REG_WMAC_TRXPTCL_CTL); + rf_mode_bw &= ~WMAC_TRXPTCL_CTL_BW_MASK; + rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + channel = hw->conf.chandef.chan->hw_value; + +/* Hack */ + subchannel = 0; + + switch (hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + ht = false; + case NL80211_CHAN_WIDTH_20: + rf_mode_bw |= WMAC_TRXPTCL_CTL_BW_20; + subchannel = 0; + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT); + val32 &= ~(BIT(30) | BIT(31)); + rtl8xxxu_write32(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT, val32); + + break; + case NL80211_CHAN_WIDTH_40: + rf_mode_bw |= WMAC_TRXPTCL_CTL_BW_40; + + if (hw->conf.chandef.center_freq1 > + hw->conf.chandef.chan->center_freq) { + sec_ch_above = 1; + channel += 2; + } else { + sec_ch_above = 0; + channel -= 2; + } + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + + /* + * Set Control channel to upper or lower. These settings + * are required only for 40MHz + */ + val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM); + val32 &= ~CCK0_SIDEBAND; + if (!sec_ch_above) + val32 |= CCK0_SIDEBAND; + rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF); + val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */ + if (sec_ch_above) + val32 |= OFDM_LSTF_PRIME_CH_LOW; + else + val32 |= OFDM_LSTF_PRIME_CH_HIGH; + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE); + val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL); + if (sec_ch_above) + val32 |= FPGA0_PS_UPPER_CHANNEL; + else + val32 |= FPGA0_PS_LOWER_CHANNEL; + rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32); + break; + case NL80211_CHAN_WIDTH_80: + rf_mode_bw |= WMAC_TRXPTCL_CTL_BW_80; + break; + default: + break; + } + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + val32 &= ~MODE_AG_CHANNEL_MASK; + val32 |= channel; + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } + + rtl8xxxu_write16(priv, REG_WMAC_TRXPTCL_CTL, rf_mode_bw); + rtl8xxxu_write8(priv, REG_DATA_SUBCHANNEL, subchannel); + + if (ht) + val8 = 0x0e; + else + val8 = 0x0a; + + rtl8xxxu_write8(priv, REG_SIFS_CCK + 1, val8); + rtl8xxxu_write8(priv, REG_SIFS_OFDM + 1, val8); + + rtl8xxxu_write16(priv, REG_R2T_SIFS, 0x0808); + rtl8xxxu_write16(priv, REG_T2T_SIFS, 0x0a0a); + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + val32 &= ~MODE_AG_BW_MASK; + switch(hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_80: + val32 |= MODE_AG_BW_80MHZ_8723B; + break; + case NL80211_CHAN_WIDTH_40: + val32 |= MODE_AG_BW_40MHZ_8723B; + break; + default: + val32 |= MODE_AG_BW_20MHZ_8723B; + break; + } + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } +} + static void rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) { @@ -7321,6 +7451,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .power_on = rtl8723au_power_on, .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, + .config_channel = rtl8723au_config_channel, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -7337,6 +7468,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .llt_init = rtl8xxxu_auto_llt_table, .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, + .config_channel = rtl8723bu_config_channel, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -7355,6 +7487,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .power_on = rtl8192cu_power_on, .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, + .config_channel = rtl8723au_config_channel, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -7372,6 +7505,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .power_on = rtl8192eu_power_on, .llt_init = rtl8xxxu_auto_llt_table, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, + .config_channel = rtl8723bu_config_channel, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 6c6bac253473..bce52cdc731a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -861,6 +861,7 @@ struct rtl8xxxu_fileops { int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); + void (*config_channel) (struct ieee80211_hw *hw); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 499210f81845..147deba749e6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -473,6 +473,9 @@ #define REG_FAST_EDCA_CTRL 0x0460 #define REG_RD_RESP_PKT_TH 0x0463 #define REG_INIRTS_RATE_SEL 0x0480 +/* 8723bu */ +#define REG_DATA_SUBCHANNEL 0x0483 +/* 8723au */ #define REG_INIDATA_RATE_SEL 0x0484 #define REG_POWER_STATUS 0x04a4 @@ -658,6 +661,10 @@ #define REG_FWDLY 0x0661 #define REG_RXERR_RPT 0x0664 #define REG_WMAC_TRXPTCL_CTL 0x0668 +#define WMAC_TRXPTCL_CTL_BW_MASK (BIT(7) | BIT(8)) +#define WMAC_TRXPTCL_CTL_BW_20 0 +#define WMAC_TRXPTCL_CTL_BW_40 BIT(7) +#define WMAC_TRXPTCL_CTL_BW_80 BIT(8) /* Security */ #define REG_CAM_CMD 0x0670 @@ -872,6 +879,9 @@ #define REG_OFDM0_RX_IQ_EXT_ANTA 0x0ca0 +/* 8723bu */ +#define REG_OFDM0_TX_PSDO_NOISE_WEIGHT 0x0ce4 + #define REG_OFDM1_LSTF 0x0d00 #define OFDM_LSTF_PRIME_CH_LOW BIT(10) #define OFDM_LSTF_PRIME_CH_HIGH BIT(11) @@ -1030,6 +1040,10 @@ #define RF6052_REG_MODE_AG 0x18 /* RF channel and BW switch */ #define MODE_AG_CHANNEL_MASK 0x3ff #define MODE_AG_CHANNEL_20MHZ BIT(10) +#define MODE_AG_BW_MASK (BIT(10) | BIT(11)) +#define MODE_AG_BW_20MHZ_8723B (BIT(10) | BIT(11)) +#define MODE_AG_BW_40MHZ_8723B BIT(10) +#define MODE_AG_BW_80MHZ_8723B 0 #define RF6052_REG_TOP 0x19 #define RF6052_REG_RX_G1 0x1a -- cgit v1.2.3 From f37e9228aecaa9c92ee0433cd45ca0c545b90ce4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:41 -0500 Subject: rtl8xxxu: Initial rtl8723bu_init_bt() code This should initialize the antennas on the 8723bu, but so far I am still not receiving anything :( More work is needed. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 87 +++++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 15 +++- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 + 3 files changed, 98 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ada0f040f41a..fa8a92a68bc5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5603,10 +5603,87 @@ static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); } -static void rtl8xxxu_init_bt(struct rtl8xxxu_priv *priv) +static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) { - if (!priv->has_bluetooth) - return; + struct h2c_cmd h2c; + u32 val32; + u8 val8; + + /* + * No indication anywhere as to what 0x0790 does. The 2 antenna + * vendor code preserves bits 6-7 here. + */ + rtl8xxxu_write8(priv, 0x0790, 0x05); + /* + * 0x0778 seems to be related to enabling the number of antennas + * In the vendor driver halbtc8723b2ant_InitHwConfig() sets it + * to 0x03, while halbtc8723b1ant_InitHwConfig() sets it to 0x01 + */ + rtl8xxxu_write8(priv, 0x0778, 0x01); + + val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG); + val8 |= BIT(5); + rtl8xxxu_write8(priv, REG_GPIO_MUXCFG, val8); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_IQADJ_G1, 0x780); + + /* + * Set BT grant to low + */ + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.bt_grant.cmd = H2C_8723B_BT_GRANT; + h2c.bt_grant.data = 0; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_grant)); + + /* + * WLAN action by PTA + */ + rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x0c); + + /* + * BT select S0/S1 controlled by WiFi + */ + val8 = rtl8xxxu_read8(priv, 0x0067); + val8 |= BIT(5); + rtl8xxxu_write8(priv, 0x0067, val8); + + val32 = rtl8xxxu_read32(priv, REG_PWR_DATA); + val32 |= BIT(11); + rtl8xxxu_write32(priv, REG_PWR_DATA, val32); + + /* + * Bits 6/7 are marked in/out ... but for what? + */ + rtl8xxxu_write8(priv, 0x0974, 0xff); + + val32 = rtl8xxxu_read32(priv, 0x0944); + val32 |= (BIT(0) | BIT(1)); + rtl8xxxu_write32(priv, 0x0944, val32); + + rtl8xxxu_write8(priv, REG_RFE_CTRL_ANTA_SRC, 0x77); + + val32 = rtl8xxxu_read32(priv, REG_LEDCFG0); + val32 &= ~BIT(24); + val32 |= BIT(23); + rtl8xxxu_write32(priv, REG_LEDCFG0, val32); + + /* + * Fix external switch Main->S1, Aux->S0 + */ + val8 = rtl8xxxu_read8(priv, REG_PAD_CTRL1); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8); + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.ant_sel_rsv.cmd = H2C_8723B_ANT_SEL_RSV; + h2c.ant_sel_rsv.ant_inverse = 1; + h2c.ant_sel_rsv.int_switch_type = 0; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ant_sel_rsv)); + + /* + * 0x280, 0x00, 0x200, 0x80 - not clear + */ + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x280); } static int rtl8xxxu_init_device(struct ieee80211_hw *hw) @@ -5933,7 +6010,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60); /* Init BT hw config. */ - rtl8xxxu_init_bt(priv); + if (priv->fops->init_bt) + priv->fops->init_bt(priv); /* Set NAV_UPPER to 30000us */ val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT); @@ -7469,6 +7547,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, + .init_bt = rtl8723bu_init_bt, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index bce52cdc731a..bcbdc78e9de6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -696,8 +696,9 @@ enum h2c_cmd_8723b { H2C_8723B_BT_MP_OPER = 0x67, H2C_8723B_BT_CONTROL = 0x68, H2C_8723B_BT_WIFI_CTRL = 0x69, - H2C_8723B_BT_FW_PATCH = 0x6A, - H2C_8723B_BT_WLAN_CALIBRATION = 0x6D, + H2C_8723B_BT_FW_PATCH = 0x6a, + H2C_8723B_BT_WLAN_CALIBRATION = 0x6d, + H2C_8723B_BT_GRANT = 0x6e, /* * WOWLAN Class: 100 @@ -743,6 +744,15 @@ struct h2c_cmd { u8 cmd; u8 data; } __packed bt_wlan_calibration; + struct { + u8 cmd; + u8 ant_inverse; + u8 int_switch_type; + } __packed ant_sel_rsv; + struct { + u8 cmd; + u8 data; + } __packed bt_grant; }; }; @@ -862,6 +872,7 @@ struct rtl8xxxu_fileops { void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); void (*config_channel) (struct ieee80211_hw *hw); + void (*init_bt) (struct rtl8xxxu_priv *priv); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 147deba749e6..248f64c7f8e3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -721,6 +721,8 @@ #define REG_BT_CONTROL_8723BU 0x0764 #define BT_CONTROL_BT_GRANT BIT(12) +#define REG_WLAN_ACT_CONTROL_8723B 0x076e + #define REG_FPGA0_RF_MODE 0x0800 #define FPGA_RF_MODE BIT(0) #define FPGA_RF_MODE_JAPAN BIT(1) -- cgit v1.2.3 From 368633ce6853bb2ba678c7cb5bfeb103e7bc56ba Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:42 -0500 Subject: rtl8xxxu: Remove unused variable Remove an unused variable to make the compiler happy. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index fa8a92a68bc5..70543942e8d4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1781,7 +1781,7 @@ static void rtl8723bu_config_channel(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; u32 val32, rsr; - u8 val8, opmode, subchannel; + u8 val8, subchannel; u16 rf_mode_bw; bool ht = true; int sec_ch_above, channel; -- cgit v1.2.3 From 3ca7b32c9d6da17a2660bc40b24f5dc0cb433cc9 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:43 -0500 Subject: rtl8xxxu: Improve 8723bu init code Implement additional init sequence code for the 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 45 ++++++++++++++++++---- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 ++++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 5 ++- 3 files changed, 49 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 70543942e8d4..91f189a85057 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2984,14 +2984,18 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) * addresses, which is initialized here. Do we need this? */ - val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL); - udelay(2); - val8 |= AFE_PLL_320_ENABLE; - rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8); - udelay(2); + if (priv->rtlchip == 0x8723b) { + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00); + } else { + val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL); + udelay(2); + val8 |= AFE_PLL_320_ENABLE; + rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8); + udelay(2); - rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff); - udelay(2); + rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff); + udelay(2); + } val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; @@ -5603,6 +5607,21 @@ static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); } +static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, + u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) +{ + struct h2c_cmd h2c; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.b_type_dma.cmd = H2C_8723B_B_TYPE_TDMA; + h2c.b_type_dma.data1 = arg1; + h2c.b_type_dma.data2 = arg2; + h2c.b_type_dma.data3 = arg3; + h2c.b_type_dma.data4 = arg4; + h2c.b_type_dma.data5 = arg5; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma)); +} + static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) { struct h2c_cmd h2c; @@ -5683,7 +5702,17 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) /* * 0x280, 0x00, 0x200, 0x80 - not clear */ - rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x280); + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00); + + /* + * Software control, antenna at WiFi side + */ + rtl8723bu_set_ps_tdma(priv, 0x00, 0x00, 0x00, 0x00, 0x00); + + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE4, 0x00000003); } static int rtl8xxxu_init_device(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index bcbdc78e9de6..c4c0b287127b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -740,6 +740,14 @@ struct h2c_cmd { u8 arg; __le16 mask_lo; } __packed ramask; + struct { + u8 cmd; + u8 data1; + u8 data2; + u8 data3; + u8 data4; + u8 data5; + } __packed b_type_dma; struct { u8 cmd; u8 data; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 248f64c7f8e3..a82c0ba7931d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -709,7 +709,10 @@ #define REG_BCN_PSR_RPT 0x06a8 #define REG_CALB32K_CTRL 0x06ac #define REG_PKT_MON_CTRL 0x06b4 -#define REG_BT_COEX_TABLE 0x06c0 +#define REG_BT_COEX_TABLE1 0x06c0 +#define REG_BT_COEX_TABLE2 0x06c4 +#define REG_BT_COEX_TABLE3 0x06c8 +#define REG_BT_COEX_TABLE4 0x06cc #define REG_WMAC_RESP_TXINFO 0x06d8 #define REG_MACID1 0x0700 -- cgit v1.2.3 From 7297f49c3761826242cd8a742f0f78a139d6653a Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:44 -0500 Subject: rtl8xxxu: Do not ignore wlan activity on 8723bu The 8723bu is a WiFi/BT combo part. When initializing it for WiFi, make sure to tell it not to ignore WiFi activity. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 +++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 91f189a85057..c9cbea7342b7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5704,6 +5704,11 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) */ rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00); + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.ignore_wlan.cmd = H2C_8723B_BT_IGNORE_WLANACT; + h2c.ignore_wlan.data = 0; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ignore_wlan)); + /* * Software control, antenna at WiFi side */ diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index c4c0b287127b..5a6b2232e20a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -752,6 +752,10 @@ struct h2c_cmd { u8 cmd; u8 data; } __packed bt_wlan_calibration; + struct { + u8 cmd; + u8 data; + } __packed ignore_wlan; struct { u8 cmd; u8 ant_inverse; -- cgit v1.2.3 From a228a5db4d19b05da7315320e0b4a87ed7c472aa Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:45 -0500 Subject: rtl8xxxu: Set the right type for ps tdma on 8723bu Use the correct type when setting PS TDMA for 8723bu. This matches the vendor driver. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index c9cbea7342b7..0638d4655dfa 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5712,7 +5712,7 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) /* * Software control, antenna at WiFi side */ - rtl8723bu_set_ps_tdma(priv, 0x00, 0x00, 0x00, 0x00, 0x00); + rtl8723bu_set_ps_tdma(priv, 0x08, 0x00, 0x00, 0x00, 0x00); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); -- cgit v1.2.3 From a6c80d211cdf0748a8ae4fd1ab41cf43d3ecbd71 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:46 -0500 Subject: rtl8xxxu: Add rtl8723bu (nextgen) rx descriptor definition The nextgen chips use a slightly different RX descriptor format. This adds support for the new format. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 125 +++++++++++++++++++++++ 1 file changed, 125 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 5a6b2232e20a..a8a4f2b451d1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -197,6 +197,131 @@ struct rtl8xxxu_rx_desc { #endif }; +struct rtl8723bu_rx_desc { +#ifdef __LITTLE_ENDIAN + u32 pktlen:14; + u32 crc32:1; + u32 icverr:1; + u32 drvinfo_sz:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 phy_stats:1; + u32 swdec:1; + u32 ls:1; + u32 fs:1; + u32 eor:1; + u32 own:1; + + u32 macid:7; + u32 dummy1_0:1; + u32 tid:4; + u32 dummy1_1:1; + u32 amsdu:1; + u32 rxid_match:1; + u32 paggr:1; + u32 a1fit:4; /* 16 */ + u32 chkerr:1; + u32 ipver:1; + u32 tcpudp:1; + u32 chkvld:1; + u32 pam:1; + u32 pwr:1; + u32 more_data:1; + u32 more_frag:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + + u32 seq:12; + u32 frag:4; + u32 rx_is_qos:1; /* 16 */ + u32 dummy2_0:1; + u32 wlanhd_iv_len:6; + u32 dummy2_1:4; + u32 rpt_sel:1; + u32 dummy2_2:3; + + u32 rxmcs:7; + u32 dummy3_0:3; + u32 htc:1; + u32 eosp:1; + u32 bssidfit:2; + u32 dummy3_1:2; + u32 usb_agg_pktnum:8; /* 16 */ + u32 dummy3_2:5; + u32 pattern_match:1; + u32 unicast_match:1; + u32 magic_match:1; + + u32 splcp:1; + u32 ldcp:1; + u32 stbc:1; + u32 dummy4_0:1; + u32 bw:2; + u32 dummy4_1:26; +#else + u32 own:1; + u32 eor:1; + u32 fs:1; + u32 ls:1; + u32 swdec:1; + u32 phy_stats:1; + u32 shift:2; + u32 qos:1; + u32 security:3; + u32 drvinfo_sz:4; + u32 icverr:1; + u32 crc32:1; + u32 pktlen:14; + + u32 bc:1; + u32 mc:1; + u32 type:2; + u32 mf:1; + u32 md:1; + u32 pwr:1; + u32 pam:1; + u32 a2fit:4; + u32 a1fit:4; + u32 faggr:1; + u32 paggr:1; + u32 amsdu:1; + u32 hwrsvd:4; + u32 tid:4; + u32 macid:5; + + u32 dummy2_2:3; + u32 rpt_sel:1; + u32 dummy2_1:4; + u32 wlanhd_iv_len:6; + u32 dummy2_0:1; + u32 rx_is_qos:1; + u32 frag:4; /* 16 */ + u32 seq:12; + + u32 magic_match:1; + u32 unicast_match:1; + u32 pattern_match:1; + u32 dummy3_2:5; + u32 usb_agg_pktnum:8; + u32 dummy3_1:2; /* 16 */ + u32 bssidfit:2; + u32 eosp:1; + u32 htc:1; + u32 dummy3_0:3; + u32 rxmcs:7; + + u32 dumm4_1:26; + u32 bw:2; + u32 dummy4_0:1; + u32 stbc:1; + u32 ldcp:1; + u32 splcp:1; +#endif + __le32 tsfl; +}; + struct rtl8xxxu_tx_desc { __le16 pkt_size; u8 pkt_offset; -- cgit v1.2.3 From b18cdfdb67b258c01947e611b6bbb745188eb131 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:47 -0500 Subject: rtl8xxxu: Handle 8723bu style rx descriptors This adds code to parse the new RX descriptor format used by the 8723bu/8192eu parts. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 125 +++++++++++++++++------ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 ++ 2 files changed, 103 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 0638d4655dfa..8e6d54f18119 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6730,6 +6730,91 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) } } +static int rtl8723au_parse_rx_desc(struct rtl8xxxu_priv *priv, + struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data; + struct rtl8723au_phy_stats *phy_stats; + int drvinfo_sz, desc_shift; + + skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc)); + + phy_stats = (struct rtl8723au_phy_stats *)skb->data; + + drvinfo_sz = rx_desc->drvinfo_sz * 8; + desc_shift = rx_desc->shift; + skb_pull(skb, drvinfo_sz + desc_shift); + + if (rx_desc->phy_stats) + rtl8xxxu_rx_parse_phystats(priv, rx_status, rx_desc, phy_stats); + + rx_status->mactime = le32_to_cpu(rx_desc->tsfl); + rx_status->flag |= RX_FLAG_MACTIME_START; + + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->flag |= RX_FLAG_40MHZ; + + if (rx_desc->rxht) { + rx_status->flag |= RX_FLAG_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } + + return RX_TYPE_DATA_PKT; +} + +static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv, + struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct rtl8723bu_rx_desc *rx_desc = + (struct rtl8723bu_rx_desc *)skb->data; + struct rtl8723au_phy_stats *phy_stats; + int drvinfo_sz, desc_shift; + int rx_type; + + skb_pull(skb, sizeof(struct rtl8723bu_rx_desc)); + + phy_stats = (struct rtl8723au_phy_stats *)skb->data; + + drvinfo_sz = rx_desc->drvinfo_sz * 8; + desc_shift = rx_desc->shift; + skb_pull(skb, drvinfo_sz + desc_shift); + + rx_status->mactime = le32_to_cpu(rx_desc->tsfl); + rx_status->flag |= RX_FLAG_MACTIME_START; + + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->flag |= RX_FLAG_40MHZ; + + if (rx_desc->rxmcs >= DESC_RATE_MCS0) { + rx_status->flag |= RX_FLAG_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } + + if (rx_desc->rpt_sel) { + struct device *dev = &priv->udev->dev; + dev_dbg(dev, "%s: C2H packet\n", __func__); + rx_type = RX_TYPE_C2H; + } else { + rx_type = RX_TYPE_DATA_PKT; + } + + return rx_type; +} + static void rtl8xxxu_rx_complete(struct urb *urb) { struct rtl8xxxu_rx_urb *rx_urb = @@ -6737,54 +6822,30 @@ static void rtl8xxxu_rx_complete(struct urb *urb) struct ieee80211_hw *hw = rx_urb->hw; struct rtl8xxxu_priv *priv = hw->priv; struct sk_buff *skb = (struct sk_buff *)urb->context; - struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data; - struct rtl8723au_phy_stats *phy_stats; struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct device *dev = &priv->udev->dev; __le32 *_rx_desc_le = (__le32 *)skb->data; u32 *_rx_desc = (u32 *)skb->data; - int drvinfo_sz, desc_shift, i; + int rx_type, i; for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++) _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); - drvinfo_sz = rx_desc->drvinfo_sz * 8; - desc_shift = rx_desc->shift; skb_put(skb, urb->actual_length); if (urb->status == 0) { - skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc)); - phy_stats = (struct rtl8723au_phy_stats *)skb->data; - - skb_pull(skb, drvinfo_sz + desc_shift); - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (rx_desc->phy_stats) - rtl8xxxu_rx_parse_phystats(priv, rx_status, - rx_desc, phy_stats); + rx_type = priv->fops->parse_rx_desc(priv, skb, rx_status); rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; - rx_status->mactime = le32_to_cpu(rx_desc->tsfl); - rx_status->flag |= RX_FLAG_MACTIME_START; - - if (!rx_desc->swdec) - rx_status->flag |= RX_FLAG_DECRYPTED; - if (rx_desc->crc32) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_desc->bw) - rx_status->flag |= RX_FLAG_40MHZ; - - if (rx_desc->rxht) { - rx_status->flag |= RX_FLAG_HT; - rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; - } else { - rx_status->rate_idx = rx_desc->rxmcs; - } + if (rx_type == RX_TYPE_DATA_PKT) + ieee80211_rx_irqsafe(hw, skb); + else + dev_kfree_skb(skb); - ieee80211_rx_irqsafe(hw, skb); skb = NULL; rx_urb->urb.context = NULL; rtl8xxxu_queue_rx_urb(priv, rx_urb); @@ -7564,6 +7625,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, + .parse_rx_desc = rtl8723au_parse_rx_desc, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -7582,6 +7644,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, .init_bt = rtl8723bu_init_bt, + .parse_rx_desc = rtl8723bu_parse_rx_desc, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -7601,6 +7664,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, + .parse_rx_desc = rtl8723au_parse_rx_desc, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -7619,6 +7683,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .llt_init = rtl8xxxu_auto_llt_table, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, + .parse_rx_desc = rtl8723bu_parse_rx_desc, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index a8a4f2b451d1..4a3afe3c8260 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -61,6 +61,12 @@ #define EFUSE_BT_MAP_LEN_8723A 1024 #define EFUSE_MAX_WORD_UNIT 4 +enum rtl8xxxu_rx_type { + RX_TYPE_DATA_PKT = 0, + RX_TYPE_C2H = 1, + RX_TYPE_ERROR = -1 +}; + struct rtl8xxxu_rx_desc { #ifdef __LITTLE_ENDIAN u32 pktlen:14; @@ -1010,6 +1016,8 @@ struct rtl8xxxu_fileops { void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); void (*config_channel) (struct ieee80211_hw *hw); void (*init_bt) (struct rtl8xxxu_priv *priv); + int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; -- cgit v1.2.3 From b2b43b7837ba2e097bb019ee488ca5f4e0056fa4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:48 -0500 Subject: rtl8xxxu: Initial functionality to handle C2H events for 8723bu The 64 bit mailbox commands also provide a different method for mailbox command responses (C2H events). Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 34 ++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 54 ++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 8e6d54f18119..1f280930ad5c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6815,6 +6815,36 @@ static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv, return rx_type; } +static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, + struct sk_buff *skb) +{ + struct rtl8723bu_c2h *c2h = (struct rtl8723bu_c2h *)skb->data; + struct device *dev = &priv->udev->dev; + int len; + + len = skb->len - 2; + + pr_info("%s: C2H ID %02x seq %02x, len %02x %02x\n", __func__, + c2h->id, c2h->seq, len, c2h->bt_info.response_source); + + switch(c2h->id) { + case C2H_8723B_BT_INFO: + if (c2h->bt_info.response_source > + BT_INFO_SRC_8723B_BT_ACTIVE_SEND) + dev_info(dev, "C2H_BT_INFO WiFi only firmware\n"); + else + dev_info(dev, "C2H_BT_INFO BT/WiFi coexist firmware\n"); + + if (c2h->bt_info.bt_has_reset) + dev_info(dev, "BT has been reset\n"); + + break; + default: + pr_info("%s: Unhandled C2H event %02x\n", __func__, c2h->id); + break; + } +} + static void rtl8xxxu_rx_complete(struct urb *urb) { struct rtl8xxxu_rx_urb *rx_urb = @@ -6843,8 +6873,10 @@ static void rtl8xxxu_rx_complete(struct urb *urb) if (rx_type == RX_TYPE_DATA_PKT) ieee80211_rx_irqsafe(hw, skb); - else + else { + rtl8723bu_handle_c2h(priv, skb); dev_kfree_skb(skb); + } skb = NULL; rx_urb->urb.context = NULL; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 4a3afe3c8260..e4d5c4b29e3a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -899,6 +899,60 @@ struct h2c_cmd { }; }; +enum c2h_evt_8723b { + C2H_8723B_DEBUG = 0, + C2H_8723B_TSF = 1, + C2H_8723B_AP_RPT_RSP = 2, + C2H_8723B_CCX_TX_RPT = 3, + C2H_8723B_BT_RSSI = 4, + C2H_8723B_BT_OP_MODE = 5, + C2H_8723B_EXT_RA_RPT = 6, + C2H_8723B_BT_INFO = 9, + C2H_8723B_HW_INFO_EXCH = 10, + C2H_8723B_BT_MP_INFO = 11, + C2H_8723B_FW_DEBUG = 0xff, +}; + +enum bt_info_src_8723b { + BT_INFO_SRC_8723B_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_BT_RSP = 0x1, + BT_INFO_SRC_8723B_BT_ACTIVE_SEND = 0x2, +}; + +struct rtl8723bu_c2h { + u8 id; + u8 seq; + union { + struct { + u8 payload[0]; + } __packed raw; + struct { + u8 response_source:4; + u8 dummy0_0:4; + + u8 bt_info; + + u8 retry_count:4; + u8 dummy2_0:1; + u8 bt_page:1; + u8 tx_rx_mask:1; + u8 dummy2_2:1; + + u8 rssi; + + u8 basic_rate:1; + u8 bt_has_reset:1; + u8 dummy4_1:1;; + u8 ignore_wlan:1; + u8 auto_report:1; + u8 dummy4_2:3; + + u8 a4; + u8 a5; + } __packed bt_info; + }; +}; + struct rtl8xxxu_fileops; struct rtl8xxxu_priv { -- cgit v1.2.3 From 394f1bd314cd08915fee9d5b36a2105dc1a543b7 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:49 -0500 Subject: rtl8xxxu: Handle BT register writes and MP_OPER events 8723bu BT registers are written via the mailbox interface. Add support for writing these and corresponding C2H event responses. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 34 +++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 59 +++++++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 1f280930ad5c..ec03e912e82c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1531,6 +1531,27 @@ error: return retval; } +static void rtl8723bu_write_btreg(struct rtl8xxxu_priv *priv, u8 reg, u8 data) +{ + struct h2c_cmd h2c; + int reqnum = 0; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.bt_mp_oper.cmd = H2C_8723B_BT_MP_OPER; + h2c.bt_mp_oper.operreq = 0 | (reqnum << 4); + h2c.bt_mp_oper.opcode = BT_MP_OP_WRITE_REG_VALUE; + h2c.bt_mp_oper.data = data; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_mp_oper)); + + reqnum++; + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.bt_mp_oper.cmd = H2C_8723B_BT_MP_OPER; + h2c.bt_mp_oper.operreq = 0 | (reqnum << 4); + h2c.bt_mp_oper.opcode = BT_MP_OP_WRITE_REG_VALUE; + h2c.bt_mp_oper.addr = reg; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_mp_oper)); +} + static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv) { u8 val8; @@ -5646,6 +5667,8 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_IQADJ_G1, 0x780); + rtl8723bu_write_btreg(priv, 0x3c, 0x15); /* BT TRx Mask on */ + /* * Set BT grant to low */ @@ -6824,8 +6847,9 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, len = skb->len - 2; - pr_info("%s: C2H ID %02x seq %02x, len %02x %02x\n", __func__, - c2h->id, c2h->seq, len, c2h->bt_info.response_source); + dev_info(dev, "%s: C2H ID %02x seq %02x, len %02x source %02x\n", + __func__, + c2h->id, c2h->seq, len, c2h->bt_info.response_source); switch(c2h->id) { case C2H_8723B_BT_INFO: @@ -6837,8 +6861,14 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, if (c2h->bt_info.bt_has_reset) dev_info(dev, "BT has been reset\n"); + if (c2h->bt_info.tx_rx_mask) + dev_info(dev, "BT TRx mask\n"); break; + case C2H_8723B_BT_MP_INFO: + dev_info(dev, "C2H_MP_INFO ext ID %02x, status %02x\n", + c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); + break; default: pr_info("%s: Unhandled C2H event %02x\n", __func__, c2h->id); break; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index e4d5c4b29e3a..3e4e355ce2e2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -879,6 +879,13 @@ struct h2c_cmd { u8 data4; u8 data5; } __packed b_type_dma; + struct { + u8 cmd; + u8 operreq; + u8 opcode; + u8 data; + u8 addr; + } __packed bt_mp_oper; struct { u8 cmd; u8 data; @@ -908,8 +915,8 @@ enum c2h_evt_8723b { C2H_8723B_BT_OP_MODE = 5, C2H_8723B_EXT_RA_RPT = 6, C2H_8723B_BT_INFO = 9, - C2H_8723B_HW_INFO_EXCH = 10, - C2H_8723B_BT_MP_INFO = 11, + C2H_8723B_HW_INFO_EXCH = 0x0a, + C2H_8723B_BT_MP_INFO = 0x0b, C2H_8723B_FW_DEBUG = 0xff, }; @@ -919,6 +926,46 @@ enum bt_info_src_8723b { BT_INFO_SRC_8723B_BT_ACTIVE_SEND = 0x2, }; +enum bt_mp_oper_opcode_8723b { + BT_MP_OP_GET_BT_VERSION = 0x00, + BT_MP_OP_RESET = 0x01, + BT_MP_OP_TEST_CTRL = 0x02, + BT_MP_OP_SET_BT_MODE = 0x03, + BT_MP_OP_SET_CHNL_TX_GAIN = 0x04, + BT_MP_OP_SET_PKT_TYPE_LEN = 0x05, + BT_MP_OP_SET_PKT_CNT_L_PL_TYPE = 0x06, + BT_MP_OP_SET_PKT_CNT_H_PKT_INTV = 0x07, + BT_MP_OP_SET_PKT_HEADER = 0x08, + BT_MP_OP_SET_WHITENCOEFF = 0x09, + BT_MP_OP_SET_BD_ADDR_L = 0x0a, + BT_MP_OP_SET_BD_ADDR_H = 0x0b, + BT_MP_OP_WRITE_REG_ADDR = 0x0c, + BT_MP_OP_WRITE_REG_VALUE = 0x0d, + BT_MP_OP_GET_BT_STATUS = 0x0e, + BT_MP_OP_GET_BD_ADDR_L = 0x0f, + BT_MP_OP_GET_BD_ADDR_H = 0x10, + BT_MP_OP_READ_REG = 0x11, + BT_MP_OP_SET_TARGET_BD_ADDR_L = 0x12, + BT_MP_OP_SET_TARGET_BD_ADDR_H = 0x13, + BT_MP_OP_SET_TX_POWER_CALIBRATION = 0x14, + BT_MP_OP_GET_RX_PKT_CNT_L = 0x15, + BT_MP_OP_GET_RX_PKT_CNT_H = 0x16, + BT_MP_OP_GET_RX_ERROR_BITS_L = 0x17, + BT_MP_OP_GET_RX_ERROR_BITS_H = 0x18, + BT_MP_OP_GET_RSSI = 0x19, + BT_MP_OP_GET_CFO_HDR_QUALITY_L = 0x1a, + BT_MP_OP_GET_CFO_HDR_QUALITY_H = 0x1b, + BT_MP_OP_GET_TARGET_BD_ADDR_L = 0x1c, + BT_MP_OP_GET_TARGET_BD_ADDR_H = 0x1d, + BT_MP_OP_GET_AFH_MAP_L = 0x1e, + BT_MP_OP_GET_AFH_MAP_M = 0x1f, + BT_MP_OP_GET_AFH_MAP_H = 0x20, + BT_MP_OP_GET_AFH_STATUS = 0x21, + BT_MP_OP_SET_TRACKING_INTERVAL = 0x22, + BT_MP_OP_SET_THERMAL_METER = 0x23, + BT_MP_OP_ENABLE_CFO_TRACKING = 0x24, +}; + struct rtl8723bu_c2h { u8 id; u8 seq; @@ -926,6 +973,14 @@ struct rtl8723bu_c2h { struct { u8 payload[0]; } __packed raw; + struct { + u8 ext_id; + u8 status:4; + u8 retlen:4; + u8 opcode_ver:4; + u8 req_num:4; + u8 payload[2]; + } __packed bt_mp_info; struct { u8 response_source:4; u8 dummy0_0:4; -- cgit v1.2.3 From 6b9eae0129f43b8e691cec91a99601b0829fb841 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:50 -0500 Subject: rtl8xxxu: Issue BT_INFO command Issue a BT_INFO command to verify the status of BT/WiFi settings. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 18 +++++++++++------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++++ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ec03e912e82c..9b5b768ee33b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5727,20 +5727,25 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) */ rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00); - memset(&h2c, 0, sizeof(struct h2c_cmd)); - h2c.ignore_wlan.cmd = H2C_8723B_BT_IGNORE_WLANACT; - h2c.ignore_wlan.data = 0; - rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ignore_wlan)); - /* * Software control, antenna at WiFi side */ rtl8723bu_set_ps_tdma(priv, 0x08, 0x00, 0x00, 0x00, 0x00); + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.bt_info.cmd = H2C_8723B_BT_INFO; + h2c.bt_info.data = BIT(0); + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_info)); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE4, 0x00000003); + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.ignore_wlan.cmd = H2C_8723B_BT_IGNORE_WLANACT; + h2c.ignore_wlan.data = 0; + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ignore_wlan)); } static int rtl8xxxu_init_device(struct ieee80211_hw *hw) @@ -6847,8 +6852,7 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, len = skb->len - 2; - dev_info(dev, "%s: C2H ID %02x seq %02x, len %02x source %02x\n", - __func__, + dev_info(dev, "C2H ID %02x seq %02x, len %02x source %02x\n", c2h->id, c2h->seq, len, c2h->bt_info.response_source); switch(c2h->id) { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 3e4e355ce2e2..ea0b28a9a519 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -879,6 +879,10 @@ struct h2c_cmd { u8 data4; u8 data5; } __packed b_type_dma; + struct { + u8 cmd; + u8 data; + } __packed bt_info; struct { u8 cmd; u8 operreq; -- cgit v1.2.3 From 04313eb4f2225cb5dba2fffdb0f5f1abd71e611d Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:51 -0500 Subject: rtl8xxxu: Do not set REG_AFE_XTAL_CTRL on 8723bu The 8723bu does not like REG_AFE_XTAL_CTRL being set, so skip this for now, to match the vendor driver. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 9b5b768ee33b..a41f7f0e5b0b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2998,6 +2998,7 @@ static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv, static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) { u8 val8, ldoa15, ldov12d, lpldo, ldohci12; + u16 val16; u32 val32; /* @@ -3018,16 +3019,18 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) udelay(2); } - val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); - val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; - rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); - /* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */ - val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); - val32 &= ~AFE_XTAL_RF_GATE; - if (priv->has_bluetooth) - val32 &= ~AFE_XTAL_BT_GATE; - rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + if (priv->rtlchip != 0x8723b) { + /* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */ + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + val32 &= ~AFE_XTAL_RF_GATE; + if (priv->has_bluetooth) + val32 &= ~AFE_XTAL_BT_GATE; + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + } /* 6. 0x1f[7:0] = 0x07 */ val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB; -- cgit v1.2.3 From 42836db1f609b66fdb1b307243fa01451748ab68 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:52 -0500 Subject: rtl8xxxu: Implement 8723bu power on sequence This implements the 8723bu specific power on sequence as it is different from that of the 8723au chips. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 183 ++++++++++++++++++++- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 11 ++ 2 files changed, 189 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index a41f7f0e5b0b..1f30b3bb5daf 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2933,10 +2933,6 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv) val32 &= 0xffffff00; val32 |= 0x77; rtl8xxxu_write32(priv, 0x0930, val32); - - val32 = rtl8xxxu_read32(priv, REG_PWR_DATA); - val32 |= BIT(11); - rtl8xxxu_write32(priv, REG_PWR_DATA, val32); } static int @@ -5359,6 +5355,127 @@ exit: return ret; } +static int rtl8723b_emu_to_active(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u32 val32; + int count, ret = 0; + + /* 0x20[0] = 1 enable LDOA12 MACRO block for all interface */ + val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL); + val8 |= LDOA15_ENABLE; + rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8); + + /* 0x67[0] = 0 to disable BT_GPS_SEL pins*/ + val8 = rtl8xxxu_read8(priv, 0x0067); + val8 &= ~BIT(4); + rtl8xxxu_write8(priv, 0x0067, val8); + + mdelay(1); + + /* 0x00[5] = 0 release analog Ips to digital, 1:isolation */ + val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL); + val8 &= ~SYS_ISO_ANALOG_IPS; + rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8); + + /* Disable SW LPS 0x04[10]= 0 */ + val32 = rtl8xxxu_read8(priv, REG_APS_FSMCO); + val32 &= ~APS_FSMCO_SW_LPS; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + /* Wait until 0x04[17] = 1 power ready */ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if (val32 & BIT(17)) + break; + + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* We should be able to optimize the following three entries into one */ + + /* Release WLON reset 0x04[16]= 1*/ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 |= APS_FSMCO_WLON_RESET; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + /* Disable HWPDN 0x04[15]= 0*/ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 &= ~APS_FSMCO_HW_POWERDOWN; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + /* Disable WL suspend*/ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE); + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + /* Set, then poll until 0 */ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 |= APS_FSMCO_MAC_ENABLE; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) { + ret = 0; + break; + } + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* Enable WL control XTAL setting */ + val8 = rtl8xxxu_read8(priv, REG_AFE_MISC); + val8 |= AFE_MISC_WL_XTAL_CTRL; + rtl8xxxu_write8(priv, REG_AFE_MISC, val8); + + /* Enable falling edge triggering interrupt */ + val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 1); + val8 |= BIT(1); + rtl8xxxu_write8(priv, REG_GPIO_INTM + 1, val8); + + /* Enable GPIO9 interrupt mode */ + val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL_2 + 1); + val8 |= BIT(1); + rtl8xxxu_write8(priv, REG_GPIO_IO_SEL_2 + 1, val8); + + /* Enable GPIO9 input mode */ + val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL_2); + val8 &= ~BIT(1); + rtl8xxxu_write8(priv, REG_GPIO_IO_SEL_2, val8); + + /* Enable HSISR GPIO[C:0] interrupt */ + val8 = rtl8xxxu_read8(priv, REG_HSIMR); + val8 |= BIT(0); + rtl8xxxu_write8(priv, REG_HSIMR, val8); + + /* Enable HSISR GPIO9 interrupt */ + val8 = rtl8xxxu_read8(priv, REG_HSIMR + 2); + val8 |= BIT(1); + rtl8xxxu_write8(priv, REG_HSIMR + 2, val8); + + val8 = rtl8xxxu_read8(priv, REG_MULTI_FUNC_CTRL); + val8 |= MULTI_WIFI_HW_ROF_EN; + rtl8xxxu_write8(priv, REG_MULTI_FUNC_CTRL, val8); + + /* For GPIO9 internal pull high setting BIT(14) */ + val8 = rtl8xxxu_read8(priv, REG_MULTI_FUNC_CTRL + 1); + val8 |= BIT(6); + rtl8xxxu_write8(priv, REG_MULTI_FUNC_CTRL + 1, val8); + +exit: + return ret; +} + static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv) { u8 val8; @@ -5430,6 +5547,62 @@ exit: return ret; } +static int rtl8723bu_power_on(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + u32 val32; + int ret; + + rtl8723a_disabled_to_emu(priv); + + ret = rtl8723b_emu_to_active(priv); + if (ret) + goto exit; + + /* + * Enable MAC DMA/WMAC/SCHEDULE/SEC block + * Set CR bit10 to enable 32k calibration. + */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | + CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE | + CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE | + CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + + /* + * BT coexist power on settings. This is identical for 1 and 2 + * antenna parts. + */ + rtl8xxxu_write8(priv, REG_PAD_CTRL1 + 3, 0x20); + + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 |= SYS_FUNC_BBRSTB | SYS_FUNC_BB_GLB_RSTN; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + rtl8xxxu_write8(priv, REG_BT_CONTROL_8723BU + 1, 0x18); + rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x04); + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00); + /* Antenna inverse */ + rtl8xxxu_write8(priv, 0xfe08, 0x01); + + val16 = rtl8xxxu_read16(priv, REG_PWR_DATA); + val16 |= PWR_DATA_EEPRPAD_RFE_CTRL_EN; + rtl8xxxu_write16(priv, REG_PWR_DATA, val16); + + val32 = rtl8xxxu_read32(priv, REG_LEDCFG0); + val32 |= LEDCFG0_DPDT_SELECT; + rtl8xxxu_write32(priv, REG_LEDCFG0, val32); + + val8 = rtl8xxxu_read8(priv, REG_PAD_CTRL1); + val8 &= ~PAD_CTRL1_SW_DPDT_SEL_DATA; + rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8); +exit: + return ret; +} + #ifdef CONFIG_RTL8XXXU_UNTESTED static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv) @@ -7707,7 +7880,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { static struct rtl8xxxu_fileops rtl8723bu_fops = { .parse_efuse = rtl8723bu_parse_efuse, .load_firmware = rtl8723bu_load_firmware, - .power_on = rtl8723au_power_on, + .power_on = rtl8723bu_power_on, .llt_init = rtl8xxxu_auto_llt_table, .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index a82c0ba7931d..5250388b0275 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -70,6 +70,8 @@ #define REG_EE_VPD 0x000c #define REG_AFE_MISC 0x0010 +#define AFE_MISC_WL_XTAL_CTRL BIT(6) + #define REG_SPS0_CTRL 0x0011 #define REG_SPS_OCP_CFG 0x0018 #define REG_8192E_LDOV12_CTRL 0x0014 @@ -133,6 +135,8 @@ #define EFUSE_ACCESS_DISABLE 0x00 /* RTL8723 only */ #define REG_PWR_DATA 0x0038 +#define PWR_DATA_EEPRPAD_RFE_CTRL_EN BIT(11) + #define REG_CAL_TIMER 0x003c #define REG_ACLK_MON 0x003e #define REG_GPIO_MUXCFG 0x0040 @@ -140,7 +144,10 @@ #define REG_MAC_PINMUX_CFG 0x0043 #define REG_GPIO_PIN_CTRL 0x0044 #define REG_GPIO_INTM 0x0048 +#define GPIO_INTM_EDGE_TRIG_IRQ BIT(9) + #define REG_LEDCFG0 0x004c +#define LEDCFG0_DPDT_SELECT BIT(23) #define REG_LEDCFG1 0x004d #define REG_LEDCFG2 0x004e #define LEDCFG2_DPDT_SELECT BIT(7) @@ -154,9 +161,13 @@ #define REG_GPIO_PIN_CTRL_2 0x0060 /* RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */ #define REG_GPIO_IO_SEL_2 0x0062 +#define GPIO_IO_SEL_2_GPIO09_INPUT BIT(1) +#define GPIO_IO_SEL_2_GPIO09_IRQ BIT(9) /* RTL8723B */ #define REG_PAD_CTRL1 0x0064 +#define PAD_CTRL1_SW_DPDT_SEL_DATA BIT(0) + /* RTL8723 only WIFI/BT/GPS Multi-Function control source. */ #define REG_MULTI_FUNC_CTRL 0x0068 -- cgit v1.2.3 From 79fb5fe9edb78bd28969dd0f6bacc8c12550c4cc Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:53 -0500 Subject: rtl8xxxu: Setup LLT before downloading firmware This matches the order of the 8723bu vendor driver Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 29 ++++++++++++++++-------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 1f30b3bb5daf..e836382e41c4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5955,6 +5955,26 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); if (!macpower) { + ret = priv->fops->llt_init(priv, TX_TOTAL_PAGE_NUM); + if (ret) { + dev_warn(dev, "%s: LLT table init failed\n", __func__); + goto exit; + } + + /* + * Presumably this is for 8188EU as well + * Enable TX report and TX report timer + */ + if (priv->rtlchip == 0x8723bu) { + val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); + val8 |= BIT(1); + rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); + /* Set MAX RPT MACID */ + rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1, 0x02); + /* TX report Timer. Unit: 32us */ + rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, 0xcdf0); + } + if (priv->ep_tx_normal_queue) val8 = TX_PAGE_NUM_NORM_PQ; else @@ -5996,15 +6016,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (ret) goto exit; - dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); - if (!macpower) { - ret = priv->fops->llt_init(priv, TX_TOTAL_PAGE_NUM); - if (ret) { - dev_warn(dev, "%s: LLT table init failed\n", __func__); - goto exit; - } - } - /* Fix USB interface interference issue */ if (priv->rtlchip == 0x8723a) { rtl8xxxu_write8(priv, 0xfe40, 0xe0); -- cgit v1.2.3 From 8baf670b8928893bacf95a67c86ec2d6c42263f2 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:54 -0500 Subject: rtl8xxxu: Additional fixes for 8723bu Additional tweaks to further map the init sequence for the 8723bu to that of the vendor driver. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 25 +++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e836382e41c4..e879fe28a99b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2957,7 +2957,8 @@ rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array) } } - rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a); + if (priv->rtlchip != 0x8723b) + rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a); return 0; } @@ -3003,6 +3004,11 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) */ if (priv->rtlchip == 0x8723b) { + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB | + SYS_FUNC_DIO_RF; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00); } else { val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL); @@ -3013,11 +3019,11 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff); udelay(2); - } - val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); - val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; - rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + } if (priv->rtlchip != 0x8723b) { /* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */ @@ -3036,9 +3042,14 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table); else if (priv->tx_paths == 2) rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table); - else if (priv->rtlchip == 0x8723b) + else if (priv->rtlchip == 0x8723b) { + /* + * Why? + */ + rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xe3); + rtl8xxxu_write8(priv, REG_AFE_XTAL_CTRL + 1, 0x80); rtl8xxxu_init_phy_regs(priv, rtl8723b_phy_1t_init_table); - else + } else rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table); -- cgit v1.2.3 From 4ef22eb933c21f307413f9fc402f83e7384cf726 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:55 -0500 Subject: rtl8xxxu: Handle XTAL_K value in efuse specific location Retrieve the XTAL_K value in the parse_efuse() functions as it's location various on a per device basis. For parts that do not provide an XTAL_K value, skip setting it. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 15 ++++++++++++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e879fe28a99b..7f69a1b6980d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2314,6 +2314,10 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) efuse->ht20_max_power_offset, sizeof(priv->ht20_max_power_offset)); + if (priv->efuse_wifi.efuse8723.version >= 0x01) { + priv->has_xtalk = 1; + priv->xtalk = priv->efuse_wifi.efuse8723.xtal_k & 0x3f; + } dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.41s\n", @@ -2340,6 +2344,9 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, sizeof(priv->ht40_1s_tx_power_index_B)); + priv->has_xtalk = 1; + priv->xtalk = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f; + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.41s\n", efuse->device_name); @@ -2444,6 +2451,9 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) ether_addr_copy(priv->mac_addr, efuse->mac_addr); + priv->has_xtalk = 1; + priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f; + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); @@ -3122,11 +3132,10 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) else rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table); - if ((priv->rtlchip == 0x8723a || priv->rtlchip == 0x8723b) && - priv->efuse_wifi.efuse8723.version >= 0x01) { + if (priv->has_xtalk) { val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL); - val8 = priv->efuse_wifi.efuse8723.xtal_k & 0x3f; + val8 = priv->xtalk; val32 &= 0xff000fff; val32 |= ((val8 | (val8 << 6)) << 12); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index ea0b28a9a519..2250e1b17d60 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1063,6 +1063,8 @@ struct rtl8xxxu_priv { u32 ep_tx_high_queue:1; u32 ep_tx_normal_queue:1; u32 ep_tx_low_queue:1; + u32 has_xtalk:1; + u8 xtalk; unsigned int pipe_interrupt; unsigned int pipe_in; unsigned int pipe_out[TXDESC_QUEUE_MAX]; -- cgit v1.2.3 From a0e262bcbe71892c88abb12b6d409553863efacc Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:56 -0500 Subject: rtl8xxxu: Another 8723bu patch for rtl8xxxu_init_phy_bb() This function is going to need to be split up into chip specific variants. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 7f69a1b6980d..3f742b74f293 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -3142,13 +3142,16 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32); } - ldoa15 = LDOA15_ENABLE | LDOA15_OBUF; - ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT); - ldohci12 = 0x57; - lpldo = 1; - val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15; + if (priv->rtlchip != 0x8723bu) { + ldoa15 = LDOA15_ENABLE | LDOA15_OBUF; + ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT); + ldohci12 = 0x57; + lpldo = 1; + val32 = (lpldo << 24) | (ldohci12 << 16) | + (ldov12d << 8) | ldoa15; - rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32); + rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32); + } return 0; } -- cgit v1.2.3 From 360157eb25d4088c28ff114a613d2c95b61e93f4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:57 -0500 Subject: rtl8xxxu: Another 8723bu magic register set during init No indication of what register 0xa3 does anywhere in the vendor source. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 3f742b74f293..f5f38a51486f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5996,6 +5996,11 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1, 0x02); /* TX report Timer. Unit: 32us */ rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, 0xcdf0); + + /* tmp ps ? */ + val8 = rtl8xxxu_read8(priv, 0xa3); + val8 &= 0xf8; + rtl8xxxu_write8(priv, 0xa3, val8); } if (priv->ep_tx_normal_queue) -- cgit v1.2.3 From 3a4be6a092c89ad7a94b147c3529d6626e5a59ff Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:58 -0500 Subject: rtl8xxxu: Init H2C command register for 8723bu In addition make register read/write flow match closer to vendor driver flow. This is mainly to be able to compare the register write log with the vendor driver, and can be optimized later once 8723bu support is working. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index f5f38a51486f..1d0869b55c64 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2685,6 +2685,11 @@ static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv) goto exit; } + /* + * Init H2C command + */ + if (priv->rtlchip == 0x8723b) + rtl8xxxu_write8(priv, REG_HMTFR, 0x0f); exit: return ret; } @@ -2927,14 +2932,20 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv) val32 = rtl8xxxu_read32(priv, REG_GPIO_MUXCFG); val32 &= ~BIT(4); + rtl8xxxu_write32(priv, REG_GPIO_MUXCFG, val32); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_MUXCFG); val32 |= BIT(3); rtl8xxxu_write32(priv, REG_GPIO_MUXCFG, val32); val32 = rtl8xxxu_read32(priv, REG_LEDCFG0); - val32 &= ~BIT(23); val32 |= BIT(24); rtl8xxxu_write32(priv, REG_LEDCFG0, val32); + val32 = rtl8xxxu_read32(priv, REG_LEDCFG0); + val32 &= ~BIT(23); + rtl8xxxu_write32(priv, REG_LEDCFG0, val32); + val32 = rtl8xxxu_read32(priv, 0x0944); val32 |= (BIT(0) | BIT(1)); rtl8xxxu_write32(priv, 0x0944, val32); @@ -2943,6 +2954,10 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv) val32 &= 0xffffff00; val32 |= 0x77; rtl8xxxu_write32(priv, 0x0930, val32); + + val32 = rtl8xxxu_read32(priv, REG_PWR_DATA); + val32 |= PWR_DATA_EEPRPAD_RFE_CTRL_EN; + rtl8xxxu_write32(priv, REG_PWR_DATA, val32); } static int @@ -6079,7 +6094,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, 0xfe42, 0x80); } - if (priv->rtlchip == 0x8192e || priv->rtlchip == 0x8723b) { + if (priv->rtlchip == 0x8192e) { rtl8xxxu_write32(priv, REG_HIMR0, 0x00); rtl8xxxu_write32(priv, REG_HIMR1, 0x00); } -- cgit v1.2.3 From f30ed675545dd4b9f32d3d674054b6024b413f1d Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:04:59 -0500 Subject: rtl8xxxu: 80M spur hack is for 8723au only Only apply the 80M spur hack for 8723au parts. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 1d0869b55c64..9ba4cadd1549 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6151,11 +6151,12 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (ret) goto exit; - /* Reduce 80M spur */ - rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d); - rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); - rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82); - rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); + if (priv->rtlchip == 0x8723a) { /* Reduce 80M spur */ + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); + } /* RFSW Control - clear bit 14 ?? */ rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); -- cgit v1.2.3 From 1f1b20f11ab4ce38a338b278bb6b538bbfdc831a Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:00 -0500 Subject: rtl8xxxu: Do queue init in same order as 8723bu vendor driver Reorganize the init sequence in order to be able to compare to the 8723bu vendor driver's init sequence. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 68 +++++++++++++----------- 1 file changed, 37 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 9ba4cadd1549..27fb89fe99ec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6017,32 +6017,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val8 &= 0xf8; rtl8xxxu_write8(priv, 0xa3, val8); } - - if (priv->ep_tx_normal_queue) - val8 = TX_PAGE_NUM_NORM_PQ; - else - val8 = 0; - - rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8); - - val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD; - - if (priv->ep_tx_high_queue) - val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT); - if (priv->ep_tx_low_queue) - val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT); - - rtl8xxxu_write32(priv, REG_RQPN, val32); - - /* - * Set TX buffer boundary - */ - val8 = TX_TOTAL_PAGE_NUM + 1; - rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8); - rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8); - rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8); - rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8); - rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8); } ret = rtl8xxxu_download_firmware(priv); @@ -6054,11 +6028,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (ret) goto exit; - ret = rtl8xxxu_init_queue_priority(priv); - dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret); - if (ret) - goto exit; - /* Fix USB interface interference issue */ if (priv->rtlchip == 0x8723a) { rtl8xxxu_write8(priv, 0xfe40, 0xe0); @@ -6158,6 +6127,43 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); } + if (!macpower){ + if (priv->ep_tx_normal_queue) + val8 = TX_PAGE_NUM_NORM_PQ; + else + val8 = 0; + + rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8); + + val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD; + + if (priv->ep_tx_high_queue) + val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT); + if (priv->ep_tx_low_queue) + val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT); + + rtl8xxxu_write32(priv, REG_RQPN, val32); + + /* + * Set TX buffer boundary + */ + val8 = TX_TOTAL_PAGE_NUM + 1; + + if (priv->rtlchip == 0x8723b) + val8 -= 1; + + rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8); + rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8); + rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8); + rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8); + rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8); + } + + ret = rtl8xxxu_init_queue_priority(priv); + dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret); + if (ret) + goto exit; + /* RFSW Control - clear bit 14 ?? */ rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); /* 0x07000760 */ -- cgit v1.2.3 From b87212ceceef655dae563efd2df13cb59dbd1711 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:01 -0500 Subject: rtl8xxxu: Do not set FPGA0_TX_INFO for 8723bu and use a larger PBP page size The vendor driver does not set FPGA0_TX_INFO here. In additiona the 8723bu can handler a larger PBP page size. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 27fb89fe99ec..bb43937788ce 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6165,7 +6165,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) goto exit; /* RFSW Control - clear bit 14 ?? */ - rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); + if (priv->rtlchip != 0x8723b) + rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); /* 0x07000760 */ val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE | @@ -6185,8 +6186,12 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* * Transfer page size is always 128 */ - val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) | - (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT); + if (priv->rtlchip == 0x8723b) + val8 = (PBP_PAGE_SIZE_256 << PBP_PAGE_SIZE_RX_SHIFT) | + (PBP_PAGE_SIZE_256 << PBP_PAGE_SIZE_TX_SHIFT); + else + val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) | + (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT); rtl8xxxu_write8(priv, REG_PBP, val8); /* -- cgit v1.2.3 From fadfa041546924c28ca2a3bf1ed8fd25686e8cf5 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:02 -0500 Subject: rtl8xxxu: Set RX boundary for 8723bu Set the correct TRXFF boundary for 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index bb43937788ce..6611128532f4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6182,7 +6182,10 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* * Set RX page boundary */ - rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff); + if (priv->rtlchip == 0x8723b) + rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x3f7f); + else + rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff); /* * Transfer page size is always 128 */ -- cgit v1.2.3 From c36906044104813304a9c40252f9b2a573ccd187 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:03 -0500 Subject: rtl8xxxu: Initialize burst parameters for 8723bu Implement burst parameter sequence for 8723bu parts. Eventually this should be moved into device specific sections. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 33 ++++++++++++++++++++++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 5 +++- 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 6611128532f4..631482555bee 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6278,6 +6278,39 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, REG_BEACON_DMA_TIME, BEACON_DMA_ATIME_INT_TIME); rtl8xxxu_write16(priv, REG_BEACON_TCFG, 0x660F); + /* + * Initialize burst parameters + */ + if (priv->rtlchip == 0x8723b) { + /* + * For USB high speed set 512B packets + */ + val8 = rtl8xxxu_read8(priv, REG_RXDMA_PRO_8723B); + val8 &= ~(BIT(4) | BIT(5)); + val8 |= BIT(4); + val8 |= BIT(1) | BIT(2) | BIT(3); + rtl8xxxu_write8(priv, REG_RXDMA_PRO_8723B, val8); + + /* + * For USB high speed set 512B packets + */ + val8 = rtl8xxxu_read8(priv, REG_HT_SINGLE_AMPDU_8723B); + val8 |= BIT(7); + rtl8xxxu_write8(priv, REG_HT_SINGLE_AMPDU_8723B, val8); + + rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, 0x0c14); + rtl8xxxu_write8(priv, REG_AMPDU_MAX_TIME_8723B, 0x5e); + rtl8xxxu_write32(priv, REG_AGGLEN_LMT, 0xffffffff); + rtl8xxxu_write8(priv, REG_RX_PKT_LIMIT, 0x18); + rtl8xxxu_write8(priv, REG_PIFS, 0x00); + rtl8xxxu_write8(priv, REG_USTIME_TSF_8723B, 0x50); + rtl8xxxu_write8(priv, REG_USTIME_EDCA, 0x50); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL); + val8 |= BIT(5) | BIT(6); + rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); + } + /* * Enable CCK and OFDM block */ diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 5250388b0275..8209830848d6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -405,7 +405,7 @@ /* Presumably only found on newer chips such as 8723bu */ #define REG_RX_DMA_CTRL_8723B 0x0286 -#define REG_RX_DMA_MODE_CTRL_8723B 0x0290 +#define REG_RXDMA_PRO_8723B 0x0290 #define REG_RF_BB_CMD_ADDR 0x02c0 #define REG_RF_BB_CMD_DATA 0x02c4 @@ -478,6 +478,7 @@ #define REG_ARFR1 0x0448 #define REG_ARFR2 0x044c #define REG_ARFR3 0x0450 +#define REG_AMPDU_MAX_TIME_8723B 0x0456 #define REG_AGGLEN_LMT 0x0458 #define REG_AMPDU_MIN_SPACE 0x045c #define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045d @@ -496,6 +497,7 @@ #define REG_PKT_VO_VI_LIFE_TIME 0x04c0 #define REG_PKT_BE_BK_LIFE_TIME 0x04c2 #define REG_STBC_SETTING 0x04c4 +#define REG_HT_SINGLE_AMPDU_8723B 0x04c7 #define REG_PROT_MODE_CTRL 0x04c8 #define REG_MAX_AGGR_NUM 0x04ca #define REG_RTS_MAX_AGGR_NUM 0x04cb @@ -560,6 +562,7 @@ #define BEACON_DMA_ATIME_INT_TIME 2 #define REG_ATIMWND 0x055a +#define REG_USTIME_TSF_8723B 0x055c #define REG_BCN_MAX_ERR 0x055d #define REG_RXTSF_OFFSET_CCK 0x055e #define REG_RXTSF_OFFSET_OFDM 0x055f -- cgit v1.2.3 From 1ea8e846c9eab861db1108302a391182c3fce528 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:04 -0500 Subject: rtl8xxxu: Call device specific _config_channel() Having a version for the newer chips without calling it doesn't do much good..... Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 631482555bee..960e1acd6ad7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7348,7 +7348,7 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) rtl8723a_set_tx_power(priv, channel, ht40); - rtl8723au_config_channel(hw); + priv->fops->config_channel(hw); } exit: -- cgit v1.2.3 From 5ac61789e864ca7fbfe4425afe53837f535363cc Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:05 -0500 Subject: rtl8xxxu: 8723bu lock phy after RF init Set PHY lock after running the RF init sequence on 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 960e1acd6ad7..f20568b14c3b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6093,6 +6093,13 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) case 0x8723b: rftable = rtl8723bu_radioa_1t_init_table; ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); + /* + * PHY LCK + */ + rtl8xxxu_write_rfreg(priv, RF_A, 0xb0, 0xdfbe0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, 0x8c01); + msleep(200); + rtl8xxxu_write_rfreg(priv, RF_A, 0xb0, 0xdffe0); break; case 0x8188c: if (priv->hi_pa) -- cgit v1.2.3 From 7e9567ff98a6b7312a6eb1fe0f9c0f81b42147eb Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:06 -0500 Subject: rtl8xxxu: Add REG_DWBCN1_CTRL_8723B define List yet another new register found on the 8723b. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 8209830848d6..ec6f40f2dbc7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -397,6 +397,8 @@ #define REG_AUTO_LLT 0x0224 #define AUTO_LLT_INIT_LLT BIT(16) +#define REG_DWBCN1_CTRL_8723B 0x0228 + /* 0x0280 ~ 0x02FF RXDMA Configuration */ #define REG_RXDMA_AGG_PG_TH 0x0280 #define RXDMA_USB_AGG_ENABLE BIT(31) -- cgit v1.2.3 From 2f109c8e51d6302a18687c9381a62401d6b69f24 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:07 -0500 Subject: rtl8xxxu: Group chip quirks together Group chip quirks together instead of having them scattered all over in the init code. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 28 +++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index f20568b14c3b..ad6371985402 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6028,18 +6028,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (ret) goto exit; - /* Fix USB interface interference issue */ - if (priv->rtlchip == 0x8723a) { - rtl8xxxu_write8(priv, 0xfe40, 0xe0); - rtl8xxxu_write8(priv, 0xfe41, 0x8d); - rtl8xxxu_write8(priv, 0xfe42, 0x80); - rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320); - } else { - val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK); - val32 |= TXDMA_OFFSET_DROP_DATA_EN; - rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); - } - /* Solve too many protocol error on USB bus */ /* Can't do this for 8188/8192 UMC A cut parts */ if (priv->rtlchip == 0x8723a || @@ -6127,11 +6115,25 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (ret) goto exit; - if (priv->rtlchip == 0x8723a) { /* Reduce 80M spur */ + /* + * Chip specific quirks + */ + if (priv->rtlchip == 0x8723a) { + /* Fix USB interface interference issue */ + rtl8xxxu_write8(priv, 0xfe40, 0xe0); + rtl8xxxu_write8(priv, 0xfe41, 0x8d); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320); + + /* Reduce 80M spur */ rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d); rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82); rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); + } else { + val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK); + val32 |= TXDMA_OFFSET_DROP_DATA_EN; + rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); } if (!macpower){ -- cgit v1.2.3 From 3e88ca447a8a17e122ba58d79c725c63b3efcd70 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:08 -0500 Subject: rtl8xxxu: Setup RX aggregation This initializes RX DMA aggregation on 8723bu. We should do this for all parts eventually, and also init TX aggregation. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 23 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 1 + 3 files changed, 25 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ad6371985402..04dad19402e5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5962,6 +5962,25 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ignore_wlan)); } +static void rtl8723bu_init_aggregation(struct rtl8xxxu_priv *priv) +{ + u32 agg_rx; + u8 agg_ctrl; + + /* + * For now simply disable RX aggregation + */ + agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL); + agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN; + + agg_rx = rtl8xxxu_read32(priv, REG_RXDMA_AGG_PG_TH); + agg_rx &= ~RXDMA_USB_AGG_ENABLE; + agg_rx &= ~0xff0f; + + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); + rtl8xxxu_write32(priv, REG_RXDMA_AGG_PG_TH, agg_rx); +} + static int rtl8xxxu_init_device(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -6320,6 +6339,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); } + if (priv->fops->init_aggregation) + priv->fops->init_aggregation(priv); + /* * Enable CCK and OFDM block */ @@ -7998,6 +8020,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .config_channel = rtl8723bu_config_channel, .init_bt = rtl8723bu_init_bt, .parse_rx_desc = rtl8723bu_parse_rx_desc, + .init_aggregation = rtl8723bu_init_aggregation, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 2250e1b17d60..14b7a35bc05b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1133,6 +1133,7 @@ struct rtl8xxxu_fileops { void (*init_bt) (struct rtl8xxxu_priv *priv); int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb, struct ieee80211_rx_status *rx_status); + void (*init_aggregation) (struct rtl8xxxu_priv *priv); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index ec6f40f2dbc7..d6c7ad30a87b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -318,6 +318,7 @@ #define PBP_PAGE_SIZE_1024 0x4 #define REG_TRXDMA_CTRL 0x010c +#define TRXDMA_CTRL_RXDMA_AGG_EN BIT(2) #define TRXDMA_CTRL_VOQ_SHIFT 4 #define TRXDMA_CTRL_VIQ_SHIFT 6 #define TRXDMA_CTRL_BEQ_SHIFT 8 -- cgit v1.2.3 From f2a4163a22c66d178084ff722c490f5ecf91a088 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:09 -0500 Subject: rtl8xxxu: Add missing blank space in front of bracket Keep the automated tools happy Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 04dad19402e5..1fa0dbfdef84 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6155,7 +6155,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); } - if (!macpower){ + if (!macpower) { if (priv->ep_tx_normal_queue) val8 = TX_PAGE_NUM_NORM_PQ; else -- cgit v1.2.3 From 9c79bf95d08a920b1c1219a2a9d5fce2f6172bbe Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:10 -0500 Subject: rtl8xxxu: Implement init_statistics for 8723bu Vendor driver implements this for 8723b and 8821 series Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 27 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 7 ++++++ 3 files changed, 35 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 1fa0dbfdef84..6b6fa1f24696 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5981,6 +5981,29 @@ static void rtl8723bu_init_aggregation(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_RXDMA_AGG_PG_TH, agg_rx); } +static void rtl8723bu_init_statistics(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + /* Time duration for NHM unit: 4us, 0x2710=40ms */ + rtl8xxxu_write16(priv, REG_NHM_TIMER_8723B + 2, 0x2710); + rtl8xxxu_write16(priv, REG_NHM_TH9_TH10_8723B + 2, 0xffff); + rtl8xxxu_write32(priv, REG_NHM_TH3_TO_TH0_8723B, 0xffffff52); + rtl8xxxu_write32(priv, REG_NHM_TH7_TO_TH4_8723B, 0xffffffff); + /* TH8 */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + val32 |= 0xff; + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + /* Enable CCK */ + val32 = rtl8xxxu_read32(priv, REG_NHM_TH9_TH10_8723B); + val32 |= BIT(8) | BIT(9) | BIT(10); + rtl8xxxu_write32(priv, REG_NHM_TH9_TH10_8723B, val32); + /* Max power amongst all RX antennas */ + val32 = rtl8xxxu_read32(priv, REG_OFDM0_FA_RSTC); + val32 |= BIT(7); + rtl8xxxu_write32(priv, REG_OFDM0_FA_RSTC, val32); +} + static int rtl8xxxu_init_device(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -6371,6 +6394,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); + if (priv->fops->init_statistics) + priv->fops->init_statistics(priv); + rtl8723a_phy_lc_calibrate(priv); priv->fops->phy_iq_calibrate(priv); @@ -8021,6 +8047,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .init_bt = rtl8723bu_init_bt, .parse_rx_desc = rtl8723bu_parse_rx_desc, .init_aggregation = rtl8723bu_init_aggregation, + .init_statistics = rtl8723bu_init_statistics, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 14b7a35bc05b..b75678b9b60d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1134,6 +1134,7 @@ struct rtl8xxxu_fileops { int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb, struct ieee80211_rx_status *rx_status); void (*init_aggregation) (struct rtl8xxxu_priv *priv); + void (*init_statistics) (struct rtl8xxxu_priv *priv); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index d6c7ad30a87b..d3f6fa376625 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -833,6 +833,11 @@ #define REG_FPGA0_ANALOG3 0x0888 #define REG_FPGA0_ANALOG4 0x088c +#define REG_NHM_TH9_TH10_8723B 0x0890 +#define REG_NHM_TIMER_8723B 0x0894 +#define REG_NHM_TH3_TO_TH0_8723B 0x0898 +#define REG_NHM_TH7_TO_TH4_8723B 0x089c + #define REG_FPGA0_XA_LSSI_READBACK 0x08a0 /* Tranceiver LSSI Readback */ #define REG_FPGA0_XB_LSSI_READBACK 0x08a4 #define REG_HSPI_XA_READBACK 0x08b8 /* Transceiver A HSPI read */ @@ -869,6 +874,8 @@ #define REG_OFDM0_TR_MUX_PAR 0x0c08 +#define REG_OFDM0_FA_RSTC 0x0c0c + #define REG_OFDM0_XA_RX_IQ_IMBALANCE 0x0c14 #define REG_OFDM0_XB_RX_IQ_IMBALANCE 0x0c1c -- cgit v1.2.3 From 541bca7f5d8ffbd4dba8b432f3a5162cb7ba41a6 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:11 -0500 Subject: rtl8xxxu: RF_T_METER is different on the newer chips Provide RF_T_METER register location for nextgen chips. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index d3f6fa376625..a055362471e5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -1104,9 +1104,10 @@ /* * NextGen regs: 8723BU */ -#define RF6052_REG_UNKNOWN_43 0x43 -#define RF6052_REG_UNKNOWN_55 0x55 -#define RF6052_REG_S0S1 0xb0 -#define RF6052_REG_UNKNOWN_DF 0xdf -#define RF6052_REG_UNKNOWN_ED 0xed -#define RF6052_REG_WE_LUT 0xef +#define RF6052_REG_T_METER_8723B 0x42 +#define RF6052_REG_UNKNOWN_43 0x43 +#define RF6052_REG_UNKNOWN_55 0x55 +#define RF6052_REG_S0S1 0xb0 +#define RF6052_REG_UNKNOWN_DF 0xdf +#define RF6052_REG_UNKNOWN_ED 0xed +#define RF6052_REG_WE_LUT 0xef -- cgit v1.2.3 From fc1c89b3407fe0b3ebc8fa651332a62ed773872d Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:12 -0500 Subject: rtl8xxxu: Set WLAN_ACT_CONTROL per vendor driver setting The initial code set the wrong setting in WLAN_ACT_CONTROL for the 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 6b6fa1f24696..52c75675d3b2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5894,7 +5894,7 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) /* * WLAN action by PTA */ - rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x0c); + rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x04); /* * BT select S0/S1 controlled by WiFi -- cgit v1.2.3 From 499cfc02a08a27ba29d22938ddbe5140806316c5 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:13 -0500 Subject: rtl8xxxu: 8723bu: REG_BT_COEX_TABLE4 is only 8 bits The BT_COEX_TABLE register list contains 3 32 bit registers and one 8 bit register. Hence, use rtl8xxxu_write8() when writing the 8 bit register. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 52c75675d3b2..47d85d57a175 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5954,7 +5954,7 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); - rtl8xxxu_write32(priv, REG_BT_COEX_TABLE4, 0x00000003); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); memset(&h2c, 0, sizeof(struct h2c_cmd)); h2c.ignore_wlan.cmd = H2C_8723B_BT_IGNORE_WLANACT; -- cgit v1.2.3 From 120e627f658b3fe2be2f3699527dd687168b3693 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:14 -0500 Subject: rtl8xxxu: Use name for REG_RFE_BUFFER rather than hard coded value Register 0x0944 is REG_RFE_BUFFER. Use the name rather than hard coded value when accessing it. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 47d85d57a175..3764f3e1b3dd 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2946,9 +2946,9 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv) val32 &= ~BIT(23); rtl8xxxu_write32(priv, REG_LEDCFG0, val32); - val32 = rtl8xxxu_read32(priv, 0x0944); + val32 = rtl8xxxu_read32(priv, REG_RFE_BUFFER); val32 |= (BIT(0) | BIT(1)); - rtl8xxxu_write32(priv, 0x0944, val32); + rtl8xxxu_write32(priv, REG_RFE_BUFFER, val32); val32 = rtl8xxxu_read32(priv, 0x0930); val32 &= 0xffffff00; @@ -5912,9 +5912,9 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) */ rtl8xxxu_write8(priv, 0x0974, 0xff); - val32 = rtl8xxxu_read32(priv, 0x0944); + val32 = rtl8xxxu_read32(priv, REG_RFE_BUFFER); val32 |= (BIT(0) | BIT(1)); - rtl8xxxu_write32(priv, 0x0944, val32); + rtl8xxxu_write32(priv, REG_RFE_BUFFER, val32); rtl8xxxu_write8(priv, REG_RFE_CTRL_ANTA_SRC, 0x77); -- cgit v1.2.3 From 59b743979c178b780bc57f179493fdbf3ad4f0b7 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:15 -0500 Subject: rtl8xxxu: Use REG_RFE_CTRL_ANTA_SRC rather than hard coded value Another case where we should use the register name rather than the hard coded value when accessing it. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 3764f3e1b3dd..5b74ba114d53 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2950,10 +2950,10 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv) val32 |= (BIT(0) | BIT(1)); rtl8xxxu_write32(priv, REG_RFE_BUFFER, val32); - val32 = rtl8xxxu_read32(priv, 0x0930); + val32 = rtl8xxxu_read32(priv, REG_RFE_CTRL_ANTA_SRC); val32 &= 0xffffff00; val32 |= 0x77; - rtl8xxxu_write32(priv, 0x0930, val32); + rtl8xxxu_write32(priv, REG_RFE_CTRL_ANTA_SRC, val32); val32 = rtl8xxxu_read32(priv, REG_PWR_DATA); val32 |= PWR_DATA_EEPRPAD_RFE_CTRL_EN; -- cgit v1.2.3 From a3a5dac6b1bf69b1d90f3293abfb4392ec2fc68f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:16 -0500 Subject: rtl8xxxu: Setup coex table correctly (hopefully) Use the same values as the vendor driver when setting up the BTCOEX table for 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 5b74ba114d53..3e99a17c7962 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5842,6 +5842,7 @@ static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); } +#ifdef NEED_PS_TDMA static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) { @@ -5856,6 +5857,7 @@ static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, h2c.b_type_dma.data5 = arg5; rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma)); } +#endif static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) { @@ -5944,18 +5946,20 @@ static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) /* * Software control, antenna at WiFi side */ +#ifdef NEED_PS_TDMA rtl8723bu_set_ps_tdma(priv, 0x08, 0x00, 0x00, 0x00, 0x00); +#endif + + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); memset(&h2c, 0, sizeof(struct h2c_cmd)); h2c.bt_info.cmd = H2C_8723B_BT_INFO; h2c.bt_info.data = BIT(0); rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_info)); - rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); - rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); - rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); - rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); - memset(&h2c, 0, sizeof(struct h2c_cmd)); h2c.ignore_wlan.cmd = H2C_8723B_BT_IGNORE_WLANACT; h2c.ignore_wlan.data = 0; -- cgit v1.2.3 From db08de9443be5d4eef724621d3d51cab4daf25d3 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:17 -0500 Subject: rtl8xxxu: Do not use hard-wired RF enable settings for 8723bu These settings simply block the 8723bu, for now leave an empty function. With this change we can finally communicate with aliens using the 8723bu! Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 10 +++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 3e99a17c7962..5b6b9c5efc86 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1596,6 +1596,10 @@ static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); } +static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) +{ +} + static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv) { u8 sps0; @@ -7665,7 +7669,7 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) init_usb_anchor(&priv->tx_anchor); init_usb_anchor(&priv->int_anchor); - rtl8723a_enable_rf(priv); + priv->fops->enable_rf(priv); if (priv->usb_interrupts) { ret = rtl8xxxu_submit_int_urb(hw); if (ret) @@ -8031,6 +8035,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, .parse_rx_desc = rtl8723au_parse_rx_desc, + .enable_rf = rtl8723a_enable_rf, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8052,6 +8057,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .parse_rx_desc = rtl8723bu_parse_rx_desc, .init_aggregation = rtl8723bu_init_aggregation, .init_statistics = rtl8723bu_init_statistics, + .enable_rf = rtl8723b_enable_rf, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -8072,6 +8078,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, .parse_rx_desc = rtl8723au_parse_rx_desc, + .enable_rf = rtl8723a_enable_rf, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8091,6 +8098,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, .parse_rx_desc = rtl8723bu_parse_rx_desc, + .enable_rf = rtl8723b_enable_rf, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index b75678b9b60d..ac8f47f66d5f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1135,6 +1135,7 @@ struct rtl8xxxu_fileops { struct ieee80211_rx_status *rx_status); void (*init_aggregation) (struct rtl8xxxu_priv *priv); void (*init_statistics) (struct rtl8xxxu_priv *priv); + void (*enable_rf) (struct rtl8xxxu_priv *priv); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; -- cgit v1.2.3 From 4a0d7db53124dc81b03926bcec864a0575d94f8e Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:18 -0500 Subject: rtl8xxxu: Correct struct rtl8723bu_efuse to list power bases correctly Correct TX power definitions in rtl8723bu_efuse Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 10 ---------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 23 ++++++++++++++++++----- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 5b6b9c5efc86..40447e4eb1d9 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2338,16 +2338,6 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) ether_addr_copy(priv->mac_addr, efuse->mac_addr); - memcpy(priv->cck_tx_power_index_A, efuse->cck_tx_power_index_A, - sizeof(priv->cck_tx_power_index_A)); - memcpy(priv->cck_tx_power_index_B, efuse->cck_tx_power_index_B, - sizeof(priv->cck_tx_power_index_B)); - - memcpy(priv->ht40_1s_tx_power_index_A, efuse->ht40_1s_tx_power_index_A, - sizeof(priv->ht40_1s_tx_power_index_A)); - memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, - sizeof(priv->ht40_1s_tx_power_index_B)); - priv->has_xtalk = 1; priv->xtalk = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index ac8f47f66d5f..6d565812a4b1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -53,6 +53,7 @@ #define RTL8723A_CHANNEL_GROUPS 3 #define RTL8723A_MAX_RF_PATHS 2 +#define RTL8723B_MAX_RF_PATHS 4 #define RF6052_MAX_TX_PWR 0x3f #define EFUSE_MAP_LEN 512 @@ -631,14 +632,26 @@ struct rtl8192cu_efuse { u8 customer_id; }; +struct rtl8723bu_efuse_tx_power { + u8 cck_base[6]; + u8 ht40_base[5]; + struct rtl8723au_idx ht20_ofdm_1s_diff; + struct rtl8723au_idx ht40_ht20_2s_diff; + struct rtl8723au_idx ofdm_cck_2s_diff; /* not used */ + struct rtl8723au_idx ht40_ht20_3s_diff; + struct rtl8723au_idx ofdm_cck_3s_diff; /* not used */ + struct rtl8723au_idx ht40_ht20_4s_diff; + struct rtl8723au_idx ofdm_cck_4s_diff; /* not used */ + u8 dummy5g[24]; /* max channel group (14) + power diff offset (10) */ +}; + struct rtl8723bu_efuse { __le16 rtl_id; u8 res0[0x0e]; - u8 cck_tx_power_index_A[3]; /* 0x10 */ - u8 cck_tx_power_index_B[3]; - u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ - u8 ht40_1s_tx_power_index_B[3]; - u8 res1[0x9c]; + struct rtl8723bu_efuse_tx_power tx_power_index_A; /* 0x10 */ + struct rtl8723bu_efuse_tx_power tx_power_index_B; /* 0x3a */ + struct rtl8723bu_efuse_tx_power tx_power_index_C; /* 0x64 */ + struct rtl8723bu_efuse_tx_power tx_power_index_D; /* 0x8e */ u8 channel_plan; /* 0xb8 */ u8 xtal_k; u8 thermal_meter; -- cgit v1.2.3 From e796dab4b987503913418260bce782d230df60db Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:19 -0500 Subject: rtl8xxxu: Introduce set_tx_power() fileop and a new 8723b dummy derivative The 8723b series is significantly different from the older generation in this sense. So far the 8723b version doesn't do anything useful. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 34 ++++++++++++++++++++++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 ++ 2 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 40447e4eb1d9..de1e6541b1a0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1680,6 +1680,24 @@ static int rtl8723a_channel_to_group(int channel) return group; } +static int rtl8723b_channel_to_group(int channel) +{ + int group; + + if (channel < 3) + group = 0; + else if (channel < 6) + group = 1; + else if (channel < 9) + group = 2; + else if (channel < 12) + group = 3; + else + group = 4; + + return group; +} + static void rtl8723au_config_channel(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -2041,6 +2059,14 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) } } +static void +rtl8723b_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) +{ + int group; + + group = rtl8723b_channel_to_group(channel); +} + static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, enum nl80211_iftype linktype) { @@ -6378,7 +6404,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* * Start out with default power levels for channel 6, 20MHz */ - rtl8723a_set_tx_power(priv, 1, false); + priv->fops->set_tx_power(priv, 1, false); /* Let the 8051 take control of antenna setting */ val8 = rtl8xxxu_read8(priv, REG_LEDCFG2); @@ -7401,7 +7427,7 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) channel = hw->conf.chandef.chan->hw_value; - rtl8723a_set_tx_power(priv, channel, ht40); + priv->fops->set_tx_power(priv, channel, ht40); priv->fops->config_channel(hw); } @@ -8026,6 +8052,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .config_channel = rtl8723au_config_channel, .parse_rx_desc = rtl8723au_parse_rx_desc, .enable_rf = rtl8723a_enable_rf, + .set_tx_power = rtl8723a_set_tx_power, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8048,6 +8075,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .init_aggregation = rtl8723bu_init_aggregation, .init_statistics = rtl8723bu_init_statistics, .enable_rf = rtl8723b_enable_rf, + .set_tx_power = rtl8723b_set_tx_power, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -8069,6 +8097,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .config_channel = rtl8723au_config_channel, .parse_rx_desc = rtl8723au_parse_rx_desc, .enable_rf = rtl8723a_enable_rf, + .set_tx_power = rtl8723a_set_tx_power, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8089,6 +8118,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .config_channel = rtl8723bu_config_channel, .parse_rx_desc = rtl8723bu_parse_rx_desc, .enable_rf = rtl8723b_enable_rf, + .set_tx_power = rtl8723b_set_tx_power, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 6d565812a4b1..c7b4c92ea732 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1149,6 +1149,8 @@ struct rtl8xxxu_fileops { void (*init_aggregation) (struct rtl8xxxu_priv *priv); void (*init_statistics) (struct rtl8xxxu_priv *priv); void (*enable_rf) (struct rtl8xxxu_priv *priv); + void (*set_tx_power) (struct rtl8xxxu_priv *priv, int channel, + bool ht40); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; -- cgit v1.2.3 From 3e84f9386162878deb146a7e4f05710693f1a9c7 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:20 -0500 Subject: rtl8xxxu: Use size of source pointer when copying efuse data Some newer chips have more channel groups in their efuse parameter tables, so use the size of the source, rather than the destination when copying them out. This avoids copying garbage when increasing the common array sizes. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index de1e6541b1a0..4c37bd4b73b1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2318,31 +2318,31 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) memcpy(priv->cck_tx_power_index_A, efuse->cck_tx_power_index_A, - sizeof(priv->cck_tx_power_index_A)); + sizeof(efuse->cck_tx_power_index_A)); memcpy(priv->cck_tx_power_index_B, efuse->cck_tx_power_index_B, - sizeof(priv->cck_tx_power_index_B)); + sizeof(efuse->cck_tx_power_index_B)); memcpy(priv->ht40_1s_tx_power_index_A, efuse->ht40_1s_tx_power_index_A, - sizeof(priv->ht40_1s_tx_power_index_A)); + sizeof(efuse->ht40_1s_tx_power_index_A)); memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, - sizeof(priv->ht40_1s_tx_power_index_B)); + sizeof(efuse->ht40_1s_tx_power_index_B)); memcpy(priv->ht20_tx_power_index_diff, efuse->ht20_tx_power_index_diff, - sizeof(priv->ht20_tx_power_index_diff)); + sizeof(efuse->ht20_tx_power_index_diff)); memcpy(priv->ofdm_tx_power_index_diff, efuse->ofdm_tx_power_index_diff, - sizeof(priv->ofdm_tx_power_index_diff)); + sizeof(efuse->ofdm_tx_power_index_diff)); memcpy(priv->ht40_max_power_offset, efuse->ht40_max_power_offset, - sizeof(priv->ht40_max_power_offset)); + sizeof(efuse->ht40_max_power_offset)); memcpy(priv->ht20_max_power_offset, efuse->ht20_max_power_offset, - sizeof(priv->ht20_max_power_offset)); + sizeof(efuse->ht20_max_power_offset)); if (priv->efuse_wifi.efuse8723.version >= 0x01) { priv->has_xtalk = 1; @@ -2403,34 +2403,34 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) memcpy(priv->cck_tx_power_index_A, efuse->cck_tx_power_index_A, - sizeof(priv->cck_tx_power_index_A)); + sizeof(efuse->cck_tx_power_index_A)); memcpy(priv->cck_tx_power_index_B, efuse->cck_tx_power_index_B, - sizeof(priv->cck_tx_power_index_B)); + sizeof(efuse->cck_tx_power_index_B)); memcpy(priv->ht40_1s_tx_power_index_A, efuse->ht40_1s_tx_power_index_A, - sizeof(priv->ht40_1s_tx_power_index_A)); + sizeof(efuse->ht40_1s_tx_power_index_A)); memcpy(priv->ht40_1s_tx_power_index_B, efuse->ht40_1s_tx_power_index_B, - sizeof(priv->ht40_1s_tx_power_index_B)); + sizeof(efuse->ht40_1s_tx_power_index_B)); memcpy(priv->ht40_2s_tx_power_index_diff, efuse->ht40_2s_tx_power_index_diff, - sizeof(priv->ht40_2s_tx_power_index_diff)); + sizeof(efuse->ht40_2s_tx_power_index_diff)); memcpy(priv->ht20_tx_power_index_diff, efuse->ht20_tx_power_index_diff, - sizeof(priv->ht20_tx_power_index_diff)); + sizeof(efuse->ht20_tx_power_index_diff)); memcpy(priv->ofdm_tx_power_index_diff, efuse->ofdm_tx_power_index_diff, - sizeof(priv->ofdm_tx_power_index_diff)); + sizeof(efuse->ofdm_tx_power_index_diff)); memcpy(priv->ht40_max_power_offset, efuse->ht40_max_power_offset, - sizeof(priv->ht40_max_power_offset)); + sizeof(efuse->ht40_max_power_offset)); memcpy(priv->ht20_max_power_offset, efuse->ht20_max_power_offset, - sizeof(priv->ht20_max_power_offset)); + sizeof(efuse->ht20_max_power_offset)); dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); -- cgit v1.2.3 From 21db9973303caebcbe2fde6dcc668c1aac2ed55f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:21 -0500 Subject: rtl8xxxu: Bump TX power arrays to handle larger channel groups Newer generation chips have more channels groups. In order to carry the larger arrays in common structures, bump the array sizes to match. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 25 +++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index c7b4c92ea732..92768f54ce55 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -53,7 +53,9 @@ #define RTL8723A_CHANNEL_GROUPS 3 #define RTL8723A_MAX_RF_PATHS 2 +#define RTL8723B_CHANNEL_GROUPS 6 #define RTL8723B_MAX_RF_PATHS 4 +#define RTL8XXXU_MAX_CHANNEL_GROUPS 6 #define RF6052_MAX_TX_PWR 0x3f #define EFUSE_MAP_LEN 512 @@ -1046,19 +1048,24 @@ struct rtl8xxxu_priv { u8 mac_addr[ETH_ALEN]; char chip_name[8]; char chip_vendor[8]; - u8 cck_tx_power_index_A[3]; /* 0x10 */ - u8 cck_tx_power_index_B[3]; - u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ - u8 ht40_1s_tx_power_index_B[3]; + u8 cck_tx_power_index_A[RTL8XXXU_MAX_CHANNEL_GROUPS]; + u8 cck_tx_power_index_B[RTL8XXXU_MAX_CHANNEL_GROUPS]; + u8 ht40_1s_tx_power_index_A[RTL8XXXU_MAX_CHANNEL_GROUPS]; + u8 ht40_1s_tx_power_index_B[RTL8XXXU_MAX_CHANNEL_GROUPS]; /* * The following entries are half-bytes split as: * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed */ - struct rtl8723au_idx ht40_2s_tx_power_index_diff[3]; - struct rtl8723au_idx ht20_tx_power_index_diff[3]; - struct rtl8723au_idx ofdm_tx_power_index_diff[3]; - struct rtl8723au_idx ht40_max_power_offset[3]; - struct rtl8723au_idx ht20_max_power_offset[3]; + struct rtl8723au_idx ht40_2s_tx_power_index_diff[ + RTL8XXXU_MAX_CHANNEL_GROUPS]; + struct rtl8723au_idx ht20_tx_power_index_diff[ + RTL8XXXU_MAX_CHANNEL_GROUPS]; + struct rtl8723au_idx ofdm_tx_power_index_diff[ + RTL8XXXU_MAX_CHANNEL_GROUPS]; + struct rtl8723au_idx ht40_max_power_offset[ + RTL8XXXU_MAX_CHANNEL_GROUPS]; + struct rtl8723au_idx ht20_max_power_offset[ + RTL8XXXU_MAX_CHANNEL_GROUPS]; u32 chip_cut:4; u32 rom_rev:4; u32 is_multi_func:1; -- cgit v1.2.3 From 3be269990814e7f052e134cfc1d538b7010c0600 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:22 -0500 Subject: rtl8xxxu: Parse efuse power indices for 8723bu This should (hopefully) parse the power indices correctly for the 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 43 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 43 +++++++++++++++--------- 2 files changed, 71 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4c37bd4b73b1..0723008b4437 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2358,12 +2358,55 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8723bu_efuse *efuse = &priv->efuse_wifi.efuse8723bu; + int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; ether_addr_copy(priv->mac_addr, efuse->mac_addr); + memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base, + sizeof(efuse->tx_power_index_A.cck_base)); + memcpy(priv->cck_tx_power_index_B, efuse->tx_power_index_B.cck_base, + sizeof(efuse->tx_power_index_B.cck_base)); + + memcpy(priv->ht40_1s_tx_power_index_A, + efuse->tx_power_index_A.ht40_base, + sizeof(efuse->tx_power_index_A.ht40_base)); + memcpy(priv->ht40_1s_tx_power_index_B, + efuse->tx_power_index_B.ht40_base, + sizeof(efuse->tx_power_index_B.ht40_base)); + + priv->ofdm_tx_power_diff[0].a = + efuse->tx_power_index_A.ht20_ofdm_1s_diff.a; + priv->ofdm_tx_power_diff[0].b = + efuse->tx_power_index_B.ht20_ofdm_1s_diff.a; + + priv->ht20_tx_power_diff[0].a = + efuse->tx_power_index_A.ht20_ofdm_1s_diff.b; + priv->ht20_tx_power_diff[0].b = + efuse->tx_power_index_B.ht20_ofdm_1s_diff.b; + + priv->ht40_tx_power_diff[0].a = 0; + priv->ht40_tx_power_diff[0].b = 0; + + for (i = 1; i < RTL8723B_TX_COUNT; i++) { + priv->ofdm_tx_power_diff[i].a = + efuse->tx_power_index_A.pwr_diff[i - 1].ofdm; + priv->ofdm_tx_power_diff[i].b = + efuse->tx_power_index_B.pwr_diff[i - 1].ofdm; + + priv->ht20_tx_power_diff[i].a = + efuse->tx_power_index_A.pwr_diff[i - 1].ht20; + priv->ht20_tx_power_diff[i].b = + efuse->tx_power_index_B.pwr_diff[i - 1].ht20; + + priv->ht40_tx_power_diff[i].a = + efuse->tx_power_index_A.pwr_diff[i - 1].ht40; + priv->ht40_tx_power_diff[i].b = + efuse->tx_power_index_B.pwr_diff[i - 1].ht40; + } + priv->has_xtalk = 1; priv->xtalk = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 92768f54ce55..fe2356179915 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -54,6 +54,7 @@ #define RTL8723A_CHANNEL_GROUPS 3 #define RTL8723A_MAX_RF_PATHS 2 #define RTL8723B_CHANNEL_GROUPS 6 +#define RTL8723B_TX_COUNT 4 #define RTL8723B_MAX_RF_PATHS 4 #define RTL8XXXU_MAX_CHANNEL_GROUPS 6 #define RF6052_MAX_TX_PWR 0x3f @@ -634,16 +635,25 @@ struct rtl8192cu_efuse { u8 customer_id; }; +struct rtl8723bu_pwr_idx { +#ifdef __LITTLE_ENDIAN + int ht20:4; + int ht40:4; + int ofdm:4; + int cck:4; +#else + int cck:4; + int ofdm:4; + int ht40:4; + int ht20:4; +#endif +} __attribute__((packed)); + struct rtl8723bu_efuse_tx_power { u8 cck_base[6]; u8 ht40_base[5]; struct rtl8723au_idx ht20_ofdm_1s_diff; - struct rtl8723au_idx ht40_ht20_2s_diff; - struct rtl8723au_idx ofdm_cck_2s_diff; /* not used */ - struct rtl8723au_idx ht40_ht20_3s_diff; - struct rtl8723au_idx ofdm_cck_3s_diff; /* not used */ - struct rtl8723au_idx ht40_ht20_4s_diff; - struct rtl8723au_idx ofdm_cck_4s_diff; /* not used */ + struct rtl8723bu_pwr_idx pwr_diff[3]; u8 dummy5g[24]; /* max channel group (14) + power diff offset (10) */ }; @@ -1057,15 +1067,18 @@ struct rtl8xxxu_priv { * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed */ struct rtl8723au_idx ht40_2s_tx_power_index_diff[ - RTL8XXXU_MAX_CHANNEL_GROUPS]; - struct rtl8723au_idx ht20_tx_power_index_diff[ - RTL8XXXU_MAX_CHANNEL_GROUPS]; - struct rtl8723au_idx ofdm_tx_power_index_diff[ - RTL8XXXU_MAX_CHANNEL_GROUPS]; - struct rtl8723au_idx ht40_max_power_offset[ - RTL8XXXU_MAX_CHANNEL_GROUPS]; - struct rtl8723au_idx ht20_max_power_offset[ - RTL8XXXU_MAX_CHANNEL_GROUPS]; + RTL8723A_CHANNEL_GROUPS]; + struct rtl8723au_idx ht20_tx_power_index_diff[RTL8723A_CHANNEL_GROUPS]; + struct rtl8723au_idx ofdm_tx_power_index_diff[RTL8723A_CHANNEL_GROUPS]; + struct rtl8723au_idx ht40_max_power_offset[RTL8723A_CHANNEL_GROUPS]; + struct rtl8723au_idx ht20_max_power_offset[RTL8723A_CHANNEL_GROUPS]; + /* + * Newer generation chips only keep power diffs per TX count, + * not per channel group. + */ + struct rtl8723au_idx ofdm_tx_power_diff[RTL8723B_TX_COUNT]; + struct rtl8723au_idx ht20_tx_power_diff[RTL8723B_TX_COUNT]; + struct rtl8723au_idx ht40_tx_power_diff[RTL8723B_TX_COUNT]; u32 chip_cut:4; u32 rom_rev:4; u32 is_multi_func:1; -- cgit v1.2.3 From 54bed43f3a67351b1ad75ddcad82587d9e5471e0 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:23 -0500 Subject: rtl8xxxu: Set 8723bu TX power for CCK and OFDM rates This implements support for setting TX power for CCK and OFDM rates on 8723bu. MCS rates is still pending. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 0723008b4437..e8006055c7c4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2062,9 +2062,30 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) static void rtl8723b_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) { - int group; + u32 val32, ofdm; + u8 cck, ofdmbase; + int group, tx_idx; + tx_idx = 0; group = rtl8723b_channel_to_group(channel); + + cck = priv->cck_tx_power_index_B[group]; + val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32); + val32 &= 0xffff00ff; + val32 |= (cck << 8); + rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11); + val32 &= 0xff; + val32 |= ((cck << 8) | (cck << 16) | (cck << 24)); + rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32); + + ofdmbase = priv->ht40_1s_tx_power_index_B[group]; + ofdmbase += priv->ofdm_tx_power_diff[tx_idx].b; + ofdm = ofdmbase | ofdmbase << 8 | ofdmbase << 16 | ofdmbase << 24; + + rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm); + rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm); } static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From 1d3cc44dddf8501934172ea141397647f01bb0c6 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:24 -0500 Subject: rtl8xxxu: Set 8723bu MCS TX power This adds the missing support for setting MCS TX power rates on 8723bu. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e8006055c7c4..56813390c0ea 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2062,8 +2062,8 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) static void rtl8723b_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) { - u32 val32, ofdm; - u8 cck, ofdmbase; + u32 val32, ofdm, mcs; + u8 cck, ofdmbase, mcsbase; int group, tx_idx; tx_idx = 0; @@ -2086,6 +2086,16 @@ rtl8723b_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm); rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm); + + mcsbase = priv->ht40_1s_tx_power_index_B[group]; + if (ht40) + mcsbase += priv->ht40_tx_power_diff[tx_idx++].b; + else + mcsbase += priv->ht20_tx_power_diff[tx_idx++].b; + mcs = mcsbase | mcsbase << 8 | mcsbase << 16 | mcsbase << 24; + + rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs); + rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs); } static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From 72143b9e947c593555fa2a869a4bc08b9745b105 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:25 -0500 Subject: rtl8xxxu: Set the correct thermal meter register for 8723bu Older chips use RF register 0x24 to set the thermal meter. Newer chips use register 0x42. This change makes sure to set the correct thermal meter register depending on the chip. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 56813390c0ea..241d68d161aa 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6502,7 +6502,11 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* * This should enable thermal meter */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60); + if (priv->fops->has_s0s1) + rtl8xxxu_write_rfreg(priv, + RF_A, RF6052_REG_T_METER_8723B, 0x37cf8); + else + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60); /* Init BT hw config. */ if (priv->fops->init_bt) -- cgit v1.2.3 From 80491a1f3c878be44efa9d25fda1bb7b3388ca79 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:26 -0500 Subject: rtl8xxxu: Add definition for 8723bu tx descriptor Newer generation chips use a 40 byte TX descriptor, compared to the 32 byte descriptor used on older chips. This adds the definition for the 40 byte descriptor. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index fe2356179915..f06b88b97bee 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -346,6 +346,22 @@ struct rtl8xxxu_tx_desc { __le16 txdw7; }; +struct rtl8723bu_tx_desc { + __le16 pkt_size; + u8 pkt_offset; + u8 txdw0; + __le32 txdw1; + __le32 txdw2; + __le32 txdw3; + __le32 txdw4; + __le32 txdw5; + __le32 txdw6; + __le16 csum; + __le16 txdw7; + __le32 txdw8; + __le32 txdw9; +}; + /* CCK Rates, TxHT = 0 */ #define DESC_RATE_1M 0x00 #define DESC_RATE_2M 0x01 -- cgit v1.2.3 From 179e1742569620aed495f5d106d019b2dd6057d1 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:27 -0500 Subject: rtl8xxxu: Handle 40 byte TX descriptors for rtl8723bu Note the descriptor checksum is still only calculated over the initial 32 bytes of the descriptor, ignoring the last 8 bytes of the descriptor. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 35 ++++++++++++++++-------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 3 +- 2 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 241d68d161aa..19bc5d7556bc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6787,7 +6787,12 @@ static u32 rtl8xxxu_queue_select(struct ieee80211_hw *hw, struct sk_buff *skb) return queue; } -static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc) +/* + * Despite newer chips 8723b/8812/8821 having a larger TX descriptor + * format. The descriptor checksum is still only calculated over the + * initial 32 bytes of the descriptor! + */ +static void rtl8xxxu_calc_tx_desc_csum(struct rtl8723au_tx_desc *tx_desc) { __le16 *ptr = (__le16 *)tx_desc; u16 csum = 0; @@ -6799,7 +6804,7 @@ static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc) */ tx_desc->csum = cpu_to_le16(0); - for (i = 0; i < (sizeof(struct rtl8xxxu_tx_desc) / sizeof(u16)); i++) + for (i = 0; i < (sizeof(struct rtl8723au_tx_desc) / sizeof(u16)); i++) csum = csum ^ le16_to_cpu(ptr[i]); tx_desc->csum |= cpu_to_le16(csum); @@ -6868,13 +6873,15 @@ static void rtl8xxxu_tx_complete(struct urb *urb) struct sk_buff *skb = (struct sk_buff *)urb->context; struct ieee80211_tx_info *tx_info; struct ieee80211_hw *hw; + struct rtl8xxxu_priv *priv; struct rtl8xxxu_tx_urb *tx_urb = container_of(urb, struct rtl8xxxu_tx_urb, urb); tx_info = IEEE80211_SKB_CB(skb); hw = tx_info->rate_driver_data[0]; + priv = hw->priv; - skb_pull(skb, sizeof(struct rtl8xxxu_tx_desc)); + skb_pull(skb, priv->fops->tx_desc_size); ieee80211_tx_info_clear_status(tx_info); tx_info->status.rates[0].idx = -1; @@ -6885,7 +6892,7 @@ static void rtl8xxxu_tx_complete(struct urb *urb) ieee80211_tx_status_irqsafe(hw, skb); - rtl8xxxu_free_tx_urb(hw->priv, tx_urb); + rtl8xxxu_free_tx_urb(priv, tx_urb); } static void rtl8xxxu_dump_action(struct device *dev, @@ -6935,7 +6942,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; - struct rtl8xxxu_tx_desc *tx_desc; + struct rtl8723au_tx_desc *tx_desc; struct rtl8xxxu_tx_urb *tx_urb; struct ieee80211_sta *sta = NULL; struct ieee80211_vif *vif = tx_info->control.vif; @@ -6944,16 +6951,17 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, u16 pktlen = skb->len; u16 seq_number; u16 rate_flag = tx_info->control.rates[0].flags; + int tx_desc_size = priv->fops->tx_desc_size; int ret; - if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) { + if (skb_headroom(skb) < tx_desc_size) { dev_warn(dev, "%s: Not enough headroom (%i) for tx descriptor\n", __func__, skb_headroom(skb)); goto error; } - if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) { + if (unlikely(skb->len > (65535 - tx_desc_size))) { dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n", __func__, skb->len); goto error; @@ -6977,12 +6985,11 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (control && control->sta) sta = control->sta; - tx_desc = (struct rtl8xxxu_tx_desc *) - skb_push(skb, sizeof(struct rtl8xxxu_tx_desc)); + tx_desc = (struct rtl8723au_tx_desc *)skb_push(skb, tx_desc_size); - memset(tx_desc, 0, sizeof(struct rtl8xxxu_tx_desc)); + memset(tx_desc, 0, tx_desc_size); tx_desc->pkt_size = cpu_to_le16(pktlen); - tx_desc->pkt_offset = sizeof(struct rtl8xxxu_tx_desc); + tx_desc->pkt_offset = tx_desc_size; tx_desc->txdw0 = TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT; @@ -8077,7 +8084,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, SET_IEEE80211_DEV(priv->hw, &interface->dev); SET_IEEE80211_PERM_ADDR(hw, priv->mac_addr); - hw->extra_tx_headroom = sizeof(struct rtl8xxxu_tx_desc); + hw->extra_tx_headroom = priv->fops->tx_desc_size; ieee80211_hw_set(hw, SIGNAL_DBM); /* * The firmware handles rate control @@ -8134,6 +8141,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, + .tx_desc_size = sizeof(struct rtl8723au_tx_desc), .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, .adda_2t_path_on_a = 0x04db25a4, @@ -8157,6 +8165,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, + .tx_desc_size = sizeof(struct rtl8723bu_tx_desc), .has_s0s1 = 1, .adda_1t_init = 0x01c00014, .adda_1t_path_on = 0x01c00014, @@ -8179,6 +8188,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, + .tx_desc_size = sizeof(struct rtl8723au_tx_desc), .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, .adda_2t_path_on_a = 0x04db25a4, @@ -8200,6 +8210,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, + .tx_desc_size = sizeof(struct rtl8723au_tx_desc), .has_s0s1 = 1, .adda_1t_init = 0x0fc01616, .adda_1t_path_on = 0x0fc01616, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index f06b88b97bee..d53912a8326d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -332,7 +332,7 @@ struct rtl8723bu_rx_desc { __le32 tsfl; }; -struct rtl8xxxu_tx_desc { +struct rtl8723au_tx_desc { __le16 pkt_size; u8 pkt_offset; u8 txdw0; @@ -1190,6 +1190,7 @@ struct rtl8xxxu_fileops { int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; + char tx_desc_size; char has_s0s1; u32 adda_1t_init; u32 adda_1t_path_on; -- cgit v1.2.3 From 5e00d5034abf816aa1ca5033ed7c0d6ff04cba87 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:28 -0500 Subject: rtl8xxxu: Do not unconditionally print debug info in rtl8723bu_handle_c2h() Reduce the log level in rtl8723bu_handle_c2h() Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 19bc5d7556bc..49fb5bd2950d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7296,29 +7296,29 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, len = skb->len - 2; - dev_info(dev, "C2H ID %02x seq %02x, len %02x source %02x\n", - c2h->id, c2h->seq, len, c2h->bt_info.response_source); + dev_dbg(dev, "C2H ID %02x seq %02x, len %02x source %02x\n", + c2h->id, c2h->seq, len, c2h->bt_info.response_source); switch(c2h->id) { case C2H_8723B_BT_INFO: if (c2h->bt_info.response_source > BT_INFO_SRC_8723B_BT_ACTIVE_SEND) - dev_info(dev, "C2H_BT_INFO WiFi only firmware\n"); + dev_dbg(dev, "C2H_BT_INFO WiFi only firmware\n"); else - dev_info(dev, "C2H_BT_INFO BT/WiFi coexist firmware\n"); + dev_dbg(dev, "C2H_BT_INFO BT/WiFi coexist firmware\n"); if (c2h->bt_info.bt_has_reset) - dev_info(dev, "BT has been reset\n"); + dev_dbg(dev, "BT has been reset\n"); if (c2h->bt_info.tx_rx_mask) - dev_info(dev, "BT TRx mask\n"); + dev_dbg(dev, "BT TRx mask\n"); break; case C2H_8723B_BT_MP_INFO: - dev_info(dev, "C2H_MP_INFO ext ID %02x, status %02x\n", - c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); + dev_dbg(dev, "C2H_MP_INFO ext ID %02x, status %02x\n", + c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); break; default: - pr_info("%s: Unhandled C2H event %02x\n", __func__, c2h->id); + dev_info(dev, "Unhandled C2H event %02x\n", c2h->id); break; } } -- cgit v1.2.3 From 0249258db457b1279f40c7adf46bfb2eea817884 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:29 -0500 Subject: rtl8xxxu: Add additional tx descriptor bits for data word 0 This adds documentation for some additional bits in TX descriptor word 0. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index d53912a8326d..9364a31be9bf 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -407,8 +407,12 @@ struct rtl8723bu_tx_desc { #define TXDESC_OWN BIT(31) #else #define TXDESC_BROADMULTICAST BIT(0) +#define TXDESC_HTC BIT(1) #define TXDESC_LAST_SEGMENT BIT(2) #define TXDESC_FIRST_SEGMENT BIT(3) +#define TXDESC_LINIP BIT(4) +#define TXDESC_NO_ACM BIT(5) +#define TXDESC_GF BIT(6) #define TXDESC_OWN BIT(7) #endif -- cgit v1.2.3 From ce2d1dbbb4b7b72cfe64d07fbd282f472ea51bbd Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:30 -0500 Subject: rtl8xxxu: Add more 40 byte TX desc bit definitions Add additional bit definitions for 40 byte TX descriptors, and rename bits for 32 byte descriptors that are located differently in the 40 byte descriptor format. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 7 +++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 27 +++++++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 49fb5bd2950d..4cff2c94c88f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7035,11 +7035,12 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, ampdu = (u32)sta->ht_cap.ampdu_density; val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT; tx_desc->txdw2 |= cpu_to_le32(val32); - tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE); + + tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE_8723A); } else - tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK); + tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_BREAK_8723A); } else - tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK); + tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_BREAK_8723A); if (ieee80211_is_data_qos(hdr->frame_control)) tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 9364a31be9bf..6ba12ab9ba4e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -417,9 +417,15 @@ struct rtl8723bu_tx_desc { #endif /* Word 1 */ +/* + * Bits 0-7 differ dependent on chip generation. For 8723au bits 5/6 are + * aggregation enable and break respectively. For 8723bu, bits 0-7 are macid. + */ #define TXDESC_PKT_OFFSET_SZ 0 -#define TXDESC_AGG_ENABLE BIT(5) -#define TXDESC_BK BIT(6) +#define TXDESC_AGG_ENABLE_8723A BIT(5) +#define TXDESC_AGG_BREAK_8723A BIT(6) +#define TXDESC_MACID_SHIFT_8723B 0 +#define TXDESC_MACID_MASK_8723B 0x00f0 #define TXDESC_QUEUE_SHIFT 8 #define TXDESC_QUEUE_MASK 0x1f00 #define TXDESC_QUEUE_BK 0x2 @@ -431,6 +437,9 @@ struct rtl8723bu_tx_desc { #define TXDESC_QUEUE_MGNT 0x12 #define TXDESC_QUEUE_CMD 0x13 #define TXDESC_QUEUE_MAX (TXDESC_QUEUE_CMD + 1) +#define TXDESC_RDG_NAV_EXT_8723B BIT(13) +#define TXDESC_LSIG_TXOP_ENABLE_8723B BIT(14) +#define TXDESC_PIFS_8723B BIT(15) #define DESC_RATE_ID_SHIFT 16 #define DESC_RATE_ID_MASK 0xf @@ -442,8 +451,20 @@ struct rtl8723bu_tx_desc { #define TXDESC_HWPC BIT(31) /* Word 2 */ -#define TXDESC_ACK_REPORT BIT(19) +#define TXDESC_PAID_SHIFT_8723B 0 +#define TXDESC_PAID_MASK_8723B 0x1ff +#define TXDESC_CCA_RTS_SHIFT_8723B 10 +#define TXDESC_CCA_RTS_MASK_8723B 0xc00 +#define TXDESC_AGG_ENABLE_8723B BIT(12) +#define TXDESC_RDG_ENABLE_8723B BIT(13) +#define TXDESC_AGG_BREAK_8723B BIT(16) +#define TXDESC_MORE_FRAG_8723B BIT(17) +#define TXDESC_RAW_8723B BIT(18) +#define TXDESC_ACK_REPORT_8723A BIT(19) +#define TXDESC_SPE_RPT_8723B BIT(19) #define TXDESC_AMPDU_DENSITY_SHIFT 20 +#define TXDESC_BT_INT_8723B BIT(23) +#define TXDESC_GID_8723B BIT(24) /* Word 3 */ #define TXDESC_SEQ_SHIFT 16 -- cgit v1.2.3 From a40ace4f01c77362553455a819eba407f7fccc76 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:31 -0500 Subject: rtl8xxxu: Set the correct TX descriptor bits for agg and break on 8723b Fixup victim of the relocated bits for AGG_ENABLE/AGG_BREAK in the 40 byte TX descriptor Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4cff2c94c88f..dd9addf7badf 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6953,6 +6953,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, u16 rate_flag = tx_info->control.rates[0].flags; int tx_desc_size = priv->fops->tx_desc_size; int ret; + bool txdesc40, ampdu_enable; if (skb_headroom(skb) < tx_desc_size) { dev_warn(dev, @@ -6980,6 +6981,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (ieee80211_is_action(hdr->frame_control)) rtl8xxxu_dump_action(dev, hdr); + txdesc40 = (tx_desc_size == 40); tx_info->rate_driver_data[0] = hw; if (control && control->sta) @@ -7028,6 +7030,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, tx_desc->txdw5 |= cpu_to_le32(0x0001ff00); /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */ + ampdu_enable = false; if (ieee80211_is_data_qos(hdr->frame_control) && sta) { if (sta->ht_cap.ht_supported) { u32 ampdu, val32; @@ -7036,11 +7039,21 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT; tx_desc->txdw2 |= cpu_to_le32(val32); + ampdu_enable = true; + } + } + + if (!txdesc40) { + if (ampdu_enable) tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE_8723A); - } else + else tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_BREAK_8723A); - } else - tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_BREAK_8723A); + } else { + if (ampdu_enable) + tx_desc->txdw2 |= cpu_to_le32(TXDESC_AGG_ENABLE_8723B); + else + tx_desc->txdw2 |= cpu_to_le32(TXDESC_AGG_BREAK_8723B); + }; if (ieee80211_is_data_qos(hdr->frame_control)) tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS); -- cgit v1.2.3 From cc2646d4bed4f85bbb72871717f86b625677a874 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:32 -0500 Subject: rtl8xxxu: Set sequence number correctly for 40 byte TX descriptors SEQ changed location in the 40 byte TX descriptor. Set it correctly. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 24 ++++++++++++++++-------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 ++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index dd9addf7badf..968eac70163d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6943,6 +6943,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; struct rtl8723au_tx_desc *tx_desc; + struct rtl8723bu_tx_desc *tx_desc40; struct rtl8xxxu_tx_urb *tx_urb; struct ieee80211_sta *sta = NULL; struct ieee80211_vif *vif = tx_info->control.vif; @@ -6953,7 +6954,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, u16 rate_flag = tx_info->control.rates[0].flags; int tx_desc_size = priv->fops->tx_desc_size; int ret; - bool txdesc40, ampdu_enable; + bool usedesc40, ampdu_enable; if (skb_headroom(skb) < tx_desc_size) { dev_warn(dev, @@ -6981,7 +6982,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (ieee80211_is_action(hdr->frame_control)) rtl8xxxu_dump_action(dev, hdr); - txdesc40 = (tx_desc_size == 40); + usedesc40 = (tx_desc_size == 40); tx_info->rate_driver_data[0] = hw; if (control && control->sta) @@ -7017,9 +7018,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, } } - seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT); - if (rate_flag & IEEE80211_TX_RC_MCS) rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; else @@ -7043,16 +7041,26 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, } } - if (!txdesc40) { + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + if (!usedesc40) { + tx_desc->txdw3 = + cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT_8723A); + if (ampdu_enable) tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE_8723A); else tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_BREAK_8723A); } else { + tx_desc40 = (struct rtl8723bu_tx_desc *)tx_desc; + + tx_desc40->txdw9 = + cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT_8723B); + if (ampdu_enable) - tx_desc->txdw2 |= cpu_to_le32(TXDESC_AGG_ENABLE_8723B); + tx_desc40->txdw2 |= + cpu_to_le32(TXDESC_AGG_ENABLE_8723B); else - tx_desc->txdw2 |= cpu_to_le32(TXDESC_AGG_BREAK_8723B); + tx_desc40->txdw2 |= cpu_to_le32(TXDESC_AGG_BREAK_8723B); }; if (ieee80211_is_data_qos(hdr->frame_control)) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 6ba12ab9ba4e..8f95896f4ded 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -467,8 +467,8 @@ struct rtl8723bu_tx_desc { #define TXDESC_GID_8723B BIT(24) /* Word 3 */ -#define TXDESC_SEQ_SHIFT 16 -#define TXDESC_SEQ_MASK 0x0fff0000 +#define TXDESC_SEQ_SHIFT_8723A 16 +#define TXDESC_SEQ_MASK_8723A 0x0fff0000 /* Word 4 */ #define TXDESC_QOS BIT(6) @@ -498,6 +498,10 @@ struct rtl8723bu_tx_desc { /* Word 6 */ #define TXDESC_MAX_AGG_SHIFT 11 +/* Word 9 */ +#define TXDESC_SEQ_SHIFT_8723B 12 +#define TXDESC_SEQ_MASK_8723B 0x00fff000 + struct phy_rx_agc_info { #ifdef __LITTLE_ENDIAN u8 gain:7, trsw:1; -- cgit v1.2.3 From 2098bfb5f3277b12dc2f9dc61efd57161c000f77 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:33 -0500 Subject: rtl8723au: Update TX descriptor words 4 and 5 definitions TX data words 4 and 5 differ significantly between 32 byte and 40 byte descriptors. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 11 ++++---- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 32 ++++++++++++++++-------- 2 files changed, 28 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 968eac70163d..2fa587e6d24d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7076,16 +7076,17 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, } if (ieee80211_is_mgmt(hdr->frame_control)) { tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value); - tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE); - tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT); - tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE_8723A); + tx_desc->txdw5 |= + cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT_8723A); + tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE_8723A); } if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { /* Use RTS rate 24M - does the mac80211 tell us which to use? */ tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M); - tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE); - tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE_8723A); + tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE_8723A); } rtl8xxxu_calc_tx_desc_csum(tx_desc); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 8f95896f4ded..5f60f190104d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -467,17 +467,21 @@ struct rtl8723bu_tx_desc { #define TXDESC_GID_8723B BIT(24) /* Word 3 */ +#define TXDESC_USE_DRIVER_RATE_8723B BIT(8) +#define TXDESC_CTS_SELF_ENABLE_8723B BIT(11) +#define TXDESC_RTS_CTS_ENABLE_8723B BIT(12) +#define TXDESC_HW_RTS_ENABLE_8723B BIT(13) #define TXDESC_SEQ_SHIFT_8723A 16 #define TXDESC_SEQ_MASK_8723A 0x0fff0000 /* Word 4 */ #define TXDESC_QOS BIT(6) -#define TXDESC_HW_SEQ_ENABLE BIT(7) -#define TXDESC_USE_DRIVER_RATE BIT(8) +#define TXDESC_HW_SEQ_ENABLE_8723A BIT(7) +#define TXDESC_USE_DRIVER_RATE_8723A BIT(8) #define TXDESC_DISABLE_DATA_FB BIT(10) -#define TXDESC_CTS_SELF_ENABLE BIT(11) -#define TXDESC_RTS_CTS_ENABLE BIT(12) -#define TXDESC_HW_RTS_ENABLE BIT(13) +#define TXDESC_CTS_SELF_ENABLE_8723A BIT(11) +#define TXDESC_RTS_CTS_ENABLE_8723A BIT(12) +#define TXDESC_HW_RTS_ENABLE_8723A BIT(13) #define TXDESC_PRIME_CH_OFF_LOWER BIT(20) #define TXDESC_PRIME_CH_OFF_UPPER BIT(21) #define TXDESC_SHORT_PREAMBLE BIT(24) @@ -485,19 +489,27 @@ struct rtl8723bu_tx_desc { #define TXDESC_RTS_DATA_BW BIT(27) #define TXDESC_RTS_PRIME_CH_OFF_LOWER BIT(28) #define TXDESC_RTS_PRIME_CH_OFF_UPPER BIT(29) +#define TXDESC_RETRY_LIMIT_ENABLE_8723B BIT(17) +#define TXDESC_RETRY_LIMIT_SHIFT_8723B 18 +#define TXDESC_RETRY_LIMIT_MASK_8723B 0x00fc0000 +#define TXDESC_RTS_RATE_SHIFT_8723B 24 +#define TXDESC_RTS_RATE_MASK_8723B 0x3f000000 /* Word 5 */ -#define TXDESC_RTS_RATE_SHIFT 0 -#define TXDESC_RTS_RATE_MASK 0x3f +#define TXDESC_RTS_RATE_SHIFT_8723A 0 +#define TXDESC_RTS_RATE_MASK_8723A 0x3f #define TXDESC_SHORT_GI BIT(6) #define TXDESC_CCX_TAG BIT(7) -#define TXDESC_RETRY_LIMIT_ENABLE BIT(17) -#define TXDESC_RETRY_LIMIT_SHIFT 18 -#define TXDESC_RETRY_LIMIT_MASK 0x00fc0000 +#define TXDESC_RETRY_LIMIT_ENABLE_8723A BIT(17) +#define TXDESC_RETRY_LIMIT_SHIFT_8723A 18 +#define TXDESC_RETRY_LIMIT_MASK_8723A 0x00fc0000 /* Word 6 */ #define TXDESC_MAX_AGG_SHIFT 11 +/* Word 8 */ +#define TXDESC_HW_SEQ_ENABLE_8723B BIT(15) + /* Word 9 */ #define TXDESC_SEQ_SHIFT_8723B 12 #define TXDESC_SEQ_MASK_8723B 0x00fff000 -- cgit v1.2.3 From 2c6670b2a8e6dcd17bedd4dfbac663b2aa3d6949 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:34 -0500 Subject: rtl8xxxu: TX RTS rate is word 4 for 8723a Correct the setting of TX RTS for 8723a generation chips. In addition update documentation to match that this is part of data word 4, note data word 5. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 3 ++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 2fa587e6d24d..4fbf44562d0e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7084,7 +7084,8 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { /* Use RTS rate 24M - does the mac80211 tell us which to use? */ - tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M); + tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M << + TXDESC_RTS_RATE_SHIFT_8723A); tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE_8723A); tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE_8723A); } diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 5f60f190104d..b015c75f4841 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -475,6 +475,8 @@ struct rtl8723bu_tx_desc { #define TXDESC_SEQ_MASK_8723A 0x0fff0000 /* Word 4 */ +#define TXDESC_RTS_RATE_SHIFT_8723A 0 +#define TXDESC_RTS_RATE_MASK_8723A 0x3f #define TXDESC_QOS BIT(6) #define TXDESC_HW_SEQ_ENABLE_8723A BIT(7) #define TXDESC_USE_DRIVER_RATE_8723A BIT(8) @@ -496,8 +498,6 @@ struct rtl8723bu_tx_desc { #define TXDESC_RTS_RATE_MASK_8723B 0x3f000000 /* Word 5 */ -#define TXDESC_RTS_RATE_SHIFT_8723A 0 -#define TXDESC_RTS_RATE_MASK_8723A 0x3f #define TXDESC_SHORT_GI BIT(6) #define TXDESC_CCX_TAG BIT(7) #define TXDESC_RETRY_LIMIT_ENABLE_8723A BIT(17) -- cgit v1.2.3 From 4c683607145d22c872d6b473c5f5465f8459c5de Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:35 -0500 Subject: rtl8xxxu: Improve handling of txdesc32 vs txdesc40 handling Further correct the handling of 40 byte TX descriptors. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 123 ++++++++++++++++------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 7 +- 2 files changed, 92 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4fbf44562d0e..927fd3b13ae3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7018,15 +7018,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, } } - if (rate_flag & IEEE80211_TX_RC_MCS) - rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; - else - rate = tx_rate->hw_value; - tx_desc->txdw5 = cpu_to_le32(rate); - - if (ieee80211_is_data(hdr->frame_control)) - tx_desc->txdw5 |= cpu_to_le32(0x0001ff00); - /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */ ampdu_enable = false; if (ieee80211_is_data_qos(hdr->frame_control) && sta) { @@ -7041,8 +7032,18 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, } } + if (rate_flag & IEEE80211_TX_RC_MCS) + rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; + else + rate = tx_rate->hw_value; + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); if (!usedesc40) { + tx_desc->txdw5 = cpu_to_le32(rate); + + if (ieee80211_is_data(hdr->frame_control)) + tx_desc->txdw5 |= cpu_to_le32(0x0001ff00); + tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT_8723A); @@ -7050,9 +7051,56 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE_8723A); else tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_BREAK_8723A); + + if (ieee80211_is_mgmt(hdr->frame_control)) { + tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value); + tx_desc->txdw4 |= + cpu_to_le32(TXDESC_USE_DRIVER_RATE_8723A); + tx_desc->txdw5 |= + cpu_to_le32(6 << + TXDESC_RETRY_LIMIT_SHIFT_8723A); + tx_desc->txdw5 |= + cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE_8723A); + } + + if (ieee80211_is_data_qos(hdr->frame_control)) + tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS_8723A); + + if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE || + (sta && vif && vif->bss_conf.use_short_preamble)) + tx_desc->txdw4 |= + cpu_to_le32(TXDESC_SHORT_PREAMBLE_8723A); + + if (rate_flag & IEEE80211_TX_RC_SHORT_GI || + (ieee80211_is_data_qos(hdr->frame_control) && + sta && sta->ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) { + tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI); + } + + if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { + /* + * Use RTS rate 24M - does the mac80211 tell + * us which to use? + */ + tx_desc->txdw4 |= + cpu_to_le32(DESC_RATE_24M << + TXDESC_RTS_RATE_SHIFT_8723A); + tx_desc->txdw4 |= + cpu_to_le32(TXDESC_RTS_CTS_ENABLE_8723A); + tx_desc->txdw4 |= + cpu_to_le32(TXDESC_HW_RTS_ENABLE_8723A); + } } else { tx_desc40 = (struct rtl8723bu_tx_desc *)tx_desc; + tx_desc40->txdw4 = cpu_to_le32(rate); + if (ieee80211_is_data(hdr->frame_control)) { + tx_desc->txdw4 |= + cpu_to_le32(0x1f << + TXDESC_DATA_RATE_FB_SHIFT_8723B); + } + tx_desc40->txdw9 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT_8723B); @@ -7061,34 +7109,37 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, cpu_to_le32(TXDESC_AGG_ENABLE_8723B); else tx_desc40->txdw2 |= cpu_to_le32(TXDESC_AGG_BREAK_8723B); - }; - if (ieee80211_is_data_qos(hdr->frame_control)) - tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS); - if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE || - (sta && vif && vif->bss_conf.use_short_preamble)) - tx_desc->txdw4 |= cpu_to_le32(TXDESC_SHORT_PREAMBLE); - if (rate_flag & IEEE80211_TX_RC_SHORT_GI || - (ieee80211_is_data_qos(hdr->frame_control) && - sta && sta->ht_cap.cap & - (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) { - tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI); - } - if (ieee80211_is_mgmt(hdr->frame_control)) { - tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value); - tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE_8723A); - tx_desc->txdw5 |= - cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT_8723A); - tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE_8723A); - } - - if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { - /* Use RTS rate 24M - does the mac80211 tell us which to use? */ - tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M << - TXDESC_RTS_RATE_SHIFT_8723A); - tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE_8723A); - tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE_8723A); - } + if (ieee80211_is_mgmt(hdr->frame_control)) { + tx_desc40->txdw4 = cpu_to_le32(tx_rate->hw_value); + tx_desc40->txdw3 |= + cpu_to_le32(TXDESC_USE_DRIVER_RATE_8723B); + tx_desc40->txdw4 |= + cpu_to_le32(6 << + TXDESC_RETRY_LIMIT_SHIFT_8723B); + tx_desc40->txdw4 |= + cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE_8723B); + } + + if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE || + (sta && vif && vif->bss_conf.use_short_preamble)) + tx_desc40->txdw5 |= + cpu_to_le32(TXDESC_SHORT_PREAMBLE_8723B); + + if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { + /* + * Use RTS rate 24M - does the mac80211 tell + * us which to use? + */ + tx_desc->txdw4 |= + cpu_to_le32(DESC_RATE_24M << + TXDESC_RTS_RATE_SHIFT_8723B); + tx_desc->txdw3 |= + cpu_to_le32(TXDESC_RTS_CTS_ENABLE_8723B); + tx_desc->txdw3 |= + cpu_to_le32(TXDESC_HW_RTS_ENABLE_8723B); + } + }; rtl8xxxu_calc_tx_desc_csum(tx_desc); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index b015c75f4841..687b9a938170 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -477,7 +477,7 @@ struct rtl8723bu_tx_desc { /* Word 4 */ #define TXDESC_RTS_RATE_SHIFT_8723A 0 #define TXDESC_RTS_RATE_MASK_8723A 0x3f -#define TXDESC_QOS BIT(6) +#define TXDESC_QOS_8723A BIT(6) #define TXDESC_HW_SEQ_ENABLE_8723A BIT(7) #define TXDESC_USE_DRIVER_RATE_8723A BIT(8) #define TXDESC_DISABLE_DATA_FB BIT(10) @@ -486,11 +486,13 @@ struct rtl8723bu_tx_desc { #define TXDESC_HW_RTS_ENABLE_8723A BIT(13) #define TXDESC_PRIME_CH_OFF_LOWER BIT(20) #define TXDESC_PRIME_CH_OFF_UPPER BIT(21) -#define TXDESC_SHORT_PREAMBLE BIT(24) +#define TXDESC_SHORT_PREAMBLE_8723A BIT(24) #define TXDESC_DATA_BW BIT(25) #define TXDESC_RTS_DATA_BW BIT(27) #define TXDESC_RTS_PRIME_CH_OFF_LOWER BIT(28) #define TXDESC_RTS_PRIME_CH_OFF_UPPER BIT(29) +#define TXDESC_DATA_RATE_FB_SHIFT_8723B 8 +#define TXDESC_DATA_RATE_FB_MASK_8723B 0x00001f00 #define TXDESC_RETRY_LIMIT_ENABLE_8723B BIT(17) #define TXDESC_RETRY_LIMIT_SHIFT_8723B 18 #define TXDESC_RETRY_LIMIT_MASK_8723B 0x00fc0000 @@ -498,6 +500,7 @@ struct rtl8723bu_tx_desc { #define TXDESC_RTS_RATE_MASK_8723B 0x3f000000 /* Word 5 */ +#define TXDESC_SHORT_PREAMBLE_8723B BIT(4) #define TXDESC_SHORT_GI BIT(6) #define TXDESC_CCX_TAG BIT(7) #define TXDESC_RETRY_LIMIT_ENABLE_8723A BIT(17) -- cgit v1.2.3 From e975b87cafd24d943f395823b1a000d1389f48ef Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:36 -0500 Subject: rtl8xxxu: Do not parse RX descriptor info for C2H packets C2H events are delivered as RX packets on 8723bu/8192eu. When receiving a C2H event, do not parse the rest of the RX descriptor as the info isn't valid. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 927fd3b13ae3..76793e9a9542 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7324,7 +7324,6 @@ static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv, (struct rtl8723bu_rx_desc *)skb->data; struct rtl8723au_phy_stats *phy_stats; int drvinfo_sz, desc_shift; - int rx_type; skb_pull(skb, sizeof(struct rtl8723bu_rx_desc)); @@ -7334,6 +7333,12 @@ static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv, desc_shift = rx_desc->shift; skb_pull(skb, drvinfo_sz + desc_shift); + if (rx_desc->rpt_sel) { + struct device *dev = &priv->udev->dev; + dev_dbg(dev, "%s: C2H packet\n", __func__); + return RX_TYPE_C2H; + } + rx_status->mactime = le32_to_cpu(rx_desc->tsfl); rx_status->flag |= RX_FLAG_MACTIME_START; @@ -7351,15 +7356,7 @@ static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv, rx_status->rate_idx = rx_desc->rxmcs; } - if (rx_desc->rpt_sel) { - struct device *dev = &priv->udev->dev; - dev_dbg(dev, "%s: C2H packet\n", __func__); - rx_type = RX_TYPE_C2H; - } else { - rx_type = RX_TYPE_DATA_PKT; - } - - return rx_type; + return RX_TYPE_DATA_PKT; } static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From 80b30b2af59af9400568af05b8b409e5a20da930 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:37 -0500 Subject: rtl8xxxu: Define 8723b H2C ramask command structure Define H2C command structure for setting the rate mask. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 687b9a938170..37657fee242a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -893,7 +893,7 @@ enum h2c_cmd_8723b { /* * Dynamic Mechanism Class: 010 */ - H2C_8723B_MACID_CFG = 0x40, + H2C_8723B_MACID_CFG_RAID = 0x40, H2C_8723B_TXBF = 0x41, H2C_8723B_RSSI_SETTING = 0x42, H2C_8723B_AP_REQ_TXRPT = 0x43, @@ -956,6 +956,15 @@ struct h2c_cmd { u8 arg; __le16 mask_lo; } __packed ramask; + struct { + u8 cmd; + u8 data1; + u8 data2; + u8 ramask1; + u8 ramask2; + u8 ramask3; + u8 ramask4; + } __packed b_macid_cfg; struct { u8 cmd; u8 data1; -- cgit v1.2.3 From f653e69009c633d099b34f7473b037c570c256f8 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:38 -0500 Subject: rtl8xxxu: Implement basic 8723b specific update_rate_mask() function Support for setting bandwidth and VHT parameters is still missing Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 38 ++++++++++++++++++++++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 16 +++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 76793e9a9542..5486ad70999f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6609,11 +6609,13 @@ static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw, rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); } -static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, int sgi) +static void rtl8723au_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, int sgi) { struct h2c_cmd h2c; + memset(&h2c, 0, sizeof(struct h2c_cmd)); + h2c.ramask.cmd = H2C_SET_RATE_MASK; h2c.ramask.mask_lo = cpu_to_le16(ramask & 0xffff); h2c.ramask.mask_hi = cpu_to_le16(ramask >> 16); @@ -6627,6 +6629,32 @@ static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ramask)); } +static void rtl8723bu_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, int sgi) +{ + struct h2c_cmd h2c; + u8 bw = 0; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.b_macid_cfg.cmd = H2C_8723B_MACID_CFG_RAID; + h2c.b_macid_cfg.ramask0 = ramask & 0xff; + h2c.b_macid_cfg.ramask1 = (ramask >> 8) & 0xff; + h2c.b_macid_cfg.ramask2 = (ramask >> 16) & 0xff; + h2c.b_macid_cfg.ramask3 = (ramask >> 24) & 0xff; + + h2c.ramask.arg = 0x80; + h2c.b_macid_cfg.data1 = 0; + if (sgi) + h2c.b_macid_cfg.data1 |= BIT(7); + + h2c.b_macid_cfg.data2 = bw; + + dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x, size %zi\n", + __func__, ramask, h2c.ramask.arg, sizeof(h2c.b_macid_cfg)); + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_macid_cfg)); +} + static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) { u32 val32; @@ -6693,7 +6721,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sgi = 1; rcu_read_unlock(); - rtl8xxxu_update_rate_mask(priv, ramask, sgi); + priv->fops->update_rate_mask(priv, ramask, sgi); rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); @@ -8210,6 +8238,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .parse_rx_desc = rtl8723au_parse_rx_desc, .enable_rf = rtl8723a_enable_rf, .set_tx_power = rtl8723a_set_tx_power, + .update_rate_mask = rtl8723au_update_rate_mask, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8234,6 +8263,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .init_statistics = rtl8723bu_init_statistics, .enable_rf = rtl8723b_enable_rf, .set_tx_power = rtl8723b_set_tx_power, + .update_rate_mask = rtl8723bu_update_rate_mask, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -8257,6 +8287,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .parse_rx_desc = rtl8723au_parse_rx_desc, .enable_rf = rtl8723a_enable_rf, .set_tx_power = rtl8723a_set_tx_power, + .update_rate_mask = rtl8723au_update_rate_mask, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8279,6 +8310,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .parse_rx_desc = rtl8723bu_parse_rx_desc, .enable_rf = rtl8723b_enable_rf, .set_tx_power = rtl8723b_set_tx_power, + .update_rate_mask = rtl8723au_update_rate_mask, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 37657fee242a..eea62f1a6db7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -958,12 +958,24 @@ struct h2c_cmd { } __packed ramask; struct { u8 cmd; + u8 macid; + /* + * [0:4] - RAID + * [7] - SGI + */ u8 data1; + /* + * [0:1] - Bandwidth + * [3] - No Update + * [4:5] - VHT enable + * [6] - DISPT + * [7] - DISRA + */ u8 data2; + u8 ramask0; u8 ramask1; u8 ramask2; u8 ramask3; - u8 ramask4; } __packed b_macid_cfg; struct { u8 cmd; @@ -1240,6 +1252,8 @@ struct rtl8xxxu_fileops { void (*enable_rf) (struct rtl8xxxu_priv *priv); void (*set_tx_power) (struct rtl8xxxu_priv *priv, int channel, bool ht40); + void (*update_rate_mask) (struct rtl8xxxu_priv *priv, + u32 ramask, int sgi); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; -- cgit v1.2.3 From 7d794eaa857e9475e8b02f5a53100cad569194e3 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:39 -0500 Subject: rtl8xxxu: Report media status using the correct H2C command for 8723bu Implement support for nextgen devices reporting connectition to the firmware. The H2C API for reporting connection to the firmware is different between the two device generations. Use the fileops structure to determine which one to call. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 46 ++++++++++++++++++++---- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 +++++ 2 files changed, 47 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 5486ad70999f..3441361df981 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6655,6 +6655,39 @@ static void rtl8723bu_update_rate_mask(struct rtl8xxxu_priv *priv, rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_macid_cfg)); } +static void rtl8723au_report_connect(struct rtl8xxxu_priv *priv, + u8 macid, bool connect) +{ + struct h2c_cmd h2c; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT; + + if (connect) + h2c.joinbss.data = H2C_JOIN_BSS_CONNECT; + else + h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT; + + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.joinbss)); +} + +static void rtl8723bu_report_connect(struct rtl8xxxu_priv *priv, + u8 macid, bool connect) +{ + struct h2c_cmd h2c; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.media_status_rpt.cmd = H2C_8723B_MEDIA_STATUS_RPT; + if (connect) + h2c.media_status_rpt.parm |= BIT(0); + else + h2c.media_status_rpt.parm &= ~BIT(0); + + rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); +} + static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) { u32 val32; @@ -6687,11 +6720,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 val8; if (changed & BSS_CHANGED_ASSOC) { - struct h2c_cmd h2c; - dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc); - memset(&h2c, 0, sizeof(struct h2c_cmd)); rtl8xxxu_set_linktype(priv, vif->type); if (bss_conf->assoc) { @@ -6731,16 +6761,14 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, 0xc000 | bss_conf->aid); - h2c.joinbss.data = H2C_JOIN_BSS_CONNECT; + priv->fops->report_connect(priv, 0, true); } else { val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); val8 |= BEACON_DISABLE_TSF_UPDATE; rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); - h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT; + priv->fops->report_connect(priv, 0, false); } - h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT; - rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.joinbss)); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -8239,6 +8267,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .enable_rf = rtl8723a_enable_rf, .set_tx_power = rtl8723a_set_tx_power, .update_rate_mask = rtl8723au_update_rate_mask, + .report_connect = rtl8723au_report_connect, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8264,6 +8293,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .enable_rf = rtl8723b_enable_rf, .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8723bu_update_rate_mask, + .report_connect = rtl8723bu_report_connect, .writeN_block_size = 1024, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, @@ -8288,6 +8318,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .enable_rf = rtl8723a_enable_rf, .set_tx_power = rtl8723a_set_tx_power, .update_rate_mask = rtl8723au_update_rate_mask, + .report_connect = rtl8723au_report_connect, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT_0, .mbox_ext_width = 2, @@ -8311,6 +8342,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .enable_rf = rtl8723b_enable_rf, .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8723au_update_rate_mask, + .report_connect = rtl8723au_report_connect, .writeN_block_size = 128, .mbox_ext_reg = REG_HMBOX_EXT0_8723B, .mbox_ext_width = 4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index eea62f1a6db7..2191b6bdb1fb 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -956,6 +956,12 @@ struct h2c_cmd { u8 arg; __le16 mask_lo; } __packed ramask; + struct { + u8 cmd; + u8 parm; + u8 macid; + u8 macid_end; + } __packed media_status_rpt; struct { u8 cmd; u8 macid; @@ -1254,6 +1260,8 @@ struct rtl8xxxu_fileops { bool ht40); void (*update_rate_mask) (struct rtl8xxxu_priv *priv, u32 ramask, int sgi); + void (*report_connect) (struct rtl8xxxu_priv *priv, + u8 macid, bool connect); int writeN_block_size; u16 mbox_ext_reg; char mbox_ext_width; -- cgit v1.2.3 From 739dc9f2f5c01dafc7336ffebd9d36bba4f9174e Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:40 -0500 Subject: rtl8xxxu: Dump contents of unhandled C2H events Dump the contents of unhandled C2H events. We should be handling all expected events, so this is debugging help in case an unexpected event happens. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 3441361df981..07f4ee0c7cad 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7446,7 +7446,10 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); break; default: - dev_info(dev, "Unhandled C2H event %02x\n", c2h->id); + dev_info(dev, "Unhandled C2H event %02x seq %02x\n", + c2h->id, c2h->seq); + print_hex_dump(KERN_INFO, "C2H content: ", DUMP_PREFIX_NONE, + 16, 1, c2h->raw.payload, len, false); break; } } -- cgit v1.2.3 From 55a18dd18052eaef908efbb27d5c6d7e0569048f Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:41 -0500 Subject: rtl8xxxu: Process C2H RA_REPORT events for 8723bu Handle RA_REPORTS events for 8723bu to not have them show up as unhandled. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 6 ++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 11 +++++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 07f4ee0c7cad..4164b1a3dbd3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7445,6 +7445,12 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, dev_dbg(dev, "C2H_MP_INFO ext ID %02x, status %02x\n", c2h->bt_mp_info.ext_id, c2h->bt_mp_info.status); break; + case C2H_8723B_RA_REPORT: + dev_dbg(dev, + "C2H RA RPT: rate %02x, unk %i, macid %02x, noise %i\n", + c2h->ra_report.rate, c2h->ra_report.dummy0_0, + c2h->ra_report.macid, c2h->ra_report.noisy_state); + break; default: dev_info(dev, "Unhandled C2H event %02x seq %02x\n", c2h->id, c2h->seq); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 2191b6bdb1fb..b44cb591bd36 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1033,6 +1033,7 @@ enum c2h_evt_8723b { C2H_8723B_BT_INFO = 9, C2H_8723B_HW_INFO_EXCH = 0x0a, C2H_8723B_BT_MP_INFO = 0x0b, + C2H_8723B_RA_REPORT = 0x0c, C2H_8723B_FW_DEBUG = 0xff, }; @@ -1121,6 +1122,16 @@ struct rtl8723bu_c2h { u8 a4; u8 a5; } __packed bt_info; + struct { + u8 rate:7; + u8 dummy0_0:1; + u8 macid; + u8 ldpc:1; + u8 txbf:1; + u8 noisy_state:1; + u8 dummy2_0:5; + u8 dummy3_0; + } __packed ra_report; }; }; -- cgit v1.2.3 From 87957081b749f3445fc6f10fae57280d45d6c6d5 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:42 -0500 Subject: rtl8xxxu: Pass RX rate to rx_parse_phystats and enable phystats for rtl8723bu rtl8xxxu_rx_parse_phystats() only needs the RX rate to determine whether to handle the stats as CCK or not. Parsing in the rate rather than the rx descriptor elimantes the need to handle multiple rx descriptor formats in the function. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4164b1a3dbd3..4e08f5e05c6e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7216,13 +7216,13 @@ error: static void rtl8xxxu_rx_parse_phystats(struct rtl8xxxu_priv *priv, struct ieee80211_rx_status *rx_status, - struct rtl8xxxu_rx_desc *rx_desc, - struct rtl8723au_phy_stats *phy_stats) + struct rtl8723au_phy_stats *phy_stats, + u32 rxmcs) { if (phy_stats->sgi_en) rx_status->flag |= RX_FLAG_SHORT_GI; - if (rx_desc->rxmcs < DESC_RATE_6M) { + if (rxmcs < DESC_RATE_6M) { /* * Handle PHY stats for CCK rates */ @@ -7350,7 +7350,8 @@ static int rtl8723au_parse_rx_desc(struct rtl8xxxu_priv *priv, skb_pull(skb, drvinfo_sz + desc_shift); if (rx_desc->phy_stats) - rtl8xxxu_rx_parse_phystats(priv, rx_status, rx_desc, phy_stats); + rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, + rx_desc->rxmcs); rx_status->mactime = le32_to_cpu(rx_desc->tsfl); rx_status->flag |= RX_FLAG_MACTIME_START; @@ -7395,6 +7396,10 @@ static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv, return RX_TYPE_C2H; } + if (rx_desc->phy_stats) + rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, + rx_desc->rxmcs); + rx_status->mactime = le32_to_cpu(rx_desc->tsfl); rx_status->flag |= RX_FLAG_MACTIME_START; -- cgit v1.2.3 From 6979494adf57afff0b6a5ad7ba77bdaef63274ad Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:43 -0500 Subject: rtl8xxxu: Remove unncessary semicolon This removes an superfluous semicolon. Reported-by: Fengguang Wu Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 4e08f5e05c6e..ce45c190979b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -7195,7 +7195,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, tx_desc->txdw3 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE_8723B); } - }; + } rtl8xxxu_calc_tx_desc_csum(tx_desc); -- cgit v1.2.3 From 0290e7d0fd1e91d86289abbdd2d785c945e6bb2e Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:44 -0500 Subject: rtl8xxxu: convert rtl8723bu_init_bt() into rtl8723b_enable_rf() rtl8723bu_init_bt() is effectively the function enabling RF, so name it appropriately. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 11 +---------- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ce45c190979b..aae45090d42a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -1596,10 +1596,6 @@ static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); } -static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) -{ -} - static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv) { u8 sps0; @@ -5953,7 +5949,7 @@ static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, } #endif -static void rtl8723bu_init_bt(struct rtl8xxxu_priv *priv) +static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) { struct h2c_cmd h2c; u32 val32; @@ -6508,10 +6504,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) else rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60); - /* Init BT hw config. */ - if (priv->fops->init_bt) - priv->fops->init_bt(priv); - /* Set NAV_UPPER to 30000us */ val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT); rtl8xxxu_write8(priv, REG_NAV_UPPER, val8); @@ -8300,7 +8292,6 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, - .init_bt = rtl8723bu_init_bt, .parse_rx_desc = rtl8723bu_parse_rx_desc, .init_aggregation = rtl8723bu_init_aggregation, .init_statistics = rtl8723bu_init_statistics, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index b44cb591bd36..776fd176e280 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1261,7 +1261,6 @@ struct rtl8xxxu_fileops { void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); void (*config_channel) (struct ieee80211_hw *hw); - void (*init_bt) (struct rtl8xxxu_priv *priv); int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb, struct ieee80211_rx_status *rx_status); void (*init_aggregation) (struct rtl8xxxu_priv *priv); -- cgit v1.2.3 From 37f44dc79a385fed307cdaad6003fd3c0ca99c07 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:45 -0500 Subject: rtl8xxxu: Use define for REG_PWR_DATA bits Use the bit define rather than hard code the value for REG_PWR_DATA bits. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 2 +- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index aae45090d42a..f936e03e0761 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5996,7 +5996,7 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, 0x0067, val8); val32 = rtl8xxxu_read32(priv, REG_PWR_DATA); - val32 |= BIT(11); + val32 |= PWR_DATA_EEPRPAD_RFE_CTRL_EN; rtl8xxxu_write32(priv, REG_PWR_DATA, val32); /* diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index a055362471e5..e0b9ea3811c0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -135,7 +135,7 @@ #define EFUSE_ACCESS_DISABLE 0x00 /* RTL8723 only */ #define REG_PWR_DATA 0x0038 -#define PWR_DATA_EEPRPAD_RFE_CTRL_EN BIT(11) +#define PWR_DATA_EEPRPAD_RFE_CTRL_EN BIT(11) #define REG_CAL_TIMER 0x003c #define REG_ACLK_MON 0x003e -- cgit v1.2.3 From fc89a41fa686b41b5339b3eaaa9851fa4c5551a9 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:46 -0500 Subject: rtl8xxxu: Implement 8723bu specific disable_rf() function Powering up the 8723bu RF should probably be matched by the ability to power it down again. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 17 ++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index f936e03e0761..50d2c5c8c153 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -6056,6 +6056,17 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ignore_wlan)); } +static void rtl8723b_disable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + + val32 = rtl8xxxu_read32(priv, REG_RX_WAIT_CCA); + val32 &= ~(BIT(22) | BIT(23)); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, val32); +} + static void rtl8723bu_init_aggregation(struct rtl8xxxu_priv *priv) { u32 agg_rx; @@ -7987,7 +7998,7 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) if (priv->usb_interrupts) usb_kill_anchored_urbs(&priv->int_anchor); - rtl8723a_disable_rf(priv); + priv->fops->disable_rf(priv); /* * Disable interrupts @@ -8271,6 +8282,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .config_channel = rtl8723au_config_channel, .parse_rx_desc = rtl8723au_parse_rx_desc, .enable_rf = rtl8723a_enable_rf, + .disable_rf = rtl8723a_disable_rf, .set_tx_power = rtl8723a_set_tx_power, .update_rate_mask = rtl8723au_update_rate_mask, .report_connect = rtl8723au_report_connect, @@ -8296,6 +8308,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .init_aggregation = rtl8723bu_init_aggregation, .init_statistics = rtl8723bu_init_statistics, .enable_rf = rtl8723b_enable_rf, + .disable_rf = rtl8723b_disable_rf, .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8723bu_update_rate_mask, .report_connect = rtl8723bu_report_connect, @@ -8321,6 +8334,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .config_channel = rtl8723au_config_channel, .parse_rx_desc = rtl8723au_parse_rx_desc, .enable_rf = rtl8723a_enable_rf, + .disable_rf = rtl8723a_disable_rf, .set_tx_power = rtl8723a_set_tx_power, .update_rate_mask = rtl8723au_update_rate_mask, .report_connect = rtl8723au_report_connect, @@ -8345,6 +8359,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .config_channel = rtl8723bu_config_channel, .parse_rx_desc = rtl8723bu_parse_rx_desc, .enable_rf = rtl8723b_enable_rf, + .disable_rf = rtl8723b_disable_rf, .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8723au_update_rate_mask, .report_connect = rtl8723au_report_connect, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 776fd176e280..9c535e8dbecf 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1266,6 +1266,7 @@ struct rtl8xxxu_fileops { void (*init_aggregation) (struct rtl8xxxu_priv *priv); void (*init_statistics) (struct rtl8xxxu_priv *priv); void (*enable_rf) (struct rtl8xxxu_priv *priv); + void (*disable_rf) (struct rtl8xxxu_priv *priv); void (*set_tx_power) (struct rtl8xxxu_priv *priv, int channel, bool ht40); void (*update_rate_mask) (struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From fe37d5f644e5fb7179ff6464482eca9a4ebf555c Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:47 -0500 Subject: rtl8xxxu: Implement device specific power_off function Implment 8723bu specific device power down, and make power_off() a fileops function. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 98 +++++++++++++++++++++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 + 3 files changed, 99 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 50d2c5c8c153..ef60e83ababd 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5240,6 +5240,64 @@ exit: return ret; } +static int rtl8723bu_active_to_emu(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + u32 val32; + int count, ret; + + /* Turn off RF */ + rtl8xxxu_write8(priv, REG_RF_CTRL, 0); + + /* Enable rising edge triggering interrupt */ + val16 = rtl8xxxu_read16(priv, REG_GPIO_INTM); + val16 &= ~GPIO_INTM_EDGE_TRIG_IRQ; + rtl8xxxu_write16(priv, REG_GPIO_INTM, val16); + + /* Release WLON reset 0x04[16]= 1*/ + val32 = rtl8xxxu_read32(priv, REG_GPIO_INTM); + val32 |= APS_FSMCO_WLON_RESET; + rtl8xxxu_write32(priv, REG_GPIO_INTM, val32); + + /* 0x0005[1] = 1 turn off MAC by HW state machine*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 |= BIT(1); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + if ((val8 & BIT(1)) == 0) + break; + udelay(10); + } + + if (!count) { + dev_warn(&priv->udev->dev, "%s: Disabling MAC timed out\n", + __func__); + ret = -EBUSY; + goto exit; + } + + /* Enable BT control XTAL setting */ + val8 = rtl8xxxu_read8(priv, REG_AFE_MISC); + val8 &= ~AFE_MISC_WL_XTAL_CTRL; + rtl8xxxu_write8(priv, REG_AFE_MISC, val8); + + /* 0x0000[5] = 1 analog Ips to digital, 1:isolation */ + val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL); + val8 |= SYS_ISO_ANALOG_IPS; + rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8); + + /* 0x0020[0] = 0 disable LDOA12 MACRO block*/ + val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL); + val8 &= ~LDOA15_ENABLE; + rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8); + +exit: + return ret; +} + static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv) { u8 val8; @@ -5932,6 +5990,38 @@ static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); } +static void rtl8723bu_power_off(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + + /* + * Disable TX report timer + */ + val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); + val8 &= ~TX_REPORT_CTRL_TIMER_ENABLE; + rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); + + rtl8xxxu_write16(priv, REG_CR, 0x0000); + + rtl8xxxu_active_to_lps(priv); + + /* Reset Firmware if running in RAM */ + if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL) + rtl8xxxu_firmware_self_reset(priv); + + /* Reset MCU */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + /* Reset MCU ready status */ + rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); + + rtl8723bu_active_to_emu(priv); + rtl8xxxu_emu_to_disabled(priv); +} + #ifdef NEED_PS_TDMA static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) @@ -6152,7 +6242,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) */ if (priv->rtlchip == 0x8723bu) { val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); - val8 |= BIT(1); + val8 |= TX_REPORT_CTRL_TIMER_ENABLE; rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); /* Set MAX RPT MACID */ rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1, 0x02); @@ -6545,7 +6635,7 @@ static void rtl8xxxu_disable_device(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; - rtl8xxxu_power_off(priv); + priv->fops->power_off(priv); } static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv, @@ -8277,6 +8367,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .parse_efuse = rtl8723au_parse_efuse, .load_firmware = rtl8723au_load_firmware, .power_on = rtl8723au_power_on, + .power_off = rtl8xxxu_power_off, .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, @@ -8300,6 +8391,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .parse_efuse = rtl8723bu_parse_efuse, .load_firmware = rtl8723bu_load_firmware, .power_on = rtl8723bu_power_on, + .power_off = rtl8723bu_power_off, .llt_init = rtl8xxxu_auto_llt_table, .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, @@ -8329,6 +8421,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .parse_efuse = rtl8192cu_parse_efuse, .load_firmware = rtl8192cu_load_firmware, .power_on = rtl8192cu_power_on, + .power_off = rtl8xxxu_power_off, .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, @@ -8354,6 +8447,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .parse_efuse = rtl8192eu_parse_efuse, .load_firmware = rtl8192eu_load_firmware, .power_on = rtl8192eu_power_on, + .power_off = rtl8xxxu_power_off, .llt_init = rtl8xxxu_auto_llt_table, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 9c535e8dbecf..bfa9d6c5d502 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1257,6 +1257,7 @@ struct rtl8xxxu_fileops { int (*parse_efuse) (struct rtl8xxxu_priv *priv); int (*load_firmware) (struct rtl8xxxu_priv *priv); int (*power_on) (struct rtl8xxxu_priv *priv); + void (*power_off) (struct rtl8xxxu_priv *priv); int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index e0b9ea3811c0..a8d5c9f98051 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -512,6 +512,8 @@ #define REG_PKT_LOSE_RPT 0x04e1 #define REG_PTCL_ERR_STATUS 0x04e2 #define REG_TX_REPORT_CTRL 0x04ec +#define TX_REPORT_CTRL_TIMER_ENABLE BIT(1) + #define REG_TX_REPORT_TIME 0x04f0 #define REG_DUMMY 0x04fc -- cgit v1.2.3 From 430b454c5a3951ffaf117d4e613e9cea03f86a90 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:48 -0500 Subject: rtl8xxxu: Flush FIFO before powering down devices This should help when reloading the driver for 8723bu devices Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 34 ++++++++++++++++++++++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 ++ 2 files changed, 36 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index ef60e83ababd..e444e2b91f40 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5687,6 +5687,36 @@ static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv) return 0; } +static int rtl8xxxu_flush_fifo(struct rtl8xxxu_priv *priv) +{ + u32 val32; + int retry, retval; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + + val32 = rtl8xxxu_read32(priv, REG_RXPKT_NUM); + val32 |= RXPKT_NUM_RW_RELEASE_EN; + rtl8xxxu_write32(priv, REG_RXPKT_NUM, val32); + + retry = 100; + retval = -EBUSY; + + do { + val32 = rtl8xxxu_read32(priv, REG_RXPKT_NUM); + if (val32 & RXPKT_NUM_RXDMA_IDLE) { + retval = 0; + break; + } + } while (retry--); + + rtl8xxxu_write16(priv, REG_RQPN_NPQ, 0); + rtl8xxxu_write32(priv, REG_RQPN, 0x80000000); + mdelay(2); + pr_info("%s: retry %i\n", __func__, retry); + + return retval; +} + static int rtl8723au_power_on(struct rtl8xxxu_priv *priv) { u8 val8; @@ -5957,6 +5987,8 @@ static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32); } + rtl8xxxu_flush_fifo(priv); + rtl8xxxu_active_to_lps(priv); /* Turn off RF */ @@ -5995,6 +6027,8 @@ static void rtl8723bu_power_off(struct rtl8xxxu_priv *priv) u8 val8; u16 val16; + rtl8xxxu_flush_fifo(priv); + /* * Disable TX report timer */ diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index a8d5c9f98051..e545e849f5a3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -404,6 +404,8 @@ #define REG_RXDMA_AGG_PG_TH 0x0280 #define RXDMA_USB_AGG_ENABLE BIT(31) #define REG_RXPKT_NUM 0x0284 +#define RXPKT_NUM_RXDMA_IDLE BIT(17) +#define RXPKT_NUM_RW_RELEASE_EN BIT(18) #define REG_RXDMA_STATUS 0x0288 /* Presumably only found on newer chips such as 8723bu */ -- cgit v1.2.3 From 145428ec7c6794c3ac78ddce2b073076c9c870d2 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:49 -0500 Subject: rtl8xxxu: Print a warning if flushing the FIFO fails Only print a warning if the FIFO flush fails, as opposed to printing the status unconditionally. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index e444e2b91f40..5c08db745d0f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5689,6 +5689,7 @@ static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv) static int rtl8xxxu_flush_fifo(struct rtl8xxxu_priv *priv) { + struct device *dev = &priv->udev->dev; u32 val32; int retry, retval; @@ -5712,7 +5713,9 @@ static int rtl8xxxu_flush_fifo(struct rtl8xxxu_priv *priv) rtl8xxxu_write16(priv, REG_RQPN_NPQ, 0); rtl8xxxu_write32(priv, REG_RQPN, 0x80000000); mdelay(2); - pr_info("%s: retry %i\n", __func__, retry); + + if (!retry) + dev_warn(dev, "Failed to flush FIFO\n"); return retval; } -- cgit v1.2.3 From 7d4ccb8bae85550035328bddd20197614dfe415a Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:50 -0500 Subject: rtl8xxxu: Use correct 8051 reset function for 8723b parts 8723b needs more action, so implement support for device specific reset functions. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 40 ++++++++++++++++++++++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 5c08db745d0f..81777c430312 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2720,12 +2720,44 @@ static void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv) val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); val8 &= ~BIT(0); rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); sys_func &= ~SYS_FUNC_CPU_ENABLE; rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); val8 |= BIT(0); rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + sys_func |= SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); +} + +static void rtl8723bu_reset_8051(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 sys_func; + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL); + val8 &= ~BIT(1); + rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); + sys_func &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL); + val8 &= ~BIT(1); + rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 |= BIT(0); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + sys_func |= SYS_FUNC_CPU_ENABLE; rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); } @@ -2758,7 +2790,7 @@ static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv) * Reset the 8051 in order for the firmware to start running, * otherwise it won't come up on the 8192eu */ - rtl8xxxu_reset_8051(priv); + priv->fops->reset_8051(priv); /* Wait for firmware to become ready */ for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) { @@ -2805,7 +2837,7 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) if (val8 & MCU_FW_RAM_SEL) { pr_info("do the RAM reset\n"); rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); - rtl8xxxu_reset_8051(priv); + priv->fops->reset_8051(priv); } /* MCU firmware download enable */ @@ -8405,6 +8437,7 @@ static struct rtl8xxxu_fileops rtl8723au_fops = { .load_firmware = rtl8723au_load_firmware, .power_on = rtl8723au_power_on, .power_off = rtl8xxxu_power_off, + .reset_8051 = rtl8xxxu_reset_8051, .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, @@ -8429,6 +8462,7 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = { .load_firmware = rtl8723bu_load_firmware, .power_on = rtl8723bu_power_on, .power_off = rtl8723bu_power_off, + .reset_8051 = rtl8723bu_reset_8051, .llt_init = rtl8xxxu_auto_llt_table, .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, @@ -8459,6 +8493,7 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = { .load_firmware = rtl8192cu_load_firmware, .power_on = rtl8192cu_power_on, .power_off = rtl8xxxu_power_off, + .reset_8051 = rtl8xxxu_reset_8051, .llt_init = rtl8xxxu_init_llt_table, .phy_iq_calibrate = rtl8723au_phy_iq_calibrate, .config_channel = rtl8723au_config_channel, @@ -8485,6 +8520,7 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = { .load_firmware = rtl8192eu_load_firmware, .power_on = rtl8192eu_power_on, .power_off = rtl8xxxu_power_off, + .reset_8051 = rtl8xxxu_reset_8051, .llt_init = rtl8xxxu_auto_llt_table, .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate, .config_channel = rtl8723bu_config_channel, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index bfa9d6c5d502..7b73654e1368 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1258,6 +1258,7 @@ struct rtl8xxxu_fileops { int (*load_firmware) (struct rtl8xxxu_priv *priv); int (*power_on) (struct rtl8xxxu_priv *priv); void (*power_off) (struct rtl8xxxu_priv *priv); + void (*reset_8051) (struct rtl8xxxu_priv *priv); int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page); void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv); void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv); -- cgit v1.2.3 From ccfe1e85322090649d2fae599e55300c1512bf15 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 29 Feb 2016 17:05:51 -0500 Subject: rtl8xxxu: Temporarily disable 8192eu device init To reduce the patch volume, temporariliy disable 8192eu device init. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 81777c430312..abdff458b80f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -2562,6 +2562,10 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) raw[i + 6], raw[i + 7]); } } + /* + * Temporarily disable 8192eu support + */ + return -EINVAL; return 0; } -- cgit v1.2.3 From 83d6f1f15f8cce844b0a131cbc63e444620e48b5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 14 Mar 2016 15:18:36 +0100 Subject: ath9k: fix buffer overrun for ar9287 Code that was added back in 2.6.38 has an obvious overflow when accessing a static array, and at the time it was added only a code comment was put in front of it as a reminder to have it reviewed properly. This has not happened, but gcc-6 now points to the specific overflow: drivers/net/wireless/ath/ath9k/eeprom.c: In function 'ath9k_hw_get_gain_boundaries_pdadcs': drivers/net/wireless/ath/ath9k/eeprom.c:483:44: error: array subscript is above array bounds [-Werror=array-bounds] maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~ It turns out that the correct array length exists in the local 'intercepts' variable of this function, so we can just use that instead of hardcoding '4', so this patch changes all three instances to use that variable. The other two instances were already correct, but it's more consistent this way. Signed-off-by: Arnd Bergmann Fixes: 940cd2c12ebf ("ath9k_hw: merge the ar9287 version of ath9k_hw_get_gain_boundaries_pdadcs") Signed-off-by: David S. Miller --- drivers/net/wireless/ath/ath9k/eeprom.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 73fb4232f9f2..a794157a147d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -477,10 +477,9 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, if (match) { if (AR_SREV_9287(ah)) { - /* FIXME: array overrun? */ for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_9287[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_9287[idxL].pwrPdg[i], data_9287[idxL].vpdPdg[i], @@ -490,7 +489,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, } else if (eeprom_4k) { for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_4k[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_4k[idxL].pwrPdg[i], data_4k[idxL].vpdPdg[i], @@ -500,7 +499,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, } else { for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_def[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_def[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_def[idxL].pwrPdg[i], data_def[idxL].vpdPdg[i], -- cgit v1.2.3 From 362210e0dff4eb7bb36a9b34dbef3b39d779d95e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 14 Mar 2016 15:18:37 +0100 Subject: ath9k: fix misleading indentation A cleanup patch in linux-3.18 moved around some code in the ath9k driver and left some code to be indented in a misleading way, made worse by the addition of some new code for p2p mode, as discovered by a new gcc-6 warning: drivers/net/wireless/ath/ath9k/init.c: In function 'ath9k_set_hw_capab': drivers/net/wireless/ath/ath9k/init.c:851:4: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation] hw->wiphy->iface_combinations = if_comb; ^~ drivers/net/wireless/ath/ath9k/init.c:847:3: note: ...this 'if' clause, but it is not if (ath9k_is_chanctx_enabled()) ^~ The code is in fact correct, but the indentation is not, so I'm reformatting it as it should have been after the original cleanup. Signed-off-by: Arnd Bergmann Fixes: 499afaccf6f3 ("ath9k: Isolate ath9k_use_chanctx module parameter") Fixes: eb61f9f623f7 ("ath9k: advertise p2p dev support when chanctx") Signed-off-by: David S. Miller --- drivers/net/wireless/ath/ath9k/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d4e0ac946c3a..1c226d63bb03 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -848,8 +848,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE); - hw->wiphy->iface_combinations = if_comb; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + hw->wiphy->iface_combinations = if_comb; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); } hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; -- cgit v1.2.3