*/
#include <linux/firmware.h>
+#include <linux/iopoll.h>
#include "regs.h"
#include "rtl8xxxu.h"
return sta_info->macid;
}
+static void rtl8xxxu_request_hw_feature(struct rtl8xxxu_priv *priv)
+{
+ if (!priv->fops->hw_feature_report)
+ return;
+
+ rtl8xxxu_write8(priv, REG_C2HEVT_MSG_NORMAL, C2H_HW_FEATURE_DUMP);
+}
+
+static int rtl8xxxu_dump_hw_feature(struct rtl8xxxu_priv *priv)
+{
+ static const u8 bw_map[8] = { 0, 0, 160, 5, 10, 20, 40, 80 };
+ struct rtl8xxxu_hw_feature *hw_feature = &priv->hw_feature;
+ u8 feature[13];
+ int i, ret;
+ u8 id, bw;
+
+ if (!priv->fops->hw_feature_report) {
+ hw_feature->max_bw = 40;
+ return 0;
+ }
+
+ ret = read_poll_timeout(rtl8xxxu_read8, id,
+ id == C2H_HW_FEATURE_REPORT,
+ 10000, 800000, false,
+ priv, REG_C2HEVT_MSG_NORMAL);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(feature); i++)
+ feature[i] = rtl8xxxu_read8(priv, REG_C2HEVT_MSG_NORMAL + 2 + i);
+
+ rtl8xxxu_write8(priv, REG_C2HEVT_MSG_NORMAL, 0);
+
+ bw = u8_get_bits(feature[6], GENMASK(2, 0));
+
+ hw_feature->max_bw = bw_map[bw];
+
+ return 0;
+}
+
static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
{
struct rtl8xxxu_priv *priv = hw->priv;
*/
rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, fops->trxff_boundary);
+ rtl8xxxu_request_hw_feature(priv);
+
for (int retry = 5; retry >= 0 ; retry--) {
ret = rtl8xxxu_download_firmware(priv);
dev_dbg(dev, "%s: download_firmware %i\n", __func__, ret);
if (ret)
goto exit;
+ ret = rtl8xxxu_dump_hw_feature(priv);
+ if (ret) {
+ dev_err(dev, "failed to dump hw feature\n");
+ goto exit;
+ }
+
if (fops->phy_init_antenna_selection)
fops->phy_init_antenna_selection(priv);
sband->ht_cap.ht_supported = true;
sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
sband->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
- sband->ht_cap.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ sband->ht_cap.cap = IEEE80211_HT_CAP_SGI_20;
+
+ if (priv->hw_feature.max_bw >= 40) {
+ sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ } else {
+ dev_info(&udev->dev, "hardware doesn't support HT40\n");
+ }
+
memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs));
sband->ht_cap.mcs.rx_mask[0] = 0xff;
sband->ht_cap.mcs.rx_mask[4] = 0x01;
- if (priv->rf_paths > 1) {
+ if (priv->rf_paths > 1)
sband->ht_cap.mcs.rx_mask[1] = 0xff;
- sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
- }
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
hw->wiphy->bands[NL80211_BAND_2GHZ] = sband;