aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rtlwifi/rtl8192cu/hw.c')
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c191
1 files changed, 136 insertions, 55 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index c08d0f4c5f3..a903c2671b4 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -202,7 +202,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
@@ -238,11 +238,11 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
((rtlefuse->eeprom_pwrlimit_ht40[index]
& 0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -273,26 +273,26 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->legacy_ht_txpowerdiff =
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
if (!autoload_fail)
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail) {
rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
@@ -301,7 +301,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI;
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -316,7 +316,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail)
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
@@ -394,7 +394,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
if (rtlefuse->eeprom_did == 0x8176) {
if ((rtlefuse->eeprom_svid == 0x103C &&
rtlefuse->eeprom_smid == 0x1629))
- rtlhal->oem_id = RT_CID_819x_HP;
+ rtlhal->oem_id = RT_CID_819X_HP;
else
rtlhal->oem_id = RT_CID_DEFAULT;
} else {
@@ -405,7 +405,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
rtlhal->oem_id = RT_CID_TOSHIBA;
break;
case EEPROM_CID_QMI:
- rtlhal->oem_id = RT_CID_819x_QMI;
+ rtlhal->oem_id = RT_CID_819X_QMI;
break;
case EEPROM_CID_WHQL:
default:
@@ -423,14 +423,14 @@ static void _rtl92cu_hal_customized_behavior(struct ieee80211_hw *hw)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
switch (rtlhal->oem_id) {
- case RT_CID_819x_HP:
+ case RT_CID_819X_HP:
usb_priv->ledctl.led_opendrain = true;
break;
- case RT_CID_819x_Lenovo:
+ case RT_CID_819X_LENOVO:
case RT_CID_DEFAULT:
case RT_CID_TOSHIBA:
case RT_CID_CCX:
- case RT_CID_819x_Acer:
+ case RT_CID_819X_ACER:
case RT_CID_WHQL:
default:
break;
@@ -511,7 +511,7 @@ static int _rtl92cu_init_power_on(struct ieee80211_hw *hw)
pr_info("MAC auto ON okay!\n");
break;
}
- if (pollingCount++ > 100) {
+ if (pollingCount++ > 1000) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
"Failed to polling REG_APS_FSMCO[APFM_ONMAC] done!\n");
return -ENODEV;
@@ -985,19 +985,30 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
int err = 0;
static bool iqk_initialized;
+ unsigned long flags;
+
+ /* As this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU;
err = _rtl92cu_init_mac(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "init mac failed!\n");
- return err;
+ goto exit;
}
err = rtl92c_download_fw(hw);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
- return err;
+ goto exit;
}
rtlhal->last_hmeboxnum = 0; /* h2c */
_rtl92cu_phy_param_tab_init(hw);
@@ -1022,7 +1033,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
if (ppsc->rfpwr_state == ERFON) {
rtl92c_phy_set_rfpath_switch(hw, 1);
if (iqk_initialized) {
- rtl92c_phy_iq_calibrate(hw, false);
+ rtl92c_phy_iq_calibrate(hw, true);
} else {
rtl92c_phy_iq_calibrate(hw, false);
iqk_initialized = true;
@@ -1034,6 +1045,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
_InitPABias(hw);
_update_mac_setting(hw);
rtl92c_dm_init(hw);
+exit:
+ local_irq_restore(flags);
return err;
}
@@ -1379,11 +1392,13 @@ void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
- u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ u32 reg_rcr;
if (rtlpriv->psc.rfpwr_state != ERFON)
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
if (check_bssid) {
u8 tmp;
if (IS_NORMAL_CHIP(rtlhal->version)) {
@@ -1795,7 +1810,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
e_aci);
break;
}
- if (rtlusb->acm_method != eAcmWay2_SW)
+ if (rtlusb->acm_method != EACMWAY2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_ACM_CTRL, &e_aci);
break;
@@ -1973,26 +1988,35 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
}
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta,
- u8 rssi_level)
+static void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u32 ratr_value = (u32) mac->basic_rates;
- u8 *mcsrate = mac->mcs;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
u8 ratr_index = 0;
u8 nmode = mac->ht_enable;
- u8 mimo_ps = 1;
- u16 shortgi_rate = 0;
- u32 tmp_ratr_value = 0;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+ u16 shortgi_rate;
+ u32 tmp_ratr_value;
u8 curtxbw_40mhz = mac->bw_40;
- u8 curshortgi_40mhz = mac->sgi_40;
- u8 curshortgi_20mhz = mac->sgi_20;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
enum wireless_mode wirelessmode = mac->mode;
- ratr_value |= ((*(u16 *) (mcsrate))) << 12;
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
+
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
case WIRELESS_MODE_B:
if (ratr_value & 0x0000000c)
@@ -2006,7 +2030,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G:
nmode = 1;
- if (mimo_ps == 0) {
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
ratr_value &= 0x0007F005;
} else {
u32 ratr_mask;
@@ -2016,8 +2040,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_mask = 0x000ff005;
else
ratr_mask = 0x0f0ff005;
- if (curtxbw_40mhz)
- ratr_mask |= 0x00000010;
+
ratr_value &= ratr_mask;
}
break;
@@ -2026,41 +2049,74 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_value &= 0x000ff0ff;
else
ratr_value &= 0x0f0ff0ff;
+
break;
}
+
ratr_value &= 0x0FFFFFFF;
- if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
- (!curtxbw_40mhz && curshortgi_20mhz))) {
+
+ if (nmode && ((curtxbw_40mhz &&
+ curshortgi_40mhz) || (!curtxbw_40mhz &&
+ curshortgi_20mhz))) {
+
ratr_value |= 0x10000000;
tmp_ratr_value = (ratr_value >> 12);
+
for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
if ((1 << shortgi_rate) & tmp_ratr_value)
break;
}
+
shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
- (shortgi_rate << 4) | (shortgi_rate);
+ (shortgi_rate << 4) | (shortgi_rate);
}
+
rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n",
+ rtl_read_dword(rtlpriv, REG_ARFR0));
}
-void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
+static void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u32 ratr_bitmap = (u32) mac->basic_rates;
- u8 *p_mcsrate = mac->mcs;
- u8 ratr_index = 0;
- u8 curtxbw_40mhz = mac->bw_40;
- u8 curshortgi_40mhz = mac->sgi_40;
- u8 curshortgi_20mhz = mac->sgi_20;
- enum wireless_mode wirelessmode = mac->mode;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
+ u8 ratr_index;
+ u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
+ u8 curshortgi_40mhz = curtxbw_40mhz &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = 0;
bool shortgi = false;
u8 rate_mask[5];
u8 macid = 0;
- u8 mimops = 1;
-
- ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12);
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
+ curtxbw_40mhz = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_bitmap = sta->supp_rates[1] << 4;
+ else
+ ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
case WIRELESS_MODE_B:
ratr_index = RATR_INX_WIRELESS_B;
@@ -2071,6 +2127,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
break;
case WIRELESS_MODE_G:
ratr_index = RATR_INX_WIRELESS_GB;
+
if (rssi_level == 1)
ratr_bitmap &= 0x00000f00;
else if (rssi_level == 2)
@@ -2085,7 +2142,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G:
ratr_index = RATR_INX_WIRELESS_NGB;
- if (mimops == 0) {
+
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
if (rssi_level == 1)
ratr_bitmap &= 0x00070000;
else if (rssi_level == 2)
@@ -2128,8 +2186,10 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
}
}
}
+
if ((curtxbw_40mhz && curshortgi_40mhz) ||
(!curtxbw_40mhz && curshortgi_20mhz)) {
+
if (macid == 0)
shortgi = true;
else if (macid == 1)
@@ -2138,21 +2198,42 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
break;
default:
ratr_index = RATR_INX_WIRELESS_NGB;
+
if (rtlphy->rf_type == RF_1T2R)
ratr_bitmap &= 0x000ff0ff;
else
ratr_bitmap &= 0x0f0ff0ff;
break;
}
- RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n",
- ratr_bitmap);
- *(u32 *)&rate_mask = ((ratr_bitmap & 0x0fffffff) |
- ratr_index << 28);
+ sta_entry->ratr_index = ratr_index;
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "ratr_bitmap :%x\n", ratr_bitmap);
+ *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+ (ratr_index << 28);
rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
"Rate_index:%x, ratr_val:%x, %5phC\n",
ratr_index, ratr_bitmap, rate_mask);
- rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+ memcpy(rtlpriv->rate_mask, rate_mask, 5);
+ /* rtl92c_fill_h2c_cmd() does USB I/O and will result in a
+ * "scheduled while atomic" if called directly */
+ schedule_work(&rtlpriv->works.fill_h2c_cmd);
+
+ if (macid != 0)
+ sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.useramask)
+ rtl92cu_update_hal_rate_mask(hw, sta, rssi_level);
+ else
+ rtl92cu_update_hal_rate_table(hw, sta);
}
void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw)