* [RFC 1/5] mac80211: Add support for transmit beam forming.
@ 2010-11-10 12:23 Vivek Natarajan
2010-11-10 12:23 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Vivek Natarajan
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Vivek Natarajan @ 2010-11-10 12:23 UTC (permalink / raw)
To: linux-wireless
Enable beamforming if the driver and the AP are capable of sending
and receiving beam-formed frames.
Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
---
include/linux/ieee80211.h | 41 ++++++++++++++++++++++++++++++++++++++++-
include/net/cfg80211.h | 6 ++++++
include/net/mac80211.h | 9 +++++++--
net/mac80211/cfg.c | 7 +++++++
net/mac80211/ht.c | 18 ++++++++++++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 19 +++++++++++++++++++
net/mac80211/rx.c | 10 ++++++++++
net/mac80211/sta_info.c | 2 ++
net/mac80211/sta_info.h | 6 ++++++
net/mac80211/status.c | 19 +++++++++++++++++++
net/mac80211/tx.c | 27 ++++++++++++++++++++++++---
net/mac80211/work.c | 1 +
13 files changed, 160 insertions(+), 6 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index ed5a03c..ba92b73 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -120,6 +120,8 @@
#define IEEE80211_QOS_CTL_TID_MASK 0x000F
#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007
+#define IEEE80211_QOS_HTC_LEN 4
+
/* U-APSD queue for WMM IEs sent by AP */
#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7)
@@ -140,6 +142,9 @@
#define IEEE80211_HT_CTL_LEN 4
+#define IEEE80211_HTC2_CSI_NONCOMP_BF 0x00800000
+#define IEEE80211_HTC2_CSI_COMP_BF 0x00c00000
+
struct ieee80211_hdr {
__le16 frame_control;
__le16 duration_id;
@@ -169,6 +174,17 @@ struct ieee80211_qos_hdr {
__le16 qos_ctrl;
} __attribute__ ((packed));
+struct ieee80211_qos_htc_hdr {
+ __le16 frame_control;
+ __le16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ __le16 seq_ctrl;
+ __le16 qos_ctrl;
+ __le32 htc;
+} __attribute__ ((packed));
+
/**
* ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
* @fc: frame control bytes in little-endian byteorder
@@ -827,6 +843,29 @@ struct ieee80211_mcs_info {
u8 reserved[3];
} __attribute__((packed));
+struct ieee80211_txbf_caps {
+ u32 implicit_rx_capable:1,
+ rx_staggered_sounding:1,
+ tx_staggered_sounding:1,
+ rx_ndp_capable:1,
+ tx_ndp_capable:1,
+ implicit_txbf_capable:1,
+ calibration:2,
+ explicit_csi_txbf_capable:1,
+ explicit_noncomp_steering:1,
+ explicit_comp_steering:1,
+ explicit_csi_feedback:2,
+ explicit_noncomp_bf:2,
+ explicit_comp_bf:2,
+ minimal_grouping:2,
+ csi_bfer_antennas:2,
+ noncomp_bfer_antennas:2,
+ comp_bfer_antennas:2,
+ csi_max_rows_bfer:2,
+ channel_estimation_cap:2,
+ reserved:3;
+};
+
/* 802.11n HT capability MSC set */
#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff
#define IEEE80211_HT_MCS_TX_DEFINED 0x01
@@ -862,7 +901,7 @@ struct ieee80211_ht_cap {
struct ieee80211_mcs_info mcs;
__le16 extended_ht_cap_info;
- __le32 tx_BF_cap_info;
+ struct ieee80211_txbf_caps tx_BF_cap_info;
u8 antenna_selection_info;
} __attribute__ ((packed));
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e5702f5..23b120a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -210,6 +210,12 @@ struct ieee80211_sta_ht_cap {
u8 ampdu_factor;
u8 ampdu_density;
struct ieee80211_mcs_info mcs;
+ struct ieee80211_txbf_caps txbf;
+ bool explicit_compbf;
+ bool explicit_noncompbf;
+ bool implicit_bf;
+ bool staggered_sounding;
+ u8 channel_estimation_cap;
};
/**
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9fdf982..0818c58 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -321,6 +321,8 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
* @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this
* frame and selects the maximum number of streams that it can use.
+ * @IEEE80211_TX_CTL_TXBF_UPDATE: Channel information needs to be updated
+ * for beamforming of Tx frames.
*
* Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -349,6 +351,8 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
IEEE80211_TX_CTL_LDPC = BIT(22),
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
+ IEEE80211_TX_CTL_TXBF_UPDATE = BIT(25),
+ IEEE80211_TX_CTL_STAG_SOUND = BIT(26),
};
#define IEEE80211_TX_CTL_STBC_SHIFT 23
@@ -364,7 +368,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \
IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \
IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \
- IEEE80211_TX_CTL_STBC)
+ IEEE80211_TX_CTL_STBC | IEEE80211_TX_CTL_TXBF_UPDATE)
/**
* enum mac80211_rate_control_flags - per-rate flags set by the
@@ -900,7 +904,8 @@ struct ieee80211_sta {
u8 addr[ETH_ALEN];
u16 aid;
struct ieee80211_sta_ht_cap ht_cap;
-
+ bool txbf;
+ u8 channel_estimation_cap;
/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 18bd0e5..926cc8d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -698,6 +698,13 @@ static void sta_apply_parameters(struct ieee80211_local *local,
params->ht_capa,
&sta->sta.ht_cap);
+ if (sta->sta.ht_cap.explicit_compbf ||
+ sta->sta.ht_cap.explicit_noncompbf ||
+ sta->sta.ht_cap.implicit_bf) {
+ sta->sta.txbf = true;
+ sta->bf_update_cv = true;
+ }
+
if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
switch (params->plink_action) {
case PLINK_ACTION_OPEN:
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 75d679d..5223ea7 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -24,6 +24,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
{
u8 ampdu_info, tx_mcs_set_cap;
int i, max_tx_streams;
+ struct ieee80211_txbf_caps bfee, bfmr;
BUG_ON(!ht_cap);
@@ -99,6 +100,23 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
/* handle MCS rate 32 too */
if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
ht_cap->mcs.rx_mask[32/8] |= 1;
+
+ bfee = ht_cap_ie->tx_BF_cap_info;
+ bfmr = sband->ht_cap.txbf;
+
+ if (bfmr.explicit_comp_steering && (bfee.explicit_comp_bf != 0))
+ ht_cap->explicit_compbf = true;
+
+ if (bfmr.explicit_noncomp_steering && (bfee.explicit_noncomp_bf != 0))
+ ht_cap->explicit_noncompbf = true;
+
+ if (bfmr.implicit_txbf_capable && bfee.implicit_rx_capable)
+ ht_cap->implicit_bf = true;
+
+ if (bfmr.tx_staggered_sounding && bfee.rx_staggered_sounding)
+ ht_cap->staggered_sounding = true;
+
+ ht_cap->channel_estimation_cap = bfee.channel_estimation_cap;
}
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b80c386..e0eecbf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1202,6 +1202,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
void ieee80211_ba_session_work(struct work_struct *work);
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
+void ieee80211_txbf_cv_work(struct work_struct *work);
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a3a9421..0ee85f9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -63,6 +63,8 @@
#define TMR_RUNNING_TIMER 0
#define TMR_RUNNING_CHANSW 1
+#define TXBF_CV_TIMER 1000
+
/*
* All cfg80211 functions have to be called outside a locked
* section so that they can acquire a lock themselves... This
@@ -1237,6 +1239,17 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
}
+void ieee80211_txbf_cv_work(struct work_struct *work)
+{
+ struct sta_info *sta =
+ container_of(work, struct sta_info, txbf_cv_work.work);
+ struct ieee80211_local *local = sta->local;
+
+ sta->bf_update_cv = true;
+ ieee80211_queue_delayed_work(&local->hw,
+ &sta->txbf_cv_work, TXBF_CV_TIMER);
+}
+
static bool ieee80211_assoc_success(struct ieee80211_work *wk,
struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -1343,6 +1356,12 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
ap_ht_cap_flags = sta->sta.ht_cap.cap;
+ if (sta->sta.ht_cap.explicit_compbf ||
+ sta->sta.ht_cap.explicit_noncompbf ||
+ sta->sta.ht_cap.implicit_bf) {
+ sta->sta.txbf = true;
+ sta->bf_update_cv = true;
+ }
rate_control_rate_init(sta);
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 902b03e..a012fb6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1455,6 +1455,16 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
if (!ieee80211_is_data_qos(hdr->frame_control))
return RX_CONTINUE;
+ /* Qos frame with Order bit set indicates an HTC frame */
+ if (ieee80211_has_order(hdr->frame_control)) {
+ memmove(data + IEEE80211_QOS_HTC_LEN, data,
+ ieee80211_hdrlen(hdr->frame_control) -
+ IEEE80211_QOS_HTC_LEN);
+ hdr = (struct ieee80211_hdr *)skb_pull(rx->skb,
+ IEEE80211_QOS_HTC_LEN);
+ hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER);
+ }
+
/* remove the qos control field, update frame type and meta-data */
memmove(data + IEEE80211_QOS_CTL_LEN, data,
ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 6d8f897..829398e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
spin_lock_init(&sta->flaglock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+ INIT_DELAYED_WORK(&sta->txbf_cv_work, ieee80211_txbf_cv_work);
mutex_init(&sta->ampdu_mlme.mtx);
memcpy(sta->sta.addr, addr, ETH_ALEN);
@@ -691,6 +692,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
cancel_work_sync(&sta->drv_unblock_wk);
+ cancel_delayed_work_sync(&sta->txbf_cv_work);
rate_control_remove_sta_debugfs(sta);
ieee80211_sta_debugfs_remove(sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9265aca..61631e3 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -312,6 +312,12 @@ struct sta_info {
struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[STA_TID_NUM];
+ bool txbf;
+ bool bf_update_cv;
+ bool bf_sound_pending;
+ bool allow_cv_update;
+ struct delayed_work txbf_cv_work;
+
#ifdef CONFIG_MAC80211_MESH
/*
* Mesh peer link attributes
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3153c19..b0447ca 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -209,6 +209,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
return;
}
+ if (ieee80211_has_order(fc)) {
+ if ((info->flags & IEEE80211_TX_STAT_ACK) &&
+ (sta->bf_sound_pending)) {
+ sta->bf_sound_pending = false;
+ ieee80211_queue_delayed_work(&local->hw,
+ &sta->txbf_cv_work, 1000);
+ } else
+ sta->bf_update_cv = true;
+ }
+
+
+ if ((info->flags & IEEE80211_TX_CTL_TXBF_UPDATE) &&
+ !(sta->bf_sound_pending)) {
+ if (sta->sta.ht_cap.explicit_compbf ||
+ sta->sta.ht_cap.explicit_noncompbf ||
+ sta->sta.ht_cap.implicit_bf)
+ sta->bf_update_cv = true;
+ }
+
if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
(rates_idx != -1))
sta->last_tx_rate = info->status.rates[rates_idx];
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 96c5943..5900cf2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1888,6 +1888,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) {
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
hdrlen += 2;
+ if (sta->bf_update_cv)
+ hdrlen += 4;
}
/*
@@ -1973,9 +1975,28 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (ieee80211_is_data_qos(fc)) {
__le16 *qos_control;
-
- qos_control = (__le16*) skb_push(skb, 2);
- memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
+ __le32 *htc;
+
+ if (sta->bf_update_cv) {
+ hdr.frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER);
+ htc = (__le32 *) skb_push(skb, 4);
+ sta->bf_sound_pending = true;
+ *htc = 0;
+ sta->bf_update_cv = false;
+
+ if (sta->sta.ht_cap.explicit_compbf)
+ *htc |= IEEE80211_HTC2_CSI_COMP_BF;
+ else if (sta->sta.ht_cap.explicit_noncompbf)
+ *htc |= IEEE80211_HTC2_CSI_NONCOMP_BF;
+
+ ieee80211_queue_delayed_work(&local->hw,
+ &sta->txbf_cv_work, 1000);
+ qos_control = (__le16 *) skb_push(skb, 2);
+ memcpy(skb_push(skb, hdrlen - 6), &hdr, hdrlen - 6);
+ } else {
+ qos_control = (__le16 *) skb_push(skb, 2);
+ memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
+ };
/*
* Maybe we could actually set some fields here, for now just
* initialise to zero to indicate no special operation.
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index ae344d1..7676567 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -190,6 +190,7 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
/* extended capabilities */
pos += sizeof(__le16);
+ memcpy(pos, &sband->ht_cap.txbf, sizeof(sband->ht_cap.txbf));
/* BF capabilities */
pos += sizeof(__le32);
--
1.6.3.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 2/5] ath: Add a keycache entry if beamforming is enabled. 2010-11-10 12:23 [RFC 1/5] mac80211: Add support for transmit beam forming Vivek Natarajan @ 2010-11-10 12:23 ` Vivek Natarajan 2010-11-10 12:23 ` [RFC 3/5] ath9k_common: Add HTC field length if order bit is set Vivek Natarajan 2010-11-10 12:47 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Felix Fietkau 2010-11-10 12:44 ` [RFC 1/5] mac80211: Add support for transmit beam forming Felix Fietkau 2010-11-10 16:22 ` Johannes Berg 2 siblings, 2 replies; 11+ messages in thread From: Vivek Natarajan @ 2010-11-10 12:23 UTC (permalink / raw) To: linux-wireless Keycache entry for a sta has the details of the negotiated beamforming parameters which is to be used by the hardware while trasmitting to that specific sta. Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> --- drivers/net/wireless/ath/ath.h | 2 ++ drivers/net/wireless/ath/key.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 501050c..214a25f 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -177,5 +177,7 @@ int ath_key_config(struct ath_common *common, bool ath_hw_keyreset(struct ath_common *common, u16 entry); void ath_hw_cycle_counters_update(struct ath_common *common); int32_t ath_hw_get_listen_time(struct ath_common *common); +int ath_txbf_key_config(struct ath_common *common, + struct ieee80211_sta *sta); #endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 62e3dac..11f562e 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -115,6 +115,7 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, void *ah = common->ah; u32 key0, key1, key2, key3, key4; u32 keyType; + u32 txbf = 0; if (entry >= common->keymax) { ath_print(common, ATH_DBG_FATAL, @@ -199,6 +200,9 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), + keyType | txbf); + /* Write MAC address for the entry */ (void) ath_hw_keysetmac(common, entry, mac); @@ -435,6 +439,31 @@ static int ath_reserve_key_cache_slot(struct ath_common *common, return -1; } +int ath_txbf_key_config(struct ath_common *common, struct ieee80211_sta *sta) +{ + int idx, ret; + struct ath_keyval hk; + + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + + memset(&hk, 0, sizeof(hk)); + hk.kv_type = ATH_CIPHER_CLR; + + idx = ath_reserve_key_cache_slot(common, 0); + + if (idx < 0) + return -ENOSPC; + + ret = ath_hw_set_keycache_entry(common, idx, &hk, sta->addr); + + if (!ret) + return -EIO; + + return idx; +} +EXPORT_SYMBOL(ath_txbf_key_config); + /* * Configure encryption in the HW. */ -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC 3/5] ath9k_common: Add HTC field length if order bit is set. 2010-11-10 12:23 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Vivek Natarajan @ 2010-11-10 12:23 ` Vivek Natarajan 2010-11-10 12:23 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Vivek Natarajan 2010-11-10 12:47 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Felix Fietkau 1 sibling, 1 reply; 11+ messages in thread From: Vivek Natarajan @ 2010-11-10 12:23 UTC (permalink / raw) To: linux-wireless Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> --- drivers/net/wireless/ath/ath9k/common.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 48b07c3..2e56200 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -36,6 +36,8 @@ int ath9k_cmn_padpos(__le16 frame_control) if (ieee80211_is_data_qos(frame_control)) { padpos += IEEE80211_QOS_CTL_LEN; } + if (ieee80211_has_order(frame_control)) + padpos += IEEE80211_QOS_HTC_LEN; return padpos; } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC 4/5] ath9k: Add support for Tx beamforming feature. 2010-11-10 12:23 ` [RFC 3/5] ath9k_common: Add HTC field length if order bit is set Vivek Natarajan @ 2010-11-10 12:23 ` Vivek Natarajan 2010-11-10 12:23 ` [RFC 5/5] ath9k_hw: Add support for Tx beamforming Vivek Natarajan 2010-11-10 13:06 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Felix Fietkau 0 siblings, 2 replies; 11+ messages in thread From: Vivek Natarajan @ 2010-11-10 12:23 UTC (permalink / raw) To: linux-wireless Beamforming is enabled with the latest hardware if the module parameter is set. Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 + drivers/net/wireless/ath/ath9k/init.c | 9 + drivers/net/wireless/ath/ath9k/main.c | 22 ++ drivers/net/wireless/ath/ath9k/rc.c | 453 ++++++++++++++++++++------------ drivers/net/wireless/ath/ath9k/rc.h | 90 +++++++- drivers/net/wireless/ath/ath9k/xmit.c | 43 +++- 6 files changed, 454 insertions(+), 165 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8a2b04e..5216999 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -270,6 +270,8 @@ struct ath_node { struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; u8 mpdudensity; + bool txbf; + u8 key_idx; }; #define AGGR_CLEANUP BIT(1) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index f14fe53..531efe7 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -38,6 +38,10 @@ int led_blink; module_param_named(blink, led_blink, int, 0444); MODULE_PARM_DESC(blink, "Enable LED blink on activity"); +int txbf; +module_param_named(txbf, txbf, int, 0444); +MODULE_PARM_DESC(blink, "Enable TxBF"); + /* We use the hw_value as an index into our private channel structure */ #define CHAN2G(_freq, _idx) { \ @@ -239,6 +243,11 @@ static void setup_ht_cap(struct ath_softc *sc, ht_info->mcs.rx_mask[i] = 0xff; ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; + + if (txbf && AR_SREV_9300_20_OR_LATER(ah)) { + ar9003_fill_txbf_capabilities(sc->sc_ah); + ht_info->txbf = ar9003_get_txbf_capabilities(sc->sc_ah); + } } static int ath9k_reg_notifier(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4b93a72..bea2568 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -553,8 +553,10 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an; + struct ieee80211_sta_ht_cap *ht_cap; an = (struct ath_node *)sta->drv_priv; + ht_cap = &sta->ht_cap; if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); @@ -562,6 +564,15 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) sta->ht_cap.ampdu_factor); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); } + + if (ht_cap->explicit_compbf || + ht_cap->explicit_noncompbf || + ht_cap->implicit_bf) { + an->txbf = true; + an->key_idx = ath_txbf_key_config(ath9k_hw_common(sc->sc_ah), + sta); + set_bit(an->key_idx, ath9k_hw_common(sc->sc_ah)->keymap); + } } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -1858,6 +1869,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_node *an = (struct ath_node *)sta->drv_priv; int ret = 0; if (modparam_nohwcrypt) @@ -1869,6 +1881,16 @@ static int ath9k_set_key(struct ieee80211_hw *hw, switch (cmd) { case SET_KEY: + if (sta && sta->txbf && + (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + if (key->cipher == WLAN_CIPHER_SUITE_CCMP) + key->keyidx = an->key_idx; + else { + ath_hw_keyreset(common, an->key_idx); + clear_bit(an->key_idx, common->keymap); + } + } + ret = ath_key_config(common, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 85c8e93..0b9c405 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -23,141 +23,141 @@ static const struct ath_rate_table ar5416_11na_ratetable = { 68, 8, /* MCS start */ { - [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, + [0] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 6000, 5400, 0, 12, 0, 0, 0, 0 }, /* 6 Mb */ - [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, + [1] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 9000, 7800, 1, 18, 0, 1, 1, 1 }, /* 9 Mb */ - [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, + [2] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 12000, 10000, 2, 24, 2, 2, 2, 2 }, /* 12 Mb */ - [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, + [3] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 18000, 13900, 3, 36, 2, 3, 3, 3 }, /* 18 Mb */ - [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, + [4] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 24000, 17300, 4, 48, 4, 4, 4, 4 }, /* 24 Mb */ - [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, + [5] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 36000, 23000, 5, 72, 4, 5, 5, 5 }, /* 36 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, + [6] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 48000, 27400, 6, 96, 4, 6, 6, 6 }, /* 48 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, + [7] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 54000, 29300, 7, 108, 4, 7, 7, 7 }, /* 54 Mb */ - [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500, + [8] = { RC_HT_SDT_2040, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 6500, 6400, 0, 0, 0, 38, 8, 38 }, /* 6.5 Mb */ - [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, + [9] = { RC_HT_SDT_20, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 13000, 12700, 1, 1, 2, 39, 9, 39 }, /* 13 Mb */ - [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, + [10] = { RC_HT_SDT_20, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 19500, 18800, 2, 2, 2, 40, 10, 40 }, /* 19.5 Mb */ - [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, + [11] = { RC_HT_SD_20, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 26000, 25000, 3, 3, 4, 41, 11, 41 }, /* 26 Mb */ - [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, + [12] = { RC_HT_SD_20, TRUE_N2_T_N1_T_S, WLAN_RC_PHY_HT_20_SS, 39000, 36700, 4, 4, 4, 42, 12, 42 }, /* 39 Mb */ - [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, + [13] = { RC_HT_S_20, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_20_SS, 52000, 48100, 5, 5, 4, 43, 13, 43 }, /* 52 Mb */ - [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, + [14] = { RC_HT_S_20, TRUE_N2_T_N1_S, WLAN_RC_PHY_HT_20_SS, 58500, 53500, 6, 6, 4, 44, 14, 44 }, /* 58.5 Mb */ - [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, + [15] = { RC_HT_S_20, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_20_SS, 65000, 59000, 7, 7, 4, 45, 16, 46 }, /* 65 Mb */ - [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, + [16] = { RC_HT_S_20, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_20_SS_HGI, 72200, 65400, 7, 7, 4, 45, 16, 46 }, /* 75 Mb */ - [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, + [17] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_DS, 13000, 12700, 8, 8, 0, 47, 17, 47 }, /* 13 Mb */ - [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, + [18] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_DS, 26000, 24800, 9, 9, 2, 48, 18, 48 }, /* 26 Mb */ - [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, + [19] = { RC_HT_T_20, TRUE_N2_D_N1_D, WLAN_RC_PHY_HT_20_DS, 39000, 36600, 10, 10, 2, 49, 19, 49 }, /* 39 Mb */ - [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, + [20] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 52000, 48100, 11, 11, 4, 50, 20, 50 }, /* 52 Mb */ - [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, + [21] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 78000, 69500, 12, 12, 4, 51, 21, 51 }, /* 78 Mb */ - [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, + [22] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 104000, 89500, 13, 13, 4, 52, 22, 52 }, /* 104 Mb */ - [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, + [23] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 117000, 98900, 14, 14, 4, 53, 23, 53 }, /* 117 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, + [24] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T, WLAN_RC_PHY_HT_20_DS, 130000, 108300, 15, 15, 4, 54, 25, 55 }, /* 130 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, + [25] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS_HGI, 144400, 120000, 15, 15, 4, 54, 25, 55 }, /* 144.4 Mb */ - [26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, + [26] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 19500, 17400, 16, 16, 0, 56, 26, 56 }, /* 19.5 Mb */ - [27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, + [27] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 39000, 35100, 17, 17, 2, 57, 27, 57 }, /* 39 Mb */ - [28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, + [28] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 58500, 52600, 18, 18, 2, 58, 28, 58 }, /* 58.5 Mb */ - [29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, + [29] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 78000, 70400, 19, 19, 4, 59, 29, 59 }, /* 78 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, + [30] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 117000, 104900, 20, 20, 4, 60, 31, 61 }, /* 117 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, + [31] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS_HGI, 130000, 115800, 20, 20, 4, 60, 31, 61 }, /* 130 Mb*/ - [32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, + [32] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_TS, 156000, 137200, 21, 21, 4, 62, 33, 63 }, /* 156 Mb */ - [33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, + [33] = { RC_HT_T_20, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_20_TS_HGI, 173300, 151100, 21, 21, 4, 62, 33, 63 }, /* 173.3 Mb */ - [34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, + [34] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_TS, 175500, 152800, 22, 22, 4, 64, 35, 65 }, /* 175.5 Mb */ - [35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, + [35] = { RC_HT_T_20, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_20_TS_HGI, 195000, 168400, 22, 22, 4, 64, 35, 65 }, /* 195 Mb*/ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, + [36] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_TS, 195000, 168400, 23, 23, 4, 66, 37, 67 }, /* 195 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, + [37] = { RC_HT_T_20, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_20_TS_HGI, 216700, 185000, 23, 23, 4, 66, 37, 67 }, /* 216.7 Mb */ - [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, + [38] = { RC_HT_SDT_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 13500, 13200, 0, 0, 0, 38, 38, 38 }, /* 13.5 Mb*/ - [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, + [39] = { RC_HT_SDT_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 27500, 25900, 1, 1, 2, 39, 39, 39 }, /* 27.0 Mb*/ - [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, + [40] = { RC_HT_SDT_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 40500, 38600, 2, 2, 2, 40, 40, 40 }, /* 40.5 Mb*/ - [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, + [41] = { RC_HT_SD_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 54000, 49800, 3, 3, 4, 41, 41, 41 }, /* 54 Mb */ - [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, + [42] = { RC_HT_SD_40, TRUE_N2_T_N1_T_S, WLAN_RC_PHY_HT_40_SS, 81500, 72200, 4, 4, 4, 42, 42, 42 }, /* 81 Mb */ - [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000, + [43] = { RC_HT_S_40, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_40_SS, 108000, 92900, 5, 5, 4, 43, 43, 43 }, /* 108 Mb */ - [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, + [44] = { RC_HT_S_40, TRUE_N2_T_N1_S, WLAN_RC_PHY_HT_40_SS, 121500, 102700, 6, 6, 4, 44, 44, 44 }, /* 121.5 Mb*/ - [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, + [45] = { RC_HT_S_40, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_40_SS, 135000, 112000, 7, 7, 4, 45, 46, 46 }, /* 135 Mb */ - [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, + [46] = { RC_HT_S_40, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_40_SS_HGI, 150000, 122000, 7, 7, 4, 45, 46, 46 }, /* 150 Mb */ - [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, + [47] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_DS, 27000, 25800, 8, 8, 0, 47, 47, 47 }, /* 27 Mb */ - [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, + [48] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_DS, 54000, 49800, 9, 9, 2, 48, 48, 48 }, /* 54 Mb */ - [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, + [49] = { RC_HT_T_40, TRUE_N2_D_N1_D, WLAN_RC_PHY_HT_40_DS, 81000, 71900, 10, 10, 2, 49, 49, 49 }, /* 81 Mb */ - [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, + [50] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 108000, 92500, 11, 11, 4, 50, 50, 50 }, /* 108 Mb */ - [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, + [51] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 162000, 130300, 12, 12, 4, 51, 51, 51 }, /* 162 Mb */ - [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, + [52] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 216000, 162800, 13, 13, 4, 52, 52, 52 }, /* 216 Mb */ - [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, + [53] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 243000, 178200, 14, 14, 4, 53, 53, 53 }, /* 243 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, + [54] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T, WLAN_RC_PHY_HT_40_DS, 270000, 192100, 15, 15, 4, 54, 55, 55 }, /* 270 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, + [55] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS_HGI, 300000, 207000, 15, 15, 4, 54, 55, 55 }, /* 300 Mb */ - [56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, + [56] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 40500, 36100, 16, 16, 0, 56, 56, 56 }, /* 40.5 Mb */ - [57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, + [57] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 81000, 72900, 17, 17, 2, 57, 57, 57 }, /* 81 Mb */ - [58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, + [58] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 121500, 108300, 18, 18, 2, 58, 58, 58 }, /* 121.5 Mb */ - [59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, + [59] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 162000, 142000, 19, 19, 4, 59, 59, 59 }, /* 162 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, + [60] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 243000, 205100, 20, 20, 4, 60, 61, 61 }, /* 243 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, + [61] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS_HGI, 270000, 224700, 20, 20, 4, 60, 61, 61 }, /* 270 Mb */ - [62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, + [62] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_TS, 324000, 263100, 21, 21, 4, 62, 63, 63 }, /* 324 Mb */ - [63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, + [63] = { RC_HT_T_40, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_40_TS_HGI, 360000, 288000, 21, 21, 4, 62, 63, 63 }, /* 360 Mb */ - [64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, + [64] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_TS, 364500, 290700, 22, 22, 4, 64, 65, 65 }, /* 364.5 Mb */ - [65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, + [65] = { RC_HT_T_40, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_40_TS_HGI, 405000, 317200, 22, 22, 4, 64, 65, 65 }, /* 405 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, + [66] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_TS, 405000, 317200, 23, 23, 4, 66, 67, 67 }, /* 405 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, + [67] = { RC_HT_T_40, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_40_TS_HGI, 450000, 346400, 23, 23, 4, 66, 67, 67 }, /* 450 Mb */ }, 50, /* probe interval */ @@ -171,149 +171,149 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { 72, 12, /* MCS start */ { - [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000, + [0] = { RC_ALL, FALSE, WLAN_RC_PHY_CCK, 1000, 900, 0, 2, 0, 0, 0, 0 }, /* 1 Mb */ - [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000, + [1] = { RC_ALL, FALSE, WLAN_RC_PHY_CCK, 2000, 1900, 1, 4, 1, 1, 1, 1 }, /* 2 Mb */ - [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500, + [2] = { RC_ALL, FALSE, WLAN_RC_PHY_CCK, 5500, 4900, 2, 11, 2, 2, 2, 2 }, /* 5.5 Mb */ - [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000, + [3] = { RC_ALL, FALSE, WLAN_RC_PHY_CCK, 11000, 8100, 3, 22, 3, 3, 3, 3 }, /* 11 Mb */ - [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, + [4] = { RC_INVALID, FALSE, WLAN_RC_PHY_OFDM, 6000, 5400, 4, 12, 4, 4, 4, 4 }, /* 6 Mb */ - [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, + [5] = { RC_INVALID, FALSE, WLAN_RC_PHY_OFDM, 9000, 7800, 5, 18, 4, 5, 5, 5 }, /* 9 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, + [6] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 12000, 10100, 6, 24, 6, 6, 6, 6 }, /* 12 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, + [7] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 18000, 14100, 7, 36, 6, 7, 7, 7 }, /* 18 Mb */ - [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, + [8] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 24000, 17700, 8, 48, 8, 8, 8, 8 }, /* 24 Mb */ - [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, + [9] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 36000, 23700, 9, 72, 8, 9, 9, 9 }, /* 36 Mb */ - [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, + [10] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 48000, 27400, 10, 96, 8, 10, 10, 10 }, /* 48 Mb */ - [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, + [11] = { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 54000, 30900, 11, 108, 8, 11, 11, 11 }, /* 54 Mb */ - [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500, + [12] = { RC_INVALID, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 6500, 6400, 0, 0, 4, 42, 12, 42 }, /* 6.5 Mb */ - [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, + [13] = { RC_HT_SDT_20, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 13000, 12700, 1, 1, 6, 43, 13, 43 }, /* 13 Mb */ - [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, + [14] = { RC_HT_SDT_20, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 19500, 18800, 2, 2, 6, 44, 14, 44 }, /* 19.5 Mb*/ - [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, + [15] = { RC_HT_SD_20, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_20_SS, 26000, 25000, 3, 3, 8, 45, 15, 45 }, /* 26 Mb */ - [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, + [16] = { RC_HT_SD_20, TRUE_N2_T_N1_ALL, WLAN_RC_PHY_HT_20_SS, 39000, 36700, 4, 4, 8, 46, 16, 46 }, /* 39 Mb */ - [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, + [17] = { RC_HT_S_20, TRUE_N2_F_N1_D_S, WLAN_RC_PHY_HT_20_SS, 52000, 48100, 5, 5, 8, 47, 17, 47 }, /* 52 Mb */ - [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, + [18] = { RC_HT_S_20, TRUE_N2_T_N1_S, WLAN_RC_PHY_HT_20_SS, 58500, 53500, 6, 6, 8, 48, 18, 48 }, /* 58.5 Mb */ - [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, + [19] = { RC_HT_S_20, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_20_SS, 65000, 59000, 7, 7, 8, 49, 20, 50 }, /* 65 Mb */ - [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, + [20] = { RC_HT_S_20, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_20_SS_HGI, 72200, 65400, 7, 7, 8, 49, 20, 50 }, /* 65 Mb*/ - [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, + [21] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_DS, 13000, 12700, 8, 8, 4, 51, 21, 51 }, /* 13 Mb */ - [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, + [22] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_DS, 26000, 24800, 9, 9, 6, 52, 22, 52 }, /* 26 Mb */ - [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, + [23] = { RC_HT_T_20, TRUE_N2_D_N1_F, WLAN_RC_PHY_HT_20_DS, 39000, 36600, 10, 10, 6, 53, 23, 53 }, /* 39 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, + [24] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T, WLAN_RC_PHY_HT_20_DS, 52000, 48100, 11, 11, 8, 54, 24, 54 }, /* 52 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, + [25] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 78000, 69500, 12, 12, 8, 55, 25, 55 }, /* 78 Mb */ - [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, + [26] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 104000, 89500, 13, 13, 8, 56, 26, 56 }, /* 104 Mb */ - [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, + [27] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS, 117000, 98900, 14, 14, 8, 57, 27, 57 }, /* 117 Mb */ - [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, + [28] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T, WLAN_RC_PHY_HT_20_DS, 130000, 108300, 15, 15, 8, 58, 29, 59 }, /* 130 Mb */ - [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, + [29] = { RC_HT_DT_20, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_20_DS_HGI, 144400, 120000, 15, 15, 8, 58, 29, 59 }, /* 144.4 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, + [30] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 19500, 17400, 16, 16, 4, 60, 30, 60 }, /* 19.5 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, + [31] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 39000, 35100, 17, 17, 6, 61, 31, 61 }, /* 39 Mb */ - [32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, + [32] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 58500, 52600, 18, 18, 6, 62, 32, 62 }, /* 58.5 Mb */ - [33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, + [33] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 78000, 70400, 19, 19, 8, 63, 33, 63 }, /* 78 Mb */ - [34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, + [34] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS, 117000, 104900, 20, 20, 8, 64, 35, 65 }, /* 117 Mb */ - [35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, + [35] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_20_TS_HGI, 130000, 115800, 20, 20, 8, 64, 35, 65 }, /* 130 Mb */ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, + [36] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_TS, 156000, 137200, 21, 21, 8, 66, 37, 67 }, /* 156 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, + [37] = { RC_HT_T_20, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_20_TS_HGI, 173300, 151100, 21, 21, 8, 66, 37, 67 }, /* 173.3 Mb */ - [38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, + [38] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_TS, 175500, 152800, 22, 22, 8, 68, 39, 69 }, /* 175.5 Mb */ - [39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, + [39] = { RC_HT_T_20, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_20_TS_HGI, 195000, 168400, 22, 22, 8, 68, 39, 69 }, /* 195 Mb */ - [40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, + [40] = { RC_HT_T_20, FALSE, WLAN_RC_PHY_HT_20_TS, 195000, 168400, 23, 23, 8, 70, 41, 71 }, /* 195 Mb */ - [41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, + [41] = { RC_HT_T_20, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_20_TS_HGI, 216700, 185000, 23, 23, 8, 70, 41, 71 }, /* 216.7 Mb */ - [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, + [42] = { RC_HT_SDT_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 13500, 13200, 0, 0, 8, 42, 42, 42 }, /* 13.5 Mb */ - [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, + [43] = { RC_HT_SDT_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 27500, 25900, 1, 1, 8, 43, 43, 43 }, /* 27.0 Mb */ - [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, + [44] = { RC_HT_SDT_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 40500, 38600, 2, 2, 8, 44, 44, 44 }, /* 40.5 Mb */ - [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, + [45] = { RC_HT_SD_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 54000, 49800, 3, 3, 8, 45, 45, 45 }, /* 54 Mb */ - [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, + [46] = { RC_HT_SD_40, TRUE_N_1_2_ALL, WLAN_RC_PHY_HT_40_SS, 81500, 72200, 4, 4, 8, 46, 46, 46 }, /* 81 Mb */ - [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000, + [47] = { RC_HT_S_40, TRUE_N2_F_N1_D_S, WLAN_RC_PHY_HT_40_SS, 108000, 92900, 5, 5, 8, 47, 47, 47 }, /* 108 Mb */ - [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, + [48] = { RC_HT_S_40, TRUE_N2_T_N1_S, WLAN_RC_PHY_HT_40_SS, 121500, 102700, 6, 6, 8, 48, 48, 48 }, /* 121.5 Mb */ - [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, + [49] = { RC_HT_S_40, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_40_SS, 135000, 112000, 7, 7, 8, 49, 50, 50 }, /* 135 Mb */ - [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, + [50] = { RC_HT_S_40, TRUE_N2_F_N1_S, WLAN_RC_PHY_HT_40_SS_HGI, 150000, 122000, 7, 7, 8, 49, 50, 50 }, /* 150 Mb */ - [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, + [51] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_DS, 27000, 25800, 8, 8, 8, 51, 51, 51 }, /* 27 Mb */ - [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, + [52] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_DS, 54000, 49800, 9, 9, 8, 52, 52, 52 }, /* 54 Mb */ - [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, + [53] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_DS, 81000, 71900, 10, 10, 8, 53, 53, 53 }, /* 81 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, + [54] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T, WLAN_RC_PHY_HT_40_DS, 108000, 92500, 11, 11, 8, 54, 54, 54 }, /* 108 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, + [55] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 162000, 130300, 12, 12, 8, 55, 55, 55 }, /* 162 Mb */ - [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, + [56] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 216000, 162800, 13, 13, 8, 56, 56, 56 }, /* 216 Mb */ - [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, + [57] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS, 243000, 178200, 14, 14, 8, 57, 57, 57 }, /* 243 Mb */ - [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, + [58] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T, WLAN_RC_PHY_HT_40_DS, 270000, 192100, 15, 15, 8, 58, 59, 59 }, /* 270 Mb */ - [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, + [59] = { RC_HT_DT_40, TRUE_N2_ALL_N1_T_D, WLAN_RC_PHY_HT_40_DS_HGI, 300000, 207000, 15, 15, 8, 58, 59, 59 }, /* 300 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, + [60] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 40500, 36100, 16, 16, 8, 60, 60, 60 }, /* 40.5 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, + [61] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 81000, 72900, 17, 17, 8, 61, 61, 61 }, /* 81 Mb */ - [62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, + [62] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 121500, 108300, 18, 18, 8, 62, 62, 62 }, /* 121.5 Mb */ - [63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, + [63] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 162000, 142000, 19, 19, 8, 63, 63, 63 }, /* 162 Mb */ - [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, + [64] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS, 243000, 205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */ - [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20, 8, 64, 65, 65 }, /* 270 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, + [65] = { RC_INVALID, FALSE, WLAN_RC_PHY_HT_40_TS_HGI, 270000, + 224700, 20, 20, 8, 64, 65, 65 }, /* 170 Mb */ + [66] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_TS, 324000, 263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, + [67] = { RC_HT_T_40, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_40_TS_HGI, 360000, 288000, 21, 21, 8, 66, 67, 67 }, /* 360 Mb */ - [68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, + [68] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_TS, 364500, 290700, 22, 22, 8, 68, 69, 69 }, /* 364.5 Mb */ - [69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, + [69] = { RC_HT_T_40, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_40_TS_HGI, 405000, 317200, 22, 22, 8, 68, 69, 69 }, /* 405 Mb */ - [70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, + [70] = { RC_HT_T_40, FALSE, WLAN_RC_PHY_HT_40_TS, 405000, 317200, 23, 23, 8, 70, 71, 71 }, /* 405 Mb */ - [71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, + [71] = { RC_HT_T_40, TRUE_N2_T_N1_T, WLAN_RC_PHY_HT_40_TS_HGI, 450000, 346400, 23, 23, 8, 70, 71, 71 }, /* 450 Mb */ }, 50, /* probe interval */ @@ -324,21 +324,21 @@ static const struct ath_rate_table ar5416_11a_ratetable = { 8, 0, { - { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0, 12, 0}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 1, 18, 0}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 2, 24, 2}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 3, 36, 2}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 4, 48, 4}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 5, 72, 4}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 6, 96, 4}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 7, 108, 4}, }, 50, /* probe interval */ @@ -349,29 +349,29 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 12, 0, { - { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0, 2, 0}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 1, 4, 1}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 2, 11, 2}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 3, 22, 3}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ + { RC_INVALID, FALSE, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 4, 12, 4}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + { RC_INVALID, FALSE, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 5, 18, 4}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 6, 24, 6}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 7, 36, 6}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 8, 48, 8}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 9, 72, 8}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 10, 96, 8}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ + { RC_L_SDT, FALSE, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 11, 108, 8}, }, 50, /* probe interval */ @@ -541,6 +541,72 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, return hi; } +static bool ath_valid_txbf_rate(struct ath_rate_priv *ath_rc_priv, + const struct ath_rate_table *rate_table, + struct ath_rateset *rateset, + u32 capflag, u8 i, u8 j) +{ + u32 phy = rate_table->info[j].phy; + u16 rate_flags = rate_table->info[j].rate_flags; + u8 rate = rateset->rs_rates[i]; + + if (ath_rc_priv->usedNss == NSS_DIM_2) { + if (RC_TS_ONLY(rate_table->info[rate].rate_flags)) { + if (!(rate_table->info[j].tx_bf & TRUE_TS_N2)) + return true; + if (capflag & WLAN_RC_40_FLAG) { + if ((phy < WLAN_RC_PHY_HT_40_SS) || + ((phy > WLAN_RC_PHY_HT_40_TS) && + (phy < WLAN_RC_PHY_HT_40_SS_HGI))) + return true; + } + } else if (RC_DS_ONLY(rate_table->info[rate].rate_flags)) { + if (!(rate_table->info[j].tx_bf & TRUE_DS_N2)) + return true; + + if (capflag & WLAN_RC_40_FLAG) { + if ((phy < WLAN_RC_PHY_HT_40_SS) || + (phy > WLAN_RC_PHY_HT_40_TS)) + return true; + } + } + } else if (ath_rc_priv->usedNss == NSS_DIM_1) { + if (RC_TS_ONLY(rate_table->info[rate].rate_flags)) { + if (!(rate_table->info[j].tx_bf & TRUE_TS_N1)) + return true; + + if (capflag & WLAN_RC_40_FLAG) { + if ((phy < WLAN_RC_PHY_HT_40_SS) || + ((phy > WLAN_RC_PHY_HT_40_TS) && + (phy < WLAN_RC_PHY_HT_40_SS_HGI))) + return true; + } + } else if (RC_DS_ONLY(rate_table->info[rate].rate_flags)) { + if (!(rate_table->info[j].tx_bf & TRUE_DS_N1)) + return true; + + if (capflag & WLAN_RC_40_FLAG) { + if ((phy < WLAN_RC_PHY_HT_40_SS) || + ((phy > WLAN_RC_PHY_HT_40_TS) && + (phy < WLAN_RC_PHY_HT_40_SS_HGI))) + return true; + } + } else if (RC_SS_ONLY(rate_table->info[rate].rate_flags)) { + if (!(rate_table->info[j].tx_bf & TRUE_SS_N1)) + return true; + + if (capflag & WLAN_RC_40_FLAG) { + if ((phy < WLAN_RC_PHY_HT_40_SS) || + (phy > WLAN_RC_PHY_HT_40_TS)) + return true; + } + } + } else { + if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag)) + return true; + } + return false; +} static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, u8 *mcs_set, u32 capflag) @@ -557,6 +623,19 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; + if (capflag & WLAN_RC_TxBF_FLAG) { + if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy)) + continue; + else { + if (ath_valid_txbf_rate(ath_rc_priv, + rate_table, + rateset, + capflag, + i, j)) + continue; + } + } + if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) || !(rate_flags & WLAN_RC_CAP_STREAM(capflag)) || !WLAN_RC_PHY_HT_VALID(rate_flags, capflag)) @@ -749,6 +828,14 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, if (rate_control_send_low(sta, priv_sta, txrc)) return; +#define MS(_v, _f) (((_v) & _f) >> _f##_S) + ath_rc_priv->txbf_sounding = 0; + if (ieee80211_has_order(fc)) { + ath_rc_priv->txbf_sounding = 1; + if (sta->ht_cap.staggered_sounding) + tx_info->flags |= IEEE80211_TX_CTL_STAG_SOUND; + } + /* * For Multi Rate Retry we use a different number of * retry attempt counts. This ends up looking like this: @@ -764,17 +851,26 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, rate_table = ath_rc_priv->rate_table; rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); + if (ath_rc_priv->txbf_sounding) { + if (rix > 9) + rix -= 2; + if (rix == 9) + rix = 8; + } + /* * If we're in HT mode and both us and our peer supports LDPC. * We don't need to check our own device's capabilities as our own * ht capabilities would have already been intersected with our peer's. */ if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) + (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) && + !(ath_rc_priv->txbf)) tx_info->flags |= IEEE80211_TX_CTL_LDPC; if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) + (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) && + !(ath_rc_priv->txbf)) tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT); if (is_probe) { @@ -807,6 +903,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, rix, 1); + + if (ath_rc_priv->txbf && ath_rc_priv->txbf_sounding) { + if (rates[i].flags & IEEE80211_TX_RC_MCS) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; + else { + /* Remove sounding */ + hdr->frame_control &= + ~cpu_to_le16(IEEE80211_FCTL_ORDER); + } + } } /* @@ -1163,6 +1269,9 @@ static void ath_rc_tx_status(struct ath_softc *sc, !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) return; + if (ath_rc_priv->txbf_sounding) + return; + rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry); } @@ -1189,6 +1298,10 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, } } +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + static void ath_rc_init(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_supported_band *sband, @@ -1218,6 +1331,15 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->valid_phy_ratecnt[i] = 0; } + ath_rc_priv->usedNss = 0; + if (ath_rc_priv->txbf) { + ath_rc_priv->usedNss = MIN(MIN((ar5416_get_ntxchains( + sc->sc_ah->txchainmask) - 1), + TX_STREAM_USED_NUM(ath_rc_priv)), + sta->ht_cap.channel_estimation_cap + + 1); + } + if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ hi = ath_rc_init_validrates(ath_rc_priv, rate_table, @@ -1279,6 +1401,8 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, caps |= WLAN_RC_40_FLAG; if (is_sgi) caps |= WLAN_RC_SGI_FLAG; + if (sta->txbf) + caps |= WLAN_RC_TxBF_FLAG; } return caps; @@ -1437,6 +1561,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, rate_table = ath_choose_rate_table(sc, sband->band, sta->ht_cap.ht_supported); + if (sta->txbf) + ath_rc_priv->txbf = 1; + ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi); ath_rc_init(sc, priv_sta, sband, sta, rate_table); } diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 2f46a22..ec2fe4e 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -36,11 +36,80 @@ struct ath_softc; #define RC_HT_20 0x0010 #define RC_HT_40 0x0020 +/* flag for TxBF */ +/* + * N2;N1 mean Nss(number of spatial streams) of Beamforming + * Nss=2 : dualStream & tripleStream mode (DS & TS) + * Nss=1 : singleStream ,dualStream mode & tripleStream mode (SS, DS & TS) + * + * TRUE_AS_NB + * A: which stream mode supported (TS, DS or SS) + * B: under which Nss number +*/ +#define FALSE 0 +#define TRUE_TS_N2 (0x01) +#define TRUE_DS_N2 (0x02) +#define TRUE_TS_DS_N2 (TRUE_TS_N2|TRUE_DS_N2) +#define TRUE_TS_N1 (0x04) +#define TRUE_DS_N1 (0x08) +#define TRUE_SS_N1 (0x10) +#define TRUE_TS_SS_N1 (TRUE_TS_N1|TRUE_SS_N1) +#define TRUE_DS_SS_N1 (TRUE_DS_N1|TRUE_SS_N1) +#define TRUE_TS_DS_N1 (TRUE_TS_N1|TRUE_DS_N1) +#define TRUE_ALL_N1 (TRUE_TS_N1|TRUE_DS_N1|TRUE_SS_N1) + +/* + * TRUE_N2_A_N1_B + * A: support under Nss=2 + * B: support under Nss=1 + * ALL : rate supported for all configuration of its Nss + * S,D,T : rate supported for single, dual ,triple stream of its Nss + * F : rate not supported + * + * (Nss2 | Nss1) + */ +#define TRUE_N_1_2_ALL (TRUE_TS_DS_N2|TRUE_ALL_N1) +#define FALSE_N_ALL (FALSE|FALSE) +#define TRUE_N2_ALL_N1_F (TRUE_TS_DS_N2|FALSE) +#define TRUE_N2_T_N1_F (TRUE_TS_N2|FALSE) +#define TRUE_N2_D_N1_F (TRUE_DS_N2|FALSE) +#define TRUE_N2_ALL_N1_T (TRUE_TS_DS_N2|TRUE_TS_N1) +#define TRUE_N2_T_N1_T (TRUE_TS_N2|TRUE_TS_N1) +#define TRUE_N2_D_N1_T (TRUE_DS_N2|TRUE_TS_N1) +#define TRUE_N2_F_N1_T (FALSE|TRUE_TS_N1) +#define TRUE_N2_ALL_N1_D (TRUE_TS_DS_N2|TRUE_DS_N1) +#define TRUE_N2_T_N1_D (TRUE_TS_N2|TRUE_DS_N1) +#define TRUE_N2_D_N1_D (TRUE_DS_N2|TRUE_DS_N1) +#define TRUE_N2_F_N1_D (FALSE|TRUE_DS_N1) +#define TRUE_N2_ALL_N1_S (TRUE_TS_DS_N2 | TRUE_SS_N1) +#define TRUE_N2_T_N1_S (TRUE_TS_N2 | TRUE_SS_N1) +#define TRUE_N2_D_N1_S (TRUE_DS_N2 | TRUE_SS_N1) +#define TRUE_N2_F_N1_S (FALSE | TRUE_SS_N1) +#define TRUE_N2_ALL_N1_T_S (TRUE_TS_DS_N2 | TRUE_TS_SS_N1) +#define TRUE_N2_T_N1_T_S (TRUE_TS_N2 | TRUE_TS_SS_N1) +#define TRUE_N2_D_N1_T_S (TRUE_DS_N2 | TRUE_TS_SS_N1) +#define TRUE_N2_F_N1_T_S (FALSE | TRUE_TS_SS_N1) +#define TRUE_N2_ALL_N1_D_S (TRUE_TS_DS_N2 | TRUE_DS_SS_N1) +#define TRUE_N2_T_N1_D_S (TRUE_TS_N2 | TRUE_DS_SS_N1) +#define TRUE_N2_D_N1_D_S (TRUE_DS_N2 | TRUE_DS_SS_N1) +#define TRUE_N2_F_N1_D_S (FALSE | TRUE_DS_SS_N1) +#define TRUE_N2_ALL_N1_T_D (TRUE_TS_DS_N2 | TRUE_TS_DS_N1) +#define TRUE_N2_T_N1_T_D (TRUE_TS_N2 | TRUE_TS_DS_N1) +#define TRUE_N2_D_N1_T_D (TRUE_DS_N2 | TRUE_TS_DS_N1) +#define TRUE_N2_F_N1_T_D (FALSE | TRUE_TS_DS_N1) +#define TRUE_N2_T_N1_ALL (TRUE_TS_N2 | TRUE_ALL_N1) +#define TRUE_N2_D_N1_ALL (TRUE_DS_N2 | TRUE_ALL_N1) +#define TRUE_N2_F_N1_ALL (FALSE | TRUE_ALL_N1) + + + #define RC_STREAM_MASK 0xe #define RC_DS_OR_LATER(f) ((((f) & RC_STREAM_MASK) == RC_DS) || \ (((f) & RC_STREAM_MASK) == (RC_DS | RC_TS))) #define RC_TS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_TS) #define RC_SS_OR_LEGACY(f) ((f) & (RC_SS | RC_LEGACY)) +#define RC_DS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_DS) +#define RC_SS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_SS) #define RC_HT_2040 (RC_HT_20 | RC_HT_40) #define RC_ALL_STREAM (RC_SS | RC_DS | RC_TS) @@ -66,6 +135,9 @@ struct ath_softc; #define RC_ALL (RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM) +#define WLAN_RC_TxBF_FLAG (0x400) +#define WLAN_RC_CEC_FLAG (0x1800) +#define WLAN_RC_CEC_FLAG_S 11 enum { WLAN_RC_PHY_OFDM, WLAN_RC_PHY_CCK, @@ -132,7 +204,12 @@ enum { #define WLAN_RC_40_FLAG (0x04) #define WLAN_RC_SGI_FLAG (0x08) #define WLAN_RC_HT_FLAG (0x10) - +#define ATH_RC_TXBF_FLAG 0x800 +#define ATH_RC_CEC_FLAG 0x3000 +#define ATH_RC_CEC_FLAG_S 12 +#define ATH_RC_SOUNDING_FLAG 0x4000 +#define VALID_TXBF_RATE(_rate, _nss) ((_rate >= 8) && \ + (_rate < ((_nss == 2) ? 24 : 16))) /** * struct ath_rate_table - Rate Control table * @rate_cnt: total number of rates for the given wireless mode @@ -157,6 +234,7 @@ struct ath_rate_table { int mcs_start; struct { u16 rate_flags; + u8 tx_bf; u8 phy; u32 ratekbps; u32 user_ratekbps; @@ -216,6 +294,9 @@ struct ath_rate_priv { u32 probe_interval; u32 prev_data_rix; u32 tx_triglevel_max; + u8 usedNss; + u8 txbf:1, /* transmit beamforming capable */ + txbf_sounding:1; /* sounding indicator */ struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; @@ -249,5 +330,12 @@ static inline void ath_rate_control_unregister(void) { } #endif +#define NSS_DIM_2 0x2 +#define NSS_DIM_1 0x1 + +#define TX_STREAM_USED_NUM(_pSib) (3*(_pSib->ht_cap & (WLAN_RC_TS_FLAG)) + \ + 2*(_pSib->ht_cap & (WLAN_RC_DS_FLAG)) + 1) +#define OPPOSITE_CEC_NUM(_capflag) \ + (((_capflag & WLAN_RC_CEC_FLAG) >> WLAN_RC_CEC_FLAG_S) + 1) #endif /* RC_H */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2bc422e..73e3723 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -668,18 +668,32 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, struct list_head *bf_q) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) +#define MS(_v, _f) (((_v) & _f) >> _f##_S) struct ath_buf *bf, *bf_first, *bf_prev = NULL; int rl = 0, nframes = 0, ndelim, prev_al = 0; u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; + u8 is_prev_sounding = 0; bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); do { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + /* send the sounding frame as a single frame */ + if (bf->bf_flags & + (ATH9K_TXDESC_TXBF_SOUND | ATH9K_TXDESC_TXBF_STAG_SOUND)) { + if (nframes != 0) + break; + else + is_prev_sounding = 1; + } + + if ((nframes == 1) & (is_prev_sounding)) + break; + /* do not step over block-ack window */ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) { status = ATH_AGGR_BAW_CLOSED; @@ -1532,6 +1546,25 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); + if (ieee80211_has_order(hdr->frame_control)) { + struct ieee80211_qos_htc_hdr *qos_hdr; + qos_hdr = (struct ieee80211_qos_htc_hdr *)skb->data; + + if (ieee80211_has_order(hdr->frame_control)) { + if ((qos_hdr->htc & cpu_to_le32( + IEEE80211_HTC2_CSI_COMP_BF | + IEEE80211_HTC2_CSI_NONCOMP_BF))) { + if (tx_info->flags & + IEEE80211_TX_CTL_STAG_SOUND) + flags |= + ATH9K_TXDESC_TXBF_STAG_SOUND; + else + flags |= + ATH9K_TXDESC_TXBF_SOUND; + } + } + } + if (rates[i].flags & IEEE80211_TX_RC_MCS) { /* MCS rates */ series[i].Rate = rix | 0x80; @@ -1588,6 +1621,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, struct ath_softc *sc = aphy->sc; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_node *an = NULL; int hdrlen; __le16 fc; int padpos, padsize; @@ -1634,7 +1668,11 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_frmlen += tx_info->control.hw_key->icv_len; bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; } else { - bf->bf_keyix = ATH9K_TXKEYIX_INVALID; + if (tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + bf->bf_keyix = an->key_idx; + } else + bf->bf_keyix = ATH9K_TXKEYIX_INVALID; } if (ieee80211_is_data_qos(fc) && bf_isht(bf) && @@ -1998,6 +2036,9 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; } + if (ts->ts_flags & ATH9K_TX_BF_ERR) + tx_info->flags |= IEEE80211_TX_CTL_TXBF_UPDATE; + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC 5/5] ath9k_hw: Add support for Tx beamforming. 2010-11-10 12:23 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Vivek Natarajan @ 2010-11-10 12:23 ` Vivek Natarajan 2010-11-10 13:26 ` Felix Fietkau 2010-11-10 17:25 ` Luis R. Rodriguez 2010-11-10 13:06 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Felix Fietkau 1 sibling, 2 replies; 11+ messages in thread From: Vivek Natarajan @ 2010-11-10 12:23 UTC (permalink / raw) To: linux-wireless Initialize Tx beamforming capabilities, related registers and set descriptors for sounding frames. Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 80 ++++++- drivers/net/wireless/ath/ath9k/ar9003_mac.h | 22 ++ drivers/net/wireless/ath/ath9k/ar9003_phy.h | 11 + drivers/net/wireless/ath/ath9k/ar9003_txbf.c | 359 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_txbf.h | 87 +++++++ drivers/net/wireless/ath/ath9k/hw.c | 3 + drivers/net/wireless/ath/ath9k/hw.h | 56 ++++ drivers/net/wireless/ath/ath9k/mac.h | 48 ++++- drivers/net/wireless/ath/ath9k/reg.h | 119 +++++++++- 10 files changed, 782 insertions(+), 6 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_txbf.c create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_txbf.h diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index aca0162..3f4a6e6 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -33,7 +33,8 @@ ath9k_hw-y:= \ ar9002_mac.o \ ar9003_mac.o \ ar9003_eeprom.o \ - ar9003_paprd.o + ar9003_paprd.o \ + ar9003_txbf.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 10c812e..66795c9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -15,6 +15,7 @@ */ #include "hw.h" #include "ar9003_mac.h" +#include "ar9003_phy.h" static void ar9003_hw_rx_enable(struct ath_hw *hw) { @@ -302,6 +303,22 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_longretry = MS(status, AR_DataFailCnt); ts->ts_virtcol = MS(status, AR_VirtRetryCnt); + ts->ts_txbfstatus = 0; + if (ads->status8 & AR_TxBF_BW_Mismatch) + ts->ts_txbfstatus |= AR_BW_Mismatch; + + if (ads->status8 & AR_TxBF_Stream_Miss) + ts->ts_txbfstatus |= AR_Stream_Miss; + + if (ads->status8 & AR_TxBF_Dest_Miss) + ts->ts_txbfstatus |= AR_Dest_Miss; + + if (ads->status8 & AR_TxBF_Expired) + ts->ts_txbfstatus |= AR_Expired; + + if (ts->ts_txbfstatus) + ts->ts_flags |= ATH9K_TX_BF_ERR; + status = ACCESS_ONCE(ads->status7); ts->ts_rssi = MS(status, AR_TxRSSICombined); ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); @@ -360,7 +377,7 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, { struct ar9003_txc *ads = (struct ar9003_txc *) ds; struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds; - u_int32_t ctl11; + u32 ctl11, steerflag, tmp; if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { ctl11 = ads->ctl11; @@ -378,6 +395,48 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable)); } + if (flags & (ATH9K_TXDESC_TXBF_SOUND | ATH9K_TXDESC_TXBF_STAG_SOUND)) { + steerflag = set11n_txbf_flags(series, 0) + | set11n_txbf_flags(series, 1) + | set11n_txbf_flags(series, 2) + | set11n_txbf_flags(series, 3); + + if (steerflag != 0) { + if (ads->ctl17 & AR_LDPC) { + if (not_two_stream_rate(series[0].Rate)) { + steerflag = set11n_txbf_flags(series, 0); + if (not_two_stream_rate(series[1].Rate)) + steerflag |= + set11n_txbf_flags(series, 1); + + if (not_two_stream_rate(series[2].Rate)) + steerflag |= + set11n_txbf_flags(series, 2); + + if (not_two_stream_rate(series[3].Rate)) + steerflag |= + set11n_txbf_flags(series, 3); + + } else + ads->ctl17 &= ~(AR_LDPC); + } + ads->ctl11 |= steerflag; + } + } + if (flags & ATH9K_TXDESC_CAL) { + tmp = REG_READ(ah, AR_PHY_PERCHAIN_CSD); + tmp |= SM(8, AR_PHY_PERCHAIN_CSD_chn1_2chains); + tmp |= SM(4, AR_PHY_PERCHAIN_CSD_chn1_3chains); + tmp |= SM(8, AR_PHY_PERCHAIN_CSD_chn2_3chains); + REG_WRITE(ah, AR_PHY_PERCHAIN_CSD, tmp); + } else { + tmp = REG_READ(ah, AR_PHY_PERCHAIN_CSD); + tmp |= SM(2, AR_PHY_PERCHAIN_CSD_chn1_2chains); + tmp |= SM(2, AR_PHY_PERCHAIN_CSD_chn1_3chains); + tmp |= SM(4, AR_PHY_PERCHAIN_CSD_chn2_3chains); + REG_WRITE(ah, AR_PHY_PERCHAIN_CSD, tmp); + } + ads->ctl13 = set11nTries(series, 0) | set11nTries(series, 1) | set11nTries(series, 2) @@ -401,7 +460,16 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, | set11nRateFlags(series, 2) | set11nRateFlags(series, 3) | SM(rtsctsRate, AR_RTSCTSRate); - ads->ctl19 = AR_Not_Sounding; + + if (flags & (ATH9K_TXDESC_TXBF_SOUND | ATH9K_TXDESC_TXBF_STAG_SOUND)) { + ar9003_set_11n_txbf_sounding(ah, ds, series, + MS(flags, ATH9K_TXDESC_CEC), + (ATH9K_TXDESC_TXBF_SOUND | + ATH9K_TXDESC_TXBF_STAG_SOUND)); + } else { + /* set not sounding for normal frame */ + ads->ctl19 = AR_Not_Sounding; + } last_ads->ctl13 = ads->ctl13; last_ads->ctl14 = ads->ctl14; @@ -517,6 +585,7 @@ void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp, } EXPORT_SYMBOL(ath9k_hw_addrxbuf_edma); + int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, void *buf_addr) { @@ -566,6 +635,13 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; + rxs->rx_hw_upload_data = (rxsp->status2 & AR_HwUploadData) ? 1 : 0; + rxs->rx_not_sounding = (rxsp->status4 & AR_RxNotSounding) ? 1 : 0; + rxs->rx_Ness = MS(rxsp->status4, AR_RxNess); + rxs->rx_hw_upload_data_valid = (rxsp->status4 & AR_HwUploadDataValid) + ? 1 : 0; + rxs->rx_hw_upload_data_type = MS(rxsp->status11, AR_HwUploadDataType); + rxs->evm0 = rxsp->status6; rxs->evm1 = rxsp->status7; rxs->evm2 = rxsp->status8; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h index 45cc7e8..dd547aa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h @@ -36,6 +36,17 @@ #define AR_LowRxChain 0x00004000 #define AR_Not_Sounding 0x20000000 +#define AR_NESS 0xc0000000 +#define AR_NESS_S 30 + +#define AR_NESS1 0xc0000000 +#define AR_NESS1_S 30 + +#define AR_NESS2 0xc0000000 +#define AR_NESS2_S 30 + +#define AR_NESS3 0xc0000000 +#define AR_NESS3_S 30 /* ctl 12 */ #define AR_PAPRDChainMask 0x00000e00 @@ -51,7 +62,18 @@ #define MAP_ISR_S2_BB_WATCHDOG 6 #define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds) +#define set11n_txbf_flags(_series, _index) \ + ((_series)[_index].RateFlags & ATH9K_RATESERIES_TXBF ? \ + AR_TxBf##_index : 0) + +#define not_two_stream_rate(_rate) (((_rate) > 0x8f) || ((_rate) < 0x88)) +#define set11n_txbf_LDPC(_series) \ + (((not_two_stream_rate((_series)[0].Rate) && \ + (not_two_stream_rate((_series)[1].Rate) || (!(_series)[1].Tries)) \ + && (not_two_stream_rate((_series)[2].Rate) || (!(_series)[2].Tries)) \ + && (not_two_stream_rate((_series)[3].Rate) || (!(_series)[3].Tries)))) \ + ? AR_LDPC : 0) struct ar9003_rxs { u32 ds_info; u32 status1; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 3394dfe..a1fada3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -101,6 +101,8 @@ */ #define AR_PHY_TIMING2_USE_FORCE_PPM 0x00001000 #define AR_PHY_TIMING2_FORCE_PPM_VAL 0x00000fff +#define AR_PHY_TIMING2_HT_Fine_Timing_EN 0x80000000 + #define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 #define AR_PHY_TIMING3_DSC_MAN_S 17 #define AR_PHY_TIMING3_DSC_EXP 0x0001E000 @@ -188,6 +190,12 @@ #define AR_PHY_RADAR_DC_PWR_THRESH_S 15 #define AR_PHY_RADAR_LB_DC_CAP 0x7f800000 #define AR_PHY_RADAR_LB_DC_CAP_S 23 +#define AR_PHY_PERCHAIN_CSD_chn1_2chains 0x0000001f +#define AR_PHY_PERCHAIN_CSD_chn1_2chains_S 0 +#define AR_PHY_PERCHAIN_CSD_chn1_3chains 0x000003e0 +#define AR_PHY_PERCHAIN_CSD_chn1_3chains_S 5 +#define AR_PHY_PERCHAIN_CSD_chn2_3chains 0x00007c00 +#define AR_PHY_PERCHAIN_CSD_chn2_3chains_S 10 #define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW (0x3f << 6) #define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW_S 6 #define AR_PHY_FIND_SIG_LOW_FIRPWR (0x7f << 12) @@ -432,6 +440,9 @@ #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S 0 +#define AR_PHY_ENABLE_FLT_SVD 0x00001000 +#define AR_PHY_ENABLE_FLT_SVD_S 12 + #define AR_PHY_TEST (AR_SM_BASE + 0x160) #define AR_PHY_TEST_BBB_OBS_SEL 0x780000 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_txbf.c b/drivers/net/wireless/ath/ath9k/ar9003_txbf.c new file mode 100644 index 0000000..94a5133 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_txbf.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2008-2010, Atheros Communications 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 + * 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 "hw.h" +#include "ar9003_txbf.h" +#include "ar9003_phy.h" +#include "ar9003_mac.h" +/* number of carrier mappings under different bandwidth and grouping, ex: + * bw = 1 (40M), Ng=0 (no group), number of carrier = 114*/ +static u8 const Ns[NUM_OF_BW][NUM_OF_Ng] = { + {56, 30, 16}, + {114, 58, 30} +}; +static u8 const Valid_bits[MAX_BITS_PER_SYMBOL] = { + 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff +}; +static u8 Num_bits_on[NUM_OF_CHAINMASK] = { + 0 /* 000 */ , + 1 /* 001 */ , + 1 /* 010 */ , + 2 /* 011 */ , + 1 /* 100 */ , + 2 /* 101 */ , + 2 /* 110 */ , + 3 /* 111 */ +}; + +u8 ar9003_get_ntx(struct ath_hw *ah) +{ + return Num_bits_on[ah->txchainmask]; +} + +u8 ar9003_get_nrx(struct ath_hw *ah) +{ + return Num_bits_on[ah->rxchainmask]; +} + +void ar9003_set_hw_cv_timeout(struct ath_hw *ah, bool opt) +{ + /* if true use H/W settings to update cv timeout values */ + if (opt) + ah->ah_txbf_hw_cvtimeout = ah->config.ath_hw_cvtimeout; + + REG_WRITE(ah, AR_TXBF_TIMER, + (ah->ah_txbf_hw_cvtimeout << AR_TXBF_TIMER_ATIMEOUT_S) | + (ah->ah_txbf_hw_cvtimeout << AR_TXBF_TIMER_TIMEOUT_S)); +} + +void ar9003_init_txbf(struct ath_hw *ah) +{ + u32 tmp; + u8 txbf_ctl; + + /* set default settings for TxBF */ + REG_WRITE(ah, AR_TXBF, + /* size of codebook entry set to psi 3bits, phi 6bits */ + (AR_TXBF_PSI_4_PHI_6 << AR_TXBF_CB_TX_S) | + + /* set Number of bit_to 8 bits */ + (AR_TXBF_NUMBEROFBIT_8 << AR_TXBF_NB_TX_S) | + + /* NG_RPT_TX set t0 No_GROUP */ + (AR_TXBF_No_GROUP << AR_TXBF_NG_RPT_TX_S) | + + /* TXBF_NG_CVCACHE set to 16 clients */ + (AR_TXBF_SIXTEEN_CLIENTS << AR_TXBF_NG_CVCACHE_S) | + + /* set weighting method to max power */ + (SM(AR_TXBF_MAX_POWER, AR_TXBF_TXCV_BFWEIGHT_METHOD))); + /* when ah_txbf_hw_cvtimeout = 0, use setting values */ + if (ah->ah_txbf_hw_cvtimeout == 0) + ar9003_set_hw_cv_timeout(ah, true); + else + ar9003_set_hw_cv_timeout(ah, false); + + /* + * Set CEC to 2 stream for self_gen. + * Set spacing to 8 us. + * Initial selfgen Minimum MPDU. + */ + tmp = REG_READ(ah, AR_SELFGEN); + tmp |= SM(AR_SELFGEN_CEC_TWO_SPACETIMESTREAM, AR_CEC); + tmp |= SM(AR_SELFGEN_MMSS_EIGHT_us, AR_MMSS); + REG_WRITE(ah, AR_SELFGEN, tmp); + + /* set inital basic rate for all rate */ + REG_WRITE(ah, AR_BASIC_SET, ALL_RATE); + + /* enable HT fine timing */ + tmp = REG_READ(ah, AR_PHY_TIMING2); + tmp |= AR_PHY_TIMING2_HT_Fine_Timing_EN; + REG_WRITE(ah, AR_PHY_TIMING2, tmp); + + /* enable description decouple */ + tmp = REG_READ(ah, AR_PCU_MISC_MODE2); + tmp |= AR_DECOUPLE_DECRYPTION; + REG_WRITE(ah, AR_PCU_MISC_MODE2, tmp); + + /* enable restart */ + tmp = REG_READ(ah, AR_PHY_RESTART); + tmp |= AR_PHY_RESTART_ENA; + REG_WRITE(ah, AR_PHY_RESTART, tmp); + + /* enable flt SVD */ + tmp = REG_READ(ah, AR_PHY_SEARCH_START_DELAY); + + tmp |= AR_PHY_ENABLE_FLT_SVD; + REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, tmp); + txbf_ctl = ah->config.ath_hw_txbf_ctl; + + tmp = REG_READ(ah, AR_H_XFER_TIMEOUT); + tmp |= AR_EXBF_IMMDIATE_RESP; + tmp &= ~(AR_EXBF_NOACK_NO_RPT); + + /* enable immediate report */ + REG_WRITE(ah, AR_H_XFER_TIMEOUT, tmp); +} + +int ar9003_get_ness(struct ath_hw *ah, u8 code_rate, u8 cec) +{ + u8 ndltf = 0, ness = 0, ntx; + + ntx = ar9003_get_ntx(ah); + + /* cec+1 remote cap's for channel estimation in stream. */ + /* limit by remote's cap */ + if (ntx > (cec + 2)) + ntx = cec + 2; + + if (code_rate < MIN_TWO_STREAM_RATE) + ndltf = 1; + else if (code_rate < MIN_THREE_STREAM_RATE) + ndltf = 2; + else + ndltf = 4; + + /* NESS is used for setting neltf and NTX =<NDLTF + NELTF, NDLTF + * is 2^(stream-1), if NTX < NDLTF, NESS=0, other NESS = NTX-NDLTF */ + if (code_rate >= MIN_HT_RATE) { /* HT rate */ + if (ntx > ndltf) + ness = ntx - ndltf; + } + + return ness; +} + +/* + * function: ar9003_set_11n_txbf_sounding + * purpose: Set sounding frame + * inputs: + * series: rate series of sounding frame + * cec: Channel Estimation Capability . Extract from subfields + * of the Transmit Beamforming Capabilities field of remote. + * opt: control flag of current frame + */ +void +ar9003_set_11n_txbf_sounding(struct ath_hw *ah, + void *ds, + struct ath9k_11n_rate_series series[], + u8 cec, u16 opt) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + u8 ness = 0, ness1 = 0, ness2 = 0, ness3 = 0; + + ads->ctl19 &= (~AR_Not_Sounding); /*set sounding frame */ + if (opt & ATH9K_TXDESC_TXBF_STAG_SOUND) { + ness = ar9003_get_ness(ah, series[0].Rate, cec); + ness1 = ar9003_get_ness(ah, series[1].Rate, cec); + ness2 = ar9003_get_ness(ah, series[2].Rate, cec); + ness3 = ar9003_get_ness(ah, series[3].Rate, cec); + } + + ads->ctl19 |= SM(ness, AR_NESS); + ads->ctl20 |= SM(ness1, AR_NESS1); + ads->ctl21 |= SM(ness2, AR_NESS2); + ads->ctl22 |= SM(ness3, AR_NESS3); + + /* disable other series that don't support sounding at legacy rate */ + if (series[1].Rate < MIN_HT_RATE) { + ads->ctl13 &= + ~(AR_XmitDataTries1 | AR_XmitDataTries2 | + AR_XmitDataTries3); + } else if (series[2].Rate < MIN_HT_RATE) + ads->ctl13 &= ~(AR_XmitDataTries2 | AR_XmitDataTries3); + else if (series[3].Rate < MIN_HT_RATE) + ads->ctl13 &= ~(AR_XmitDataTries3); +} + +/* search CV cache address according to key index */ +static u16 ar9003_txbf_lru_search(struct ath_hw *ah, u8 key_idx) +{ + u32 tmp = 0; + u16 cv_cache_idx = 0; + + /* make sure LRU search is initially disabled */ + REG_WRITE(ah, AR_TXBF_SW, 0); + tmp = (SM(key_idx, AR_DEST_IDX) | AR_LRU_EN); + + /* enable LRU search */ + REG_WRITE(ah, AR_TXBF_SW, tmp); + + /* wait for LRU search to finish */ + do { + tmp = REG_READ(ah, AR_TXBF_SW); + } while ((tmp & AR_LRU_ACK) != 1); + cv_cache_idx = MS(tmp, AR_LRU_ADDR); + + /* disable LRU search */ + REG_WRITE(ah, AR_TXBF_SW, 0); + return cv_cache_idx; +} + +void ar9003_fill_txbf_capabilities(struct ath_hw *ah) +{ + struct ieee80211_txbf_caps *txbf = &ah->txbf_caps; + u32 val; + u8 txbf_ctl; + + memset(txbf, 0, sizeof(struct ieee80211_txbf_caps)); + + /* CEC for osprey is always 1 (2 stream) */ + txbf->channel_estimation_cap = 1; + + /* For calibration, always 2 (3 stream) for osprey */ + txbf->csi_max_rows_bfer = 2; + + /* + * Compressed Steering Number of Beamformer Antennas Supported is + * limited by local's antenna + */ + txbf->comp_bfer_antennas = ar9003_get_ntx(ah) - 1; + + /* + * Compressed Steering Number of Beamformer Antennas Supported + * is limited by local's antenna + */ + txbf->noncomp_bfer_antennas = ar9003_get_ntx(ah) - 1; + + /* NOT SUPPORT CSI */ + txbf->csi_bfer_antennas = 0; + + /* 1, 2, 4 group is supported */ + txbf->minimal_grouping = ALL_GROUP; + + /* Explicit compressed Beamforming Feedback Capable */ + txbf->explicit_comp_bf |= Delay_Rpt; + + /*TxBFCtl_Comp_ExBF_Immediately_Rpt)*/ + txbf->explicit_comp_bf |= Immediately_Rpt; + + /* Explicit non-Compressed Beamforming Feedback Capable */ + txbf->explicit_noncomp_bf |= Delay_Rpt; + + txbf->explicit_noncomp_bf |= Immediately_Rpt; + + /* not support csi feekback */ + txbf->explicit_csi_feedback = 0; + + /* Explicit compressed Steering Capable from settings */ + txbf->explicit_comp_steering = 1; + + /* Explicit Non-compressed Steering Capable from settings */ + txbf->explicit_noncomp_steering = 1; + + /* not support CSI */ + txbf->explicit_csi_txbf_capable = false; + + /* not support imbf and calibration */ + txbf->calibration = No_CALIBRATION; + txbf->implicit_txbf_capable = false; + txbf->implicit_rx_capable = false; + + /* not support NDP */ + txbf->tx_ndp_capable = false; + txbf->rx_ndp_capable = false; + + /* support stagger sounding. */ + txbf->tx_staggered_sounding = true; + txbf->rx_staggered_sounding = true; + + /* set immediately or delay report to H/W */ + val = REG_READ(ah, AR_H_XFER_TIMEOUT); + txbf_ctl = ah->config.ath_hw_txbf_ctl; + + val |= AR_EXBF_IMMDIATE_RESP; + val &= ~(AR_EXBF_NOACK_NO_RPT); + /* enable immediately report */ + REG_WRITE(ah, AR_H_XFER_TIMEOUT, val); +} +EXPORT_SYMBOL(ar9003_fill_txbf_capabilities); + +struct ieee80211_txbf_caps ar9003_get_txbf_capabilities(struct ath_hw *ah) +{ + return ah->txbf_caps; +} +EXPORT_SYMBOL(ar9003_get_txbf_capabilities); + +/* + * ar9003_txbf_set_key is used to set TXBF related field in key cache. + */ +void ar9003_txbf_set_key(struct ath_hw *ah, + u16 entry, + u8 rx_staggered_sounding, + u8 channel_estimation_cap, u8 mmss) +{ + u32 tmp, txbf; + + /* 1 for 2 stream, 0 for 1 stream, should add 1 for H/W */ + channel_estimation_cap += 1; + txbf = (SM(rx_staggered_sounding, AR_KEYTABLE_STAGGED) | + SM(channel_estimation_cap, AR_KEYTABLE_CEC) | + SM(mmss, AR_KEYTABLE_MMSS)); + tmp = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + if (txbf != + (tmp & (AR_KEYTABLE_STAGGED | AR_KEYTABLE_CEC | AR_KEYTABLE_MMSS))) + /* update key cache for txbf */ + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), tmp | txbf); +} + +u32 ar9003_read_cv_cache(struct ath_hw *ah, u32 addr) +{ + u32 tmp, value; + + REG_WRITE(ah, addr, AR_CVCACHE_RD_EN); + + do { + tmp = REG_READ(ah, AR_TXBF_SW); + } while ((tmp & AR_LRU_RD_ACK) == 0); + value = REG_READ(ah, addr); + tmp &= ~(AR_LRU_RD_ACK); + REG_WRITE(ah, AR_TXBF_SW, tmp); + return value & AR_CVCACHE_DATA; +} + +void ar9003_txbf_get_cv_cache_nr(struct ath_hw *ah, u16 key_idx, u8 * nr) +{ + u32 idx, value; + u8 nr_idx; + + /* get current CV cache addess offset from key index */ + idx = ar9003_txbf_lru_search(ah, key_idx); + + /* read the cvcache header */ + value = ar9003_read_cv_cache(ah, AR_CVCACHE(idx)); + nr_idx = MS(value, AR_CVCACHE_Nr_IDX); + *nr = nr_idx + 1; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_txbf.h b/drivers/net/wireless/ath/ath9k/ar9003_txbf.h new file mode 100644 index 0000000..1b6f5f8 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_txbf.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008-2010, Atheros Communications 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 + * 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 _ATH_AR9000_TxBF_CAL_H_ +#define _ATH_AR9300_TxBF_CAL_H_ + +#define debugKa 0 +#define debugRC 0 +#define debugWinRC 0 + +#define NUM_OF_BW 2 /* two bandwidth used for mapping:20M,40M */ +#define NUM_OF_Ng 3 /* three group define used for mapping :Ng=0,Ng=1,Ng=2*/ + +#define MAX_BITS_PER_SYMBOL 8 + +#define NUM_OF_CHAINMASK (1 << AR9300_MAX_CHAINS) + +#define BITS_PER_BYTE 8 +#define BITS_PER_COMPLEX_SYMBOL (2 * BITS_PER_SYMBOL) +#define BITS_PER_SYMBOL 10 + +#define MAX_STREAMS 3 +#define MAX_PILOTS 6 +#define EVM_MIN -128 + +#define Tone_40M 114 +#define Tone_20M 56 +#define NUM_ITER 8 + +#define Nb_phin (10-1) +#define Nb_coridc (12-1) +#define Nb_sin (8-1) +#define Nb_ph 5 +#define Nb_psi 4 +#define NUM_ITER_V 6 + +#define Nb_MHINV 13 +#define EVM_TH 10 +#define rc_max 6000 +#define rc_min 100 + +#define BW_40M 1 +#define BW_20M_low 2 +#define BW_20M_up 3 + + +/* MIMO control field related bit definiton */ + +#define AR_Nc_idx 0x0003 /* Nc Index*/ +#define AR_Nc_idx_S 0 +#define AR_Nr_idx 0x000c /* Nr Index*/ +#define AR_Nr_idx_S 2 +#define AR_bandwith 0x0010 /* MIMO Control Channel Width*/ +#define AR_bandwith_S 4 +#define AR_Ng 0x0060 /* Grouping*/ +#define AR_Ng_S 5 +#define AR_Nb 0x0180 /* Coeffiecient Size*/ +#define AR_Nb_S 7 +#define AR_CI 0x0600 /* Codebook Information*/ +#define AR_CI_S 9 +#define CAL_GAIN 0 +#define Smooth 1 + +/* constant for TXBF IE */ +#define ALL_GROUP 3 +#define No_CALIBRATION 0 +#define INIT_RESP_CAL 3 + +/* constant for rate code */ +#define MIN_THREE_STREAM_RATE 0x90 +#define MIN_TWO_STREAM_RATE 0x88 +#define MIN_HT_RATE 0x80 + +#endif diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5fb1bf3..9597cc3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1425,6 +1425,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (!ath9k_hw_init_cal(ah, chan)) return -EIO; + if (AR_SREV_9300_20_OR_LATER(ah)) + ar9003_init_txbf(ah); + ENABLE_REGWRITE_BUFFER(ah); ath9k_hw_restore_chainmask(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 8bebc3e..670a5ca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -238,6 +238,29 @@ struct ath9k_ops_config { u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; u8 max_txtrig_level; u16 ani_poll_interval; /* ANI poll interval in ms */ + u8 ath_hw_cvtimeout; + u8 ath_hw_txbf_ctl; +#define TxBFCtl_ImBF 0x01 +#define TxBFCtl_ImBF_S 0 +#define TxBFCtl_Non_ExBF 0x02 +#define TxBFCtl_Non_ExBF_S 1 +#define TxBFCtl_Comp_ExBF 0x04 +#define TxBFCtl_Comp_ExBF_S 2 +#define TxBFCtl_ImBF_FB 0x08 +#define TxBFCtl_ImBF_FB_S 3 +#define TxBFCtl_Non_ExBF_Immediately_Rpt 0x10 +#define TxBFCtl_Non_ExBF_Immediately_Rpt_S 4 +#define TxBFCtl_Comp_ExBF_Immediately_Rpt 0x20 +#define TxBFCtl_Comp_ExBF_Immediately_Rpt_S 5 + +#define TxBFCtl_Non_ExBF_delay_Rpt 0x40 +#define TxBFCtl_Non_ExBF_delay_Rpt_S 6 +#define TxBFCtl_Comp_ExBF_delay_Rpt 0x80 +#define TxBFCtl_Comp_ExBF_delay_Rpt_S 7 + +#define Delay_Rpt 1 +#define Immediately_Rpt 2 + }; enum ath9k_int { @@ -603,6 +626,28 @@ struct ath_nf_limits { s16 nominal; }; +struct hal_txbf_caps { + u8 channel_estimation_cap; + u8 csi_max_rows_bfer; + u8 comp_bfer_antennas; + u8 noncomp_bfer_antennas; + u8 csi_bfer_antennas; + u8 minimal_grouping; + u8 explicit_comp_bf; + u8 explicit_noncomp_bf; + u8 explicit_csi_feedback; + u8 explicit_comp_steering; + u8 explicit_noncomp_steering; + u8 explicit_csi_txbf_capable; + u8 calibration; + u8 implicit_txbf_capable; + u8 tx_ndp_capable; + u8 rx_ndp_capable; + u8 tx_staggered_sounding; + u8 rx_staggered_sounding; + u8 implicit_rx_capable; +}; + struct ath_hw { struct ieee80211_hw *hw; struct ath_common common; @@ -736,10 +781,12 @@ struct ath_hw { /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; + struct ieee80211_txbf_caps txbf_caps; u32 intr_txqs; u8 txchainmask; u8 rxchainmask; + bool ah_txbf_hw_cvtimeout; u32 originalGain[22]; int initPDADC; int PDADCdelta; @@ -955,6 +1002,15 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); +extern void ar9003_init_txbf(struct ath_hw *ah); +extern void ar9003_set_11n_txbf_sounding(struct ath_hw *ah, + void *ds, struct ath9k_11n_rate_series series[], + u8 cec, u16 opt); +extern void ar9003_fill_txbf_capabilities(struct ath_hw *ah); +extern struct ieee80211_txbf_caps + ar9003_get_txbf_capabilities(struct ath_hw *ah); +extern bool ar9300_read_key_cache_mac(struct ath_hw *ah, u16 entry, + u8 *mac); #define ATH_PCIE_CAP_LINK_CTRL 0x70 #define ATH_PCIE_CAP_LINK_L0S 1 #define ATH_PCIE_CAP_LINK_L1 2 diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 22907e2..7110506 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -89,7 +89,7 @@ #define ATH9K_TX_DATA_UNDERRUN 0x08 #define ATH9K_TX_DELIM_UNDERRUN 0x10 #define ATH9K_TX_SW_FILTERED 0x80 - +#define ATH9K_TX_BF_ERR 0xa0 /* 64 bytes */ #define MIN_TX_FIFO_THRESHOLD 0x1 @@ -124,6 +124,12 @@ struct ath_tx_status { u32 evm0; u32 evm1; u32 evm2; + u8 ts_txbfstatus; /* Tx bf status */ +#define AR_BW_Mismatch 0x1 +#define AR_Stream_Miss 0x2 +#define AR_CV_Missed 0x4 +#define AR_Dest_Miss 0x8 +#define AR_Expired 0x10 }; struct ath_rx_status { @@ -151,6 +157,11 @@ struct ath_rx_status { u32 evm2; u32 evm3; u32 evm4; + u8 rx_hw_upload_data:1, + rx_not_sounding:1, + rx_Ness:2, + rx_hw_upload_data_valid:1, + rx_hw_upload_data_type:2; }; struct ath_htc_rx_status { @@ -263,6 +274,15 @@ struct ath_desc { #define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 #define ATH9K_TXDESC_LOWRXCHAIN 0x0400 +#define ATH9K_TXDESC_TXBF 0x0800 /*for txbf*/ +#define ATH9K_TXDESC_TXBF_SOUND 0x1000 /* for sounding settings*/ +#define ATH9K_TXDESC_TXBF_SOUND_S 11 +#define ATH9K_TXDESC_SOUND 0x1 /* enable sounding */ +#define ATH9K_TXDESC_TXBF_STAG_SOUND 0x2000 /* enable sounding */ +#define ATH9K_TXDESC_TRQ 0x3 /* request sounding */ +#define ATH9K_TXDESC_CAL 0x2000 /* calibration frame */ +#define ATH9K_TXDESC_CEC 0xC000 /* channel calibration capability*/ +#define ATH9K_TXDESC_CEC_S 14 #define ATH9K_TXDESC_LDPC 0x00010000 #define ATH9K_RXDESC_INTREQ 0x0020 @@ -352,7 +372,12 @@ struct ar5416_desc { #define AR_RTSEnable 0x00400000 #define AR_VEOL 0x00800000 #define AR_ClrDestMask 0x01000000 -#define AR_TxCtlRsvd01 0x1e000000 +#define AR_TxBf0 0x02000000 +#define AR_TxBf1 0x04000000 +#define AR_TxBf2 0x08000000 +#define AR_TxBf3 0x10000000 + +#define AR_TxBfSteered 0x1e000000 #define AR_TxIntrReq 0x20000000 #define AR_DestIdxValid 0x40000000 #define AR_CTSEnable 0x80000000 @@ -495,8 +520,14 @@ struct ar5416_desc { #define AR_TxStatusRsvd80 0x0001e000 #define AR_TxOpExceeded 0x00020000 #define AR_TxStatusRsvd81 0x001c0000 +#define AR_TXBFStatus 0x001c0000 +#define AR_TXBFStatus_S 18 +#define AR_TxBF_BW_Mismatch 0x00040000 +#define AR_TxBF_Stream_Miss 0x00080000 #define AR_FinalTxIdx 0x00600000 #define AR_FinalTxIdx_S 21 +#define AR_TxBF_Dest_Miss 0x00800000 +#define AR_TxBF_Expired 0x01000000 #define AR_TxStatusRsvd82 0x01800000 #define AR_PowerMgmt 0x02000000 #define AR_TxStatusRsvd83 0xfc000000 @@ -521,6 +552,8 @@ struct ar5416_desc { #define AR_RxMore 0x00001000 #define AR_NumDelim 0x003fc000 #define AR_NumDelim_S 14 +#define AR_HwUploadData 0x00400000 +#define AR_HwUploadData_S 22 #define AR_RxStatusRsvd10 0xff800000 #define AR_RcvTimestamp ds_rxstatus2 @@ -529,6 +562,12 @@ struct ar5416_desc { #define AR_2040 0x00000002 #define AR_Parallel40 0x00000004 #define AR_Parallel40_S 2 +#define AR_RxStbc 0x00000008 +#define AR_RxNotSounding 0x00000010 +#define AR_RxNess 0x00000060 +#define AR_RxNess_S 5 +#define AR_HwUploadDataValid 0x00000080 +#define AR_HwUploadDataValid_S 7 #define AR_RxStatusRsvd30 0x000000f8 #define AR_RxAntenna 0xffffff00 #define AR_RxAntenna_S 8 @@ -563,6 +602,10 @@ struct ar5416_desc { #define AR_RxAggr 0x00020000 #define AR_PostDelimCRCErr 0x00040000 #define AR_RxStatusRsvd71 0x3ff80000 +#define AR_HwUploadDataType 0x06000000 +#define AR_HwUploadDataType_S 25 +#define AR_HiRxChain 0x10000000 +#define AR_RxFirstAggr 0x20000000 #define AR_DecryptBusyErr 0x40000000 #define AR_KeyMiss 0x80000000 @@ -648,6 +691,7 @@ enum ath9k_rx_filter { #define ATH9K_RATESERIES_2040 0x0002 #define ATH9K_RATESERIES_HALFGI 0x0004 #define ATH9K_RATESERIES_STBC 0x0008 +#define ATH9K_RATESERIES_TXBF 0x0010 /* use TxBF for series */ struct ath9k_11n_rate_series { u32 Tries; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index fa05b71..3d9914e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1499,6 +1499,9 @@ enum { #define AR_FCS_FAIL 0x8094 #define AR_BEACON_CNT 0x8098 +#define AR_BASIC_SET 0x80a0 +#define ALL_RATE 0xff + #define AR_SLEEP1 0x80d4 #define AR_SLEEP1_ASSUME_DTIM 0x00080000 #define AR_SLEEP1_CAB_TIMEOUT 0xFFE00000 @@ -1508,6 +1511,24 @@ enum { #define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000 #define AR_SLEEP2_BEACON_TIMEOUT_S 21 +/*MAC_PCU_SELF_GEN_DEFAULT*/ +#define AR_SELFGEN 0x80dc +#define AR_MMSS 0x00000007 +#define AR_MMSS_S 0 +#define AR_SELFGEN_MMSS_NO RESTRICTION 0 +#define AR_SELFGEN_MMSS_ONEOVER4_us 1 +#define AR_SELFGEN_MMSS_ONEOVER2_us 2 +#define AR_SELFGEN_MMSS_ONE_us 3 +#define AR_SELFGEN_MMSS_TWO_us 4 +#define AR_SELFGEN_MMSS_FOUR_us 5 +#define AR_SELFGEN_MMSS_EIGHT_us 6 +#define AR_SELFGEN_MMSS_SIXTEEN_us 7 + +#define AR_CEC 0x00000018 +#define AR_CEC_S 3 +#define AR_SELFGEN_CEC_ONE_SPACETIMESTREAM 1 +#define AR_SELFGEN_CEC_TWO_SPACETIMESTREAM 2 + #define AR_TPC 0x80e8 #define AR_TPC_ACK 0x0000003f #define AR_TPC_ACK_S 0x00 @@ -1716,6 +1737,9 @@ enum { #define AR_2040_MODE 0x8318 #define AR_2040_JOINED_RX_CLEAR 0x00000001 +#define AR_H_XFER_TIMEOUT 0x831c +#define AR_EXBF_IMMDIATE_RESP 0x00000040 +#define AR_EXBF_NOACK_NO_RPT 0x00000100 #define AR_EXTRCCNT 0x8328 @@ -1739,6 +1763,7 @@ enum { #define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000 #define AR_PCU_MISC_MODE2_HWWAR1 0x00100000 #define AR_PCU_MISC_MODE2_HWWAR2 0x02000000 +#define AR_DECOUPLE_DECRYPTION 0x08000000 #define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000 #define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358 @@ -1776,6 +1801,14 @@ enum { #define AR_KEYTABLE_TYPE_CCM 0x00000006 #define AR_KEYTABLE_TYPE_CLR 0x00000007 #define AR_KEYTABLE_ANT 0x00000008 + +#define AR_KEYTABLE_MMSS 0x00001c00 /* remote's MMSS*/ +#define AR_KEYTABLE_MMSS_S 10 +#define AR_KEYTABLE_CEC 0x00006000 /* remote's CEC*/ +#define AR_KEYTABLE_CEC_S 13 +#define AR_KEYTABLE_STAGGED 0x00010000 /* remote's stagged sounding*/ +#define AR_KEYTABLE_STAGGED_S 16 + #define AR_KEYTABLE_VALID 0x00008000 #define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0) #define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4) @@ -1816,5 +1849,89 @@ enum { #define AR_PHY_AGC_CONTROL_CLC_SUCCESS 0x00080000 /* carrier leak calibration done */ #define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0 #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 - +#define AR_TXBF_DBG 0x10000 + +#define AR_TXBF 0x10004 +#define AR_TXBF_CB_TX 0x00000003 +#define AR_TXBF_CB_TX_S 0 +#define AR_TXBF_PSI_1_PHI_3 0 +#define AR_TXBF_PSI_2_PHI_4 1 +#define AR_TXBF_PSI_3_PHI_5 2 +#define AR_TXBF_PSI_4_PHI_6 3 + +#define AR_TXBF_NB_TX 0x0000000C +#define AR_TXBF_NB_TX_S 2 +#define AR_TXBF_NUMBEROFBIT_4 0 +#define AR_TXBF_NUMBEROFBIT_2 1 +#define AR_TXBF_NUMBEROFBIT_6 2 +#define AR_TXBF_NUMBEROFBIT_8 3 + +#define AR_TXBF_NG_RPT_TX 0x00000030 +#define AR_TXBF_NG_RPT_TX_S 4 +#define AR_TXBF_No_GROUP 0 +#define AR_TXBF_TWO_GROUP 1 +#define AR_TXBF_FOUR_GROUP 2 + +#define AR_TXBF_NG_CVCACHE 0x000000C0 +#define AR_TXBF_NG_CVCACHE_S 6 +#define AR_TXBF_FOUR_CLIENTS 0 +#define AR_TXBF_EIGHT_CLIENTS 1 +#define AR_TXBF_SIXTEEN_CLIENTS 2 + +#define AR_TXBF_TXCV_BFWEIGHT_METHOD 0x00000600 +#define AR_TXBF_TXCV_BFWEIGHT_METHOD_S 9 +#define AR_TXBF_NO_WEIGHTING 0 +#define AR_TXBF_MAX_POWER 1 +#define AR_TXBF_KEEP_RATIO 2 + +#define AR_TXBF_RLR_EN 0x00000800 +#define AR_TXBF_RC_20_U_DONE 0x00001000 +#define AR_TXBF_RC_20_L_DONE 0x00002000 +#define AR_TXBF_RC_40_DONE 0x00004000 +#define AR_TXBF_FORCE_UPDATE_V2BB 0x00008000 + +#define AR_TXBF_TIMER 0x10008 +#define AR_TXBF_TIMER_TIMEOUT 0x000000FF +#define AR_TXBF_TIMER_TIMEOUT_S 0 +#define AR_TXBF_TIMER_ATIMEOUT 0x0000FF00 +#define AR_TXBF_TIMER_ATIMEOUT_S 8 + +/* for SVD cache update */ +#define AR_TXBF_SW 0x1000c +#define AR_LRU_ACK 0x00000001 +#define AR_LRU_ADDR 0x000003FE +#define AR_LRU_ADDR_S 1 +#define AR_LRU_EN 0x00000400 +#define AR_LRU_EN_S 11 +#define AR_DEST_IDX 0x0007f000 +#define AR_DEST_IDX_S 12 +#define AR_LRU_WR_ACK 0x00080000 +#define AR_LRU_WR_ACK_S 19 +#define AR_LRU_RD_ACK 0x00100000 +#define AR_LRU_RD_ACK_S 20 + +#define AR_RC0_0 0x11000 +#define AR_RC0(_idx) (AR_RC0_0+(_idx)) +#define AR_RC1_0 0x11200 +#define AR_RC1(_idx) (AR_RC1_0+(_idx)) + +#define AR_CVCACHE_0 0x12400 +#define AR_CVCACHE(_idx) (AR_CVCACHE_0+(_idx)) +#define AR_CVCACHE_Ng_IDX 0x0000C000 +#define AR_CVCACHE_Ng_IDX_S 14 +#define AR_CVCACHE_BW40 0x00010000 +#define AR_CVCACHE_BW40_S 16 +#define AR_CVCACHE_IMPLICIT 0x00020000 +#define AR_CVCACHE_IMPLICIT_S 17 +#define AR_CVCACHE_DEST_IDX 0x01FC0000 +#define AR_CVCACHE_DEST_IDX_S 18 +#define AR_CVCACHE_Nc_IDX 0x06000000 +#define AR_CVCACHE_Nc_IDX_S 25 +#define AR_CVCACHE_Nr_IDX 0x18000000 +#define AR_CVCACHE_Nr_IDX_S 27 +#define AR_CVCACHE_EXPIRED 0x20000000 +#define AR_CVCACHE_EXPIRED_S 29 +#define AR_CVCACHE_WRITE 0x80000000 +#define AR_CVCACHE_RD_EN 0x40000000 +#define AR_CVCACHE_DATA 0x3fffffff #endif -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC 5/5] ath9k_hw: Add support for Tx beamforming. 2010-11-10 12:23 ` [RFC 5/5] ath9k_hw: Add support for Tx beamforming Vivek Natarajan @ 2010-11-10 13:26 ` Felix Fietkau 2010-11-10 17:25 ` Luis R. Rodriguez 1 sibling, 0 replies; 11+ messages in thread From: Felix Fietkau @ 2010-11-10 13:26 UTC (permalink / raw) To: Vivek Natarajan; +Cc: linux-wireless On 2010-11-10 1:23 PM, Vivek Natarajan wrote: > Initialize Tx beamforming capabilities, related registers and set > descriptors for sounding frames. > > Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> > --- > drivers/net/wireless/ath/ath9k/Makefile | 3 +- > drivers/net/wireless/ath/ath9k/ar9003_mac.c | 80 ++++++- > drivers/net/wireless/ath/ath9k/ar9003_mac.h | 22 ++ > drivers/net/wireless/ath/ath9k/ar9003_phy.h | 11 + > drivers/net/wireless/ath/ath9k/ar9003_txbf.c | 359 ++++++++++++++++++++++++++ > drivers/net/wireless/ath/ath9k/ar9003_txbf.h | 87 +++++++ > drivers/net/wireless/ath/ath9k/hw.c | 3 + > drivers/net/wireless/ath/ath9k/hw.h | 56 ++++ > drivers/net/wireless/ath/ath9k/mac.h | 48 ++++- > drivers/net/wireless/ath/ath9k/reg.h | 119 +++++++++- > 10 files changed, 782 insertions(+), 6 deletions(-) > create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_txbf.c > create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_txbf.h > > diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h > index 3394dfe..a1fada3 100644 > --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h > +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h > @@ -101,6 +101,8 @@ > */ > #define AR_PHY_TIMING2_USE_FORCE_PPM 0x00001000 > #define AR_PHY_TIMING2_FORCE_PPM_VAL 0x00000fff > +#define AR_PHY_TIMING2_HT_Fine_Timing_EN 0x80000000 > + > #define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 > #define AR_PHY_TIMING3_DSC_MAN_S 17 > #define AR_PHY_TIMING3_DSC_EXP 0x0001E000 > @@ -188,6 +190,12 @@ > #define AR_PHY_RADAR_DC_PWR_THRESH_S 15 > #define AR_PHY_RADAR_LB_DC_CAP 0x7f800000 > #define AR_PHY_RADAR_LB_DC_CAP_S 23 > +#define AR_PHY_PERCHAIN_CSD_chn1_2chains 0x0000001f > +#define AR_PHY_PERCHAIN_CSD_chn1_2chains_S 0 > +#define AR_PHY_PERCHAIN_CSD_chn1_3chains 0x000003e0 > +#define AR_PHY_PERCHAIN_CSD_chn1_3chains_S 5 > +#define AR_PHY_PERCHAIN_CSD_chn2_3chains 0x00007c00 > +#define AR_PHY_PERCHAIN_CSD_chn2_3chains_S 10 > #define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW (0x3f << 6) > #define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW_S 6 > #define AR_PHY_FIND_SIG_LOW_FIRPWR (0x7f << 12) Lowercase/Uppercase consistency? > diff --git a/drivers/net/wireless/ath/ath9k/ar9003_txbf.h b/drivers/net/wireless/ath/ath9k/ar9003_txbf.h > new file mode 100644 > index 0000000..1b6f5f8 > --- /dev/null > +++ b/drivers/net/wireless/ath/ath9k/ar9003_txbf.h > @@ -0,0 +1,87 @@ > +/* > + * Copyright (c) 2008-2010, Atheros Communications 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 > + * 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 _ATH_AR9000_TxBF_CAL_H_ > +#define _ATH_AR9300_TxBF_CAL_H_ > + > +#define debugKa 0 > +#define debugRC 0 > +#define debugWinRC 0 ??? > + > +#define NUM_OF_BW 2 /* two bandwidth used for mapping:20M,40M */ > +#define NUM_OF_Ng 3 /* three group define used for mapping :Ng=0,Ng=1,Ng=2*/ > + > +#define MAX_BITS_PER_SYMBOL 8 > +#define NUM_OF_CHAINMASK (1 << AR9300_MAX_CHAINS) > +#define BITS_PER_BYTE 8 What's this for? > +#define BITS_PER_COMPLEX_SYMBOL (2 * BITS_PER_SYMBOL) > +#define BITS_PER_SYMBOL 10 > + > +#define MAX_STREAMS 3 > +#define MAX_PILOTS 6 > +#define EVM_MIN -128 > + > +#define Tone_40M 114 > +#define Tone_20M 56 > +#define NUM_ITER 8 > + > +#define Nb_phin (10-1) > +#define Nb_coridc (12-1) > +#define Nb_sin (8-1) > +#define Nb_ph 5 > +#define Nb_psi 4 > +#define NUM_ITER_V 6 > + > +#define Nb_MHINV 13 > +#define EVM_TH 10 > +#define rc_max 6000 > +#define rc_min 100 > + > +#define BW_40M 1 > +#define BW_20M_low 2 > +#define BW_20M_up 3 What are those for? > diff --git a/drivers/net/wireless/ath/ath9k/ar9003_txbf.c b/drivers/net/wireless/ath/ath9k/ar9003_txbf.c > new file mode 100644 > index 0000000..94a5133 > --- /dev/null > +++ b/drivers/net/wireless/ath/ath9k/ar9003_txbf.c > @@ -0,0 +1,359 @@ > +/* > + * Copyright (c) 2008-2010, Atheros Communications 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 > + * 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 "hw.h" > +#include "ar9003_txbf.h" > +#include "ar9003_phy.h" > +#include "ar9003_mac.h" > +/* number of carrier mappings under different bandwidth and grouping, ex: > + * bw = 1 (40M), Ng=0 (no group), number of carrier = 114*/ > +static u8 const Ns[NUM_OF_BW][NUM_OF_Ng] = { > + {56, 30, 16}, > + {114, 58, 30} > +}; > +static u8 const Valid_bits[MAX_BITS_PER_SYMBOL] = { > + 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff > +}; Unused, also rather useless, there are kernel functions for that sort of thing. > diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h > index 8bebc3e..670a5ca 100644 > --- a/drivers/net/wireless/ath/ath9k/hw.h > +++ b/drivers/net/wireless/ath/ath9k/hw.h > @@ -238,6 +238,29 @@ struct ath9k_ops_config { > u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; > u8 max_txtrig_level; > u16 ani_poll_interval; /* ANI poll interval in ms */ > + u8 ath_hw_cvtimeout; > + u8 ath_hw_txbf_ctl; > +#define TxBFCtl_ImBF 0x01 > +#define TxBFCtl_ImBF_S 0 > +#define TxBFCtl_Non_ExBF 0x02 > +#define TxBFCtl_Non_ExBF_S 1 > +#define TxBFCtl_Comp_ExBF 0x04 > +#define TxBFCtl_Comp_ExBF_S 2 > +#define TxBFCtl_ImBF_FB 0x08 > +#define TxBFCtl_ImBF_FB_S 3 > +#define TxBFCtl_Non_ExBF_Immediately_Rpt 0x10 > +#define TxBFCtl_Non_ExBF_Immediately_Rpt_S 4 > +#define TxBFCtl_Comp_ExBF_Immediately_Rpt 0x20 > +#define TxBFCtl_Comp_ExBF_Immediately_Rpt_S 5 > + > +#define TxBFCtl_Non_ExBF_delay_Rpt 0x40 > +#define TxBFCtl_Non_ExBF_delay_Rpt_S 6 > +#define TxBFCtl_Comp_ExBF_delay_Rpt 0x80 > +#define TxBFCtl_Comp_ExBF_delay_Rpt_S 7 Why the _S defines? Also, why not just use BIT() instead of the raw hex values. > @@ -603,6 +626,28 @@ struct ath_nf_limits { > s16 nominal; > }; > > +struct hal_txbf_caps { > + u8 channel_estimation_cap; > + u8 csi_max_rows_bfer; > + u8 comp_bfer_antennas; > + u8 noncomp_bfer_antennas; > + u8 csi_bfer_antennas; > + u8 minimal_grouping; > + u8 explicit_comp_bf; > + u8 explicit_noncomp_bf; > + u8 explicit_csi_feedback; > + u8 explicit_comp_steering; > + u8 explicit_noncomp_steering; > + u8 explicit_csi_txbf_capable; > + u8 calibration; > + u8 implicit_txbf_capable; > + u8 tx_ndp_capable; > + u8 rx_ndp_capable; > + u8 tx_staggered_sounding; > + u8 rx_staggered_sounding; > + u8 implicit_rx_capable; > +}; Maybe rename this to ath9k_hw_txbf_caps? > @@ -955,6 +1002,15 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); > void ath9k_hw_proc_mib_event(struct ath_hw *ah); > void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); > > +extern void ar9003_init_txbf(struct ath_hw *ah); > +extern void ar9003_set_11n_txbf_sounding(struct ath_hw *ah, > + void *ds, struct ath9k_11n_rate_series series[], > + u8 cec, u16 opt); > +extern void ar9003_fill_txbf_capabilities(struct ath_hw *ah); > +extern struct ieee80211_txbf_caps > + ar9003_get_txbf_capabilities(struct ath_hw *ah); > +extern bool ar9300_read_key_cache_mac(struct ath_hw *ah, u16 entry, > + u8 *mac); > #define ATH_PCIE_CAP_LINK_CTRL 0x70 > #define ATH_PCIE_CAP_LINK_L0S 1 > #define ATH_PCIE_CAP_LINK_L1 2 > diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h > index 22907e2..7110506 100644 > --- a/drivers/net/wireless/ath/ath9k/mac.h > +++ b/drivers/net/wireless/ath/ath9k/mac.h > @@ -89,7 +89,7 @@ > #define ATH9K_TX_DATA_UNDERRUN 0x08 > #define ATH9K_TX_DELIM_UNDERRUN 0x10 > #define ATH9K_TX_SW_FILTERED 0x80 > - > +#define ATH9K_TX_BF_ERR 0xa0 > /* 64 bytes */ > #define MIN_TX_FIFO_THRESHOLD 0x1 > > @@ -124,6 +124,12 @@ struct ath_tx_status { > u32 evm0; > u32 evm1; > u32 evm2; > + u8 ts_txbfstatus; /* Tx bf status */ > +#define AR_BW_Mismatch 0x1 > +#define AR_Stream_Miss 0x2 > +#define AR_CV_Missed 0x4 > +#define AR_Dest_Miss 0x8 > +#define AR_Expired 0x10 > }; > > struct ath_rx_status { > @@ -151,6 +157,11 @@ struct ath_rx_status { > u32 evm2; > u32 evm3; > u32 evm4; > + u8 rx_hw_upload_data:1, > + rx_not_sounding:1, > + rx_Ness:2, > + rx_hw_upload_data_valid:1, > + rx_hw_upload_data_type:2; > }; > > struct ath_htc_rx_status { > @@ -263,6 +274,15 @@ struct ath_desc { > #define ATH9K_TXDESC_VMF 0x0100 > #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 > #define ATH9K_TXDESC_LOWRXCHAIN 0x0400 > +#define ATH9K_TXDESC_TXBF 0x0800 /*for txbf*/ > +#define ATH9K_TXDESC_TXBF_SOUND 0x1000 /* for sounding settings*/ > +#define ATH9K_TXDESC_TXBF_SOUND_S 11 It's just one bit, it doesn't need a _S > diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h > index fa05b71..3d9914e 100644 > --- a/drivers/net/wireless/ath/ath9k/reg.h > +++ b/drivers/net/wireless/ath/ath9k/reg.h > @@ -1816,5 +1849,89 @@ enum { > #define AR_PHY_AGC_CONTROL_CLC_SUCCESS 0x00080000 /* carrier leak calibration done */ > #define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0 > #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 > - > +#define AR_TXBF_DBG 0x10000 > + > +#define AR_TXBF 0x10004 > +#define AR_TXBF_CB_TX 0x00000003 > +#define AR_TXBF_CB_TX_S 0 > +#define AR_TXBF_PSI_1_PHI_3 0 > +#define AR_TXBF_PSI_2_PHI_4 1 > +#define AR_TXBF_PSI_3_PHI_5 2 > +#define AR_TXBF_PSI_4_PHI_6 3 > + > +#define AR_TXBF_NB_TX 0x0000000C > +#define AR_TXBF_NB_TX_S 2 > +#define AR_TXBF_NUMBEROFBIT_4 0 > +#define AR_TXBF_NUMBEROFBIT_2 1 > +#define AR_TXBF_NUMBEROFBIT_6 2 > +#define AR_TXBF_NUMBEROFBIT_8 3 > + > +#define AR_TXBF_NG_RPT_TX 0x00000030 > +#define AR_TXBF_NG_RPT_TX_S 4 > +#define AR_TXBF_No_GROUP 0 > +#define AR_TXBF_TWO_GROUP 1 > +#define AR_TXBF_FOUR_GROUP 2 > + > +#define AR_TXBF_NG_CVCACHE 0x000000C0 > +#define AR_TXBF_NG_CVCACHE_S 6 > +#define AR_TXBF_FOUR_CLIENTS 0 > +#define AR_TXBF_EIGHT_CLIENTS 1 > +#define AR_TXBF_SIXTEEN_CLIENTS 2 > + > +#define AR_TXBF_TXCV_BFWEIGHT_METHOD 0x00000600 > +#define AR_TXBF_TXCV_BFWEIGHT_METHOD_S 9 > +#define AR_TXBF_NO_WEIGHTING 0 > +#define AR_TXBF_MAX_POWER 1 > +#define AR_TXBF_KEEP_RATIO 2 > + > +#define AR_TXBF_RLR_EN 0x00000800 > +#define AR_TXBF_RC_20_U_DONE 0x00001000 > +#define AR_TXBF_RC_20_L_DONE 0x00002000 > +#define AR_TXBF_RC_40_DONE 0x00004000 > +#define AR_TXBF_FORCE_UPDATE_V2BB 0x00008000 > + > +#define AR_TXBF_TIMER 0x10008 > +#define AR_TXBF_TIMER_TIMEOUT 0x000000FF > +#define AR_TXBF_TIMER_TIMEOUT_S 0 > +#define AR_TXBF_TIMER_ATIMEOUT 0x0000FF00 > +#define AR_TXBF_TIMER_ATIMEOUT_S 8 > + > +/* for SVD cache update */ > +#define AR_TXBF_SW 0x1000c > +#define AR_LRU_ACK 0x00000001 > +#define AR_LRU_ADDR 0x000003FE > +#define AR_LRU_ADDR_S 1 > +#define AR_LRU_EN 0x00000400 > +#define AR_LRU_EN_S 11 > +#define AR_DEST_IDX 0x0007f000 > +#define AR_DEST_IDX_S 12 > +#define AR_LRU_WR_ACK 0x00080000 > +#define AR_LRU_WR_ACK_S 19 > +#define AR_LRU_RD_ACK 0x00100000 > +#define AR_LRU_RD_ACK_S 20 > + > +#define AR_RC0_0 0x11000 > +#define AR_RC0(_idx) (AR_RC0_0+(_idx)) > +#define AR_RC1_0 0x11200 > +#define AR_RC1(_idx) (AR_RC1_0+(_idx)) > + > +#define AR_CVCACHE_0 0x12400 > +#define AR_CVCACHE(_idx) (AR_CVCACHE_0+(_idx)) > +#define AR_CVCACHE_Ng_IDX 0x0000C000 > +#define AR_CVCACHE_Ng_IDX_S 14 > +#define AR_CVCACHE_BW40 0x00010000 > +#define AR_CVCACHE_BW40_S 16 > +#define AR_CVCACHE_IMPLICIT 0x00020000 > +#define AR_CVCACHE_IMPLICIT_S 17 _S unnecessary here as well - Felix ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 5/5] ath9k_hw: Add support for Tx beamforming. 2010-11-10 12:23 ` [RFC 5/5] ath9k_hw: Add support for Tx beamforming Vivek Natarajan 2010-11-10 13:26 ` Felix Fietkau @ 2010-11-10 17:25 ` Luis R. Rodriguez 1 sibling, 0 replies; 11+ messages in thread From: Luis R. Rodriguez @ 2010-11-10 17:25 UTC (permalink / raw) To: Vivek Natarajan; +Cc: linux-wireless On Wed, Nov 10, 2010 at 4:23 AM, Vivek Natarajan <vnatarajan@atheros.com> wrote: > Initialize Tx beamforming capabilities, related registers and set > descriptors for sounding frames. > > Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> Hardware patch for ath9k_hw should go first otherwise would you not get a compile issue? Luis ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 4/5] ath9k: Add support for Tx beamforming feature. 2010-11-10 12:23 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Vivek Natarajan 2010-11-10 12:23 ` [RFC 5/5] ath9k_hw: Add support for Tx beamforming Vivek Natarajan @ 2010-11-10 13:06 ` Felix Fietkau 1 sibling, 0 replies; 11+ messages in thread From: Felix Fietkau @ 2010-11-10 13:06 UTC (permalink / raw) To: Vivek Natarajan; +Cc: linux-wireless On 2010-11-10 1:23 PM, Vivek Natarajan wrote: > Beamforming is enabled with the latest hardware if the module parameter > is set. > > Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> > --- > drivers/net/wireless/ath/ath9k/ath9k.h | 2 + > drivers/net/wireless/ath/ath9k/init.c | 9 + > drivers/net/wireless/ath/ath9k/main.c | 22 ++ > drivers/net/wireless/ath/ath9k/rc.c | 453 ++++++++++++++++++++------------ > drivers/net/wireless/ath/ath9k/rc.h | 90 +++++++- > drivers/net/wireless/ath/ath9k/xmit.c | 43 +++- > 6 files changed, 454 insertions(+), 165 deletions(-) > > diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h > index 8a2b04e..5216999 100644 > --- a/drivers/net/wireless/ath/ath9k/ath9k.h > +++ b/drivers/net/wireless/ath/ath9k/ath9k.h > @@ -270,6 +270,8 @@ struct ath_node { > struct ath_atx_ac ac[WME_NUM_AC]; > u16 maxampdu; > u8 mpdudensity; > + bool txbf; > + u8 key_idx; > }; > > #define AGGR_CLEANUP BIT(1) > diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c > index f14fe53..531efe7 100644 > --- a/drivers/net/wireless/ath/ath9k/init.c > +++ b/drivers/net/wireless/ath/ath9k/init.c > @@ -38,6 +38,10 @@ int led_blink; > module_param_named(blink, led_blink, int, 0444); > MODULE_PARM_DESC(blink, "Enable LED blink on activity"); > > +int txbf; > +module_param_named(txbf, txbf, int, 0444); > +MODULE_PARM_DESC(blink, "Enable TxBF"); > + I don't think a module parameter is a good idea here. If you want to make it possible to disable txbf, just add a debugfs entry. > diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c > index 85c8e93..0b9c405 100644 > --- a/drivers/net/wireless/ath/ath9k/rc.c > +++ b/drivers/net/wireless/ath/ath9k/rc.c > @@ -749,6 +828,14 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, > if (rate_control_send_low(sta, priv_sta, txrc)) > return; > > +#define MS(_v, _f) (((_v) & _f) >> _f##_S) That one's already defined in hw.h > @@ -807,6 +903,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, > /* All other rates in the series have RTS enabled */ > ath_rc_rate_set_series(rate_table, &rates[i], txrc, > try_per_rate, rix, 1); > + > + if (ath_rc_priv->txbf && ath_rc_priv->txbf_sounding) { > + if (rates[i].flags & IEEE80211_TX_RC_MCS) > + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; > + else { > + /* Remove sounding */ > + hdr->frame_control &= > + ~cpu_to_le16(IEEE80211_FCTL_ORDER); Shouldn't mac80211 take care of ensuring hdr->frame_control sanity? Doing this in the rate control module seems a little messy to me. > @@ -1189,6 +1298,10 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, > } > } > > +#ifndef MIN > +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) > +#endif There's a Linux kernel macro for exactly the same purpose. > diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c > index 2bc422e..73e3723 100644 > --- a/drivers/net/wireless/ath/ath9k/xmit.c > +++ b/drivers/net/wireless/ath/ath9k/xmit.c > @@ -668,18 +668,32 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, > struct list_head *bf_q) > { > #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) > +#define MS(_v, _f) (((_v) & _f) >> _f##_S) Again, already defined in hw.h > struct ath_buf *bf, *bf_first, *bf_prev = NULL; > int rl = 0, nframes = 0, ndelim, prev_al = 0; > u16 aggr_limit = 0, al = 0, bpad = 0, > al_delta, h_baw = tid->baw_size / 2; > enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; > struct ieee80211_tx_info *tx_info; > + u8 is_prev_sounding = 0; > > bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); > > do { > bf = list_first_entry(&tid->buf_q, struct ath_buf, list); > > + /* send the sounding frame as a single frame */ > + if (bf->bf_flags & > + (ATH9K_TXDESC_TXBF_SOUND | ATH9K_TXDESC_TXBF_STAG_SOUND)) { > + if (nframes != 0) > + break; > + else > + is_prev_sounding = 1; > + } > + > + if ((nframes == 1) & (is_prev_sounding)) > + break; > + How about adding this check in a similar way as the IEEE80211_TX_CTL_RATE_CTRL_PROBE flag check, instead of adding the is_prev_sounding variable. That way you won't introduce the same bug that rate control probing had before I fixed it. - Felix ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 2/5] ath: Add a keycache entry if beamforming is enabled. 2010-11-10 12:23 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Vivek Natarajan 2010-11-10 12:23 ` [RFC 3/5] ath9k_common: Add HTC field length if order bit is set Vivek Natarajan @ 2010-11-10 12:47 ` Felix Fietkau 1 sibling, 0 replies; 11+ messages in thread From: Felix Fietkau @ 2010-11-10 12:47 UTC (permalink / raw) To: Vivek Natarajan; +Cc: linux-wireless On 2010-11-10 1:23 PM, Vivek Natarajan wrote: > Keycache entry for a sta has the details of the negotiated > beamforming parameters which is to be used by the hardware > while trasmitting to that specific sta. > > Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> > --- > drivers/net/wireless/ath/ath.h | 2 ++ > drivers/net/wireless/ath/key.c | 29 +++++++++++++++++++++++++++++ > 2 files changed, 31 insertions(+), 0 deletions(-) > > diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c > index 62e3dac..11f562e 100644 > --- a/drivers/net/wireless/ath/key.c > +++ b/drivers/net/wireless/ath/key.c > @@ -115,6 +115,7 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, > void *ah = common->ah; > u32 key0, key1, key2, key3, key4; > u32 keyType; > + u32 txbf = 0; > > if (entry >= common->keymax) { > ath_print(common, ATH_DBG_FATAL, > @@ -199,6 +200,9 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, > REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); > REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); > > + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), > + keyType | txbf); > + > /* Write MAC address for the entry */ > (void) ath_hw_keysetmac(common, entry, mac); > What's the point of this change, if txbf is always zero? And why duplicate the REG_WRITE? - Felix ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 1/5] mac80211: Add support for transmit beam forming. 2010-11-10 12:23 [RFC 1/5] mac80211: Add support for transmit beam forming Vivek Natarajan 2010-11-10 12:23 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Vivek Natarajan @ 2010-11-10 12:44 ` Felix Fietkau 2010-11-10 16:22 ` Johannes Berg 2 siblings, 0 replies; 11+ messages in thread From: Felix Fietkau @ 2010-11-10 12:44 UTC (permalink / raw) To: Vivek Natarajan; +Cc: linux-wireless On 2010-11-10 1:23 PM, Vivek Natarajan wrote: > Enable beamforming if the driver and the AP are capable of sending > and receiving beam-formed frames. > > Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com> > --- > include/linux/ieee80211.h | 41 ++++++++++++++++++++++++++++++++++++++++- > include/net/cfg80211.h | 6 ++++++ > include/net/mac80211.h | 9 +++++++-- > net/mac80211/cfg.c | 7 +++++++ > net/mac80211/ht.c | 18 ++++++++++++++++++ > net/mac80211/ieee80211_i.h | 1 + > net/mac80211/mlme.c | 19 +++++++++++++++++++ > net/mac80211/rx.c | 10 ++++++++++ > net/mac80211/sta_info.c | 2 ++ > net/mac80211/sta_info.h | 6 ++++++ > net/mac80211/status.c | 19 +++++++++++++++++++ > net/mac80211/tx.c | 27 ++++++++++++++++++++++++--- > net/mac80211/work.c | 1 + > 13 files changed, 160 insertions(+), 6 deletions(-) > > diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h > index ed5a03c..ba92b73 100644 > --- a/include/linux/ieee80211.h > +++ b/include/linux/ieee80211.h [...] > /** > * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set > * @fc: frame control bytes in little-endian byteorder > @@ -827,6 +843,29 @@ struct ieee80211_mcs_info { > u8 reserved[3]; > } __attribute__((packed)); > > +struct ieee80211_txbf_caps { > + u32 implicit_rx_capable:1, > + rx_staggered_sounding:1, > + tx_staggered_sounding:1, > + rx_ndp_capable:1, > + tx_ndp_capable:1, > + implicit_txbf_capable:1, > + calibration:2, > + explicit_csi_txbf_capable:1, > + explicit_noncomp_steering:1, > + explicit_comp_steering:1, > + explicit_csi_feedback:2, > + explicit_noncomp_bf:2, > + explicit_comp_bf:2, > + minimal_grouping:2, > + csi_bfer_antennas:2, > + noncomp_bfer_antennas:2, > + comp_bfer_antennas:2, > + csi_max_rows_bfer:2, > + channel_estimation_cap:2, > + reserved:3; > +}; > + > /* 802.11n HT capability MSC set */ > #define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff > #define IEEE80211_HT_MCS_TX_DEFINED 0x01 > @@ -862,7 +901,7 @@ struct ieee80211_ht_cap { > struct ieee80211_mcs_info mcs; > > __le16 extended_ht_cap_info; > - __le32 tx_BF_cap_info; > + struct ieee80211_txbf_caps tx_BF_cap_info; > u8 antenna_selection_info; > } __attribute__ ((packed)); What about big endian? I think it's better to just use defines with the proper masks - bitfields make handling endian differences harder. - Felix ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 1/5] mac80211: Add support for transmit beam forming. 2010-11-10 12:23 [RFC 1/5] mac80211: Add support for transmit beam forming Vivek Natarajan 2010-11-10 12:23 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Vivek Natarajan 2010-11-10 12:44 ` [RFC 1/5] mac80211: Add support for transmit beam forming Felix Fietkau @ 2010-11-10 16:22 ` Johannes Berg 2 siblings, 0 replies; 11+ messages in thread From: Johannes Berg @ 2010-11-10 16:22 UTC (permalink / raw) To: Vivek Natarajan; +Cc: linux-wireless On Wed, 2010-11-10 at 17:53 +0530, Vivek Natarajan wrote: > +struct ieee80211_txbf_caps { > + u32 implicit_rx_capable:1, > + rx_staggered_sounding:1, > + tx_staggered_sounding:1, > + rx_ndp_capable:1, > + tx_ndp_capable:1, > + implicit_txbf_capable:1, > + calibration:2, > + explicit_csi_txbf_capable:1, > + explicit_noncomp_steering:1, > + explicit_comp_steering:1, > + explicit_csi_feedback:2, > + explicit_noncomp_bf:2, > + explicit_comp_bf:2, > + minimal_grouping:2, > + csi_bfer_antennas:2, > + noncomp_bfer_antennas:2, > + comp_bfer_antennas:2, > + csi_max_rows_bfer:2, > + channel_estimation_cap:2, > + reserved:3; > +}; No way, never use bitfields. > @@ -862,7 +901,7 @@ struct ieee80211_ht_cap { > struct ieee80211_mcs_info mcs; > > __le16 extended_ht_cap_info; > - __le32 tx_BF_cap_info; > + struct ieee80211_txbf_caps tx_BF_cap_info; > u8 antenna_selection_info; > } __attribute__ ((packed)); keep __le32 and add #defines for the bits. > @@ -321,6 +321,8 @@ struct ieee80211_bss_conf { > * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame > * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this > * frame and selects the maximum number of streams that it can use. > + * @IEEE80211_TX_CTL_TXBF_UPDATE: Channel information needs to be updated > + * for beamforming of Tx frames. > * > * Note: If you have to add new flags to the enumeration, then don't > * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. > @@ -349,6 +351,8 @@ enum mac80211_tx_control_flags { > IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), > IEEE80211_TX_CTL_LDPC = BIT(22), > IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), > + IEEE80211_TX_CTL_TXBF_UPDATE = BIT(25), > + IEEE80211_TX_CTL_STAG_SOUND = BIT(26), Missing docs for the second entry. > #define IEEE80211_TX_CTL_STBC_SHIFT 23 > @@ -364,7 +368,7 @@ enum mac80211_tx_control_flags { > IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ > IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ > IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ > - IEEE80211_TX_CTL_STBC) > + IEEE80211_TX_CTL_STBC | IEEE80211_TX_CTL_TXBF_UPDATE) Therefore I cannot evaluate this change. > @@ -900,7 +904,8 @@ struct ieee80211_sta { > u8 addr[ETH_ALEN]; > u16 aid; > struct ieee80211_sta_ht_cap ht_cap; > - > + bool txbf; not sure I like names that short -- docs missing too > @@ -698,6 +698,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, > params->ht_capa, > &sta->sta.ht_cap); > > + if (sta->sta.ht_cap.explicit_compbf || > + sta->sta.ht_cap.explicit_noncompbf || > + sta->sta.ht_cap.implicit_bf) { > + sta->sta.txbf = true; > + sta->bf_update_cv = true; > + } I wonder at what point we should move the capability handling from hostapd to the kernel ... > @@ -99,6 +100,23 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, > /* handle MCS rate 32 too */ > if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) > ht_cap->mcs.rx_mask[32/8] |= 1; > + > + bfee = ht_cap_ie->tx_BF_cap_info; > + bfmr = sband->ht_cap.txbf; Nice variable names... what? > + if (bfmr.explicit_comp_steering && (bfee.explicit_comp_bf != 0)) > + ht_cap->explicit_compbf = true; > + > + if (bfmr.explicit_noncomp_steering && (bfee.explicit_noncomp_bf != 0)) > + ht_cap->explicit_noncompbf = true; > + > + if (bfmr.implicit_txbf_capable && bfee.implicit_rx_capable) > + ht_cap->implicit_bf = true; xx = a && b; instead of the if? > --- a/net/mac80211/mlme.c > +++ b/net/mac80211/mlme.c > @@ -63,6 +63,8 @@ > #define TMR_RUNNING_TIMER 0 > #define TMR_RUNNING_CHANSW 1 > > +#define TXBF_CV_TIMER 1000 Err ... missing units. > +void ieee80211_txbf_cv_work(struct work_struct *work) > +{ > + struct sta_info *sta = > + container_of(work, struct sta_info, txbf_cv_work.work); > + struct ieee80211_local *local = sta->local; > + > + sta->bf_update_cv = true; > + ieee80211_queue_delayed_work(&local->hw, > + &sta->txbf_cv_work, TXBF_CV_TIMER); > +} self arming -- how does it get cancelled properly? also, this is part of a sta_info entry, so why is it in mlme.c?? > --- a/net/mac80211/rx.c > +++ b/net/mac80211/rx.c > @@ -1455,6 +1455,16 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) > if (!ieee80211_is_data_qos(hdr->frame_control)) > return RX_CONTINUE; > > + /* Qos frame with Order bit set indicates an HTC frame */ > + if (ieee80211_has_order(hdr->frame_control)) { > + memmove(data + IEEE80211_QOS_HTC_LEN, data, > + ieee80211_hdrlen(hdr->frame_control) - > + IEEE80211_QOS_HTC_LEN); > + hdr = (struct ieee80211_hdr *)skb_pull(rx->skb, > + IEEE80211_QOS_HTC_LEN); > + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER); > + } > + > /* remove the qos control field, update frame type and meta-data */ > memmove(data + IEEE80211_QOS_CTL_LEN, data, > ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN); > diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c > index 6d8f897..829398e 100644 > --- a/net/mac80211/sta_info.c > +++ b/net/mac80211/sta_info.c > @@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, > spin_lock_init(&sta->flaglock); > INIT_WORK(&sta->drv_unblock_wk, sta_unblock); > INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); > + INIT_DELAYED_WORK(&sta->txbf_cv_work, ieee80211_txbf_cv_work); > mutex_init(&sta->ampdu_mlme.mtx); > > memcpy(sta->sta.addr, addr, ETH_ALEN); > @@ -691,6 +692,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) > wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr); > #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ > cancel_work_sync(&sta->drv_unblock_wk); > + cancel_delayed_work_sync(&sta->txbf_cv_work); > > rate_control_remove_sta_debugfs(sta); > ieee80211_sta_debugfs_remove(sta); > diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h > index 9265aca..61631e3 100644 > --- a/net/mac80211/sta_info.h > +++ b/net/mac80211/sta_info.h > @@ -312,6 +312,12 @@ struct sta_info { > struct sta_ampdu_mlme ampdu_mlme; > u8 timer_to_tid[STA_TID_NUM]; > > + bool txbf; > + bool bf_update_cv; > + bool bf_sound_pending; > + bool allow_cv_update; > + struct delayed_work txbf_cv_work; > + > #ifdef CONFIG_MAC80211_MESH > /* > * Mesh peer link attributes > diff --git a/net/mac80211/status.c b/net/mac80211/status.c > index 3153c19..b0447ca 100644 > --- a/net/mac80211/status.c > +++ b/net/mac80211/status.c > @@ -209,6 +209,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) > return; > } > > + if (ieee80211_has_order(fc)) { > + if ((info->flags & IEEE80211_TX_STAT_ACK) && > + (sta->bf_sound_pending)) { > + sta->bf_sound_pending = false; > + ieee80211_queue_delayed_work(&local->hw, > + &sta->txbf_cv_work, 1000); 1000 what? > + } else > + sta->bf_update_cv = true; > + } > + > + > + if ((info->flags & IEEE80211_TX_CTL_TXBF_UPDATE) && > + !(sta->bf_sound_pending)) { > + if (sta->sta.ht_cap.explicit_compbf || > + sta->sta.ht_cap.explicit_noncompbf || > + sta->sta.ht_cap.implicit_bf) > + sta->bf_update_cv = true; > + } > + > if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) && > (rates_idx != -1)) > sta->last_tx_rate = info->status.rates[rates_idx]; > diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c > index 96c5943..5900cf2 100644 > --- a/net/mac80211/tx.c > +++ b/net/mac80211/tx.c > @@ -1888,6 +1888,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, > if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) { > fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); > hdrlen += 2; > + if (sta->bf_update_cv) > + hdrlen += 4; 4? > @@ -1973,9 +1975,28 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, > > if (ieee80211_is_data_qos(fc)) { > __le16 *qos_control; > - > - qos_control = (__le16*) skb_push(skb, 2); > - memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2); > + __le32 *htc; > + > + if (sta->bf_update_cv) { It seems to me that this variable access is racy between the hdrlen += 4 and checking it again here since there's no locking on it. > + hdr.frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER); > + htc = (__le32 *) skb_push(skb, 4); > + sta->bf_sound_pending = true; > + *htc = 0; > + sta->bf_update_cv = false; > + > + if (sta->sta.ht_cap.explicit_compbf) > + *htc |= IEEE80211_HTC2_CSI_COMP_BF; no cpu_to_le32? have you run sparse on this? > + qos_control = (__le16 *) skb_push(skb, 2); > + memcpy(skb_push(skb, hdrlen - 6), &hdr, hdrlen - 6); > + } else { > + qos_control = (__le16 *) skb_push(skb, 2); > + memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2); > + }; }; ??? also why not move this out of the if()? johannes ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2010-11-10 17:26 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-11-10 12:23 [RFC 1/5] mac80211: Add support for transmit beam forming Vivek Natarajan 2010-11-10 12:23 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Vivek Natarajan 2010-11-10 12:23 ` [RFC 3/5] ath9k_common: Add HTC field length if order bit is set Vivek Natarajan 2010-11-10 12:23 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Vivek Natarajan 2010-11-10 12:23 ` [RFC 5/5] ath9k_hw: Add support for Tx beamforming Vivek Natarajan 2010-11-10 13:26 ` Felix Fietkau 2010-11-10 17:25 ` Luis R. Rodriguez 2010-11-10 13:06 ` [RFC 4/5] ath9k: Add support for Tx beamforming feature Felix Fietkau 2010-11-10 12:47 ` [RFC 2/5] ath: Add a keycache entry if beamforming is enabled Felix Fietkau 2010-11-10 12:44 ` [RFC 1/5] mac80211: Add support for transmit beam forming Felix Fietkau 2010-11-10 16:22 ` Johannes Berg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).