|
@@ -1359,11 +1359,124 @@ lim_decide_short_slot(struct mac_context *mac_ctx, tpDphHashNode sta_ds,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static uint8_t lim_get_nss_from_vht_mcs_map(uint16_t mcs_map)
|
|
|
+{
|
|
|
+ uint8_t nss = 0;
|
|
|
+ uint16_t mcs_mask = 0x3;
|
|
|
+
|
|
|
+ for (nss = 0; nss < VHT_MAX_NSS; nss++) {
|
|
|
+ if ((mcs_map & mcs_mask) == mcs_mask)
|
|
|
+ return nss;
|
|
|
+
|
|
|
+ mcs_mask = (mcs_mask << 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ return nss;
|
|
|
+}
|
|
|
+
|
|
|
+static void lim_get_vht_gt80_nss(struct mac_context *mac_ctx,
|
|
|
+ struct sDphHashNode *sta_ds,
|
|
|
+ tDot11fIEVHTCaps *vht_caps,
|
|
|
+ struct pe_session *session)
|
|
|
+{
|
|
|
+ uint8_t nss;
|
|
|
+
|
|
|
+ if (!vht_caps->vht_extended_nss_bw_cap) {
|
|
|
+ sta_ds->vht_160mhz_nss = 0;
|
|
|
+ sta_ds->vht_80p80mhz_nss = 0;
|
|
|
+ pe_debug("peer does not support vht extnd nss bw");
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ nss = lim_get_nss_from_vht_mcs_map(vht_caps->rxMCSMap);
|
|
|
+
|
|
|
+ if (!nss) {
|
|
|
+ pe_debug("Invalid peer VHT MCS map %0X", vht_caps->rxMCSMap);
|
|
|
+ nss = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (vht_caps->supportedChannelWidthSet) {
|
|
|
+ case VHT_CAP_NO_160M_SUPP:
|
|
|
+ if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_80_HALF_NSS_160) {
|
|
|
+ sta_ds->vht_160mhz_nss = nss / 2;
|
|
|
+ sta_ds->vht_80p80mhz_nss = 0;
|
|
|
+ } else if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_80_HALF_NSS_80P80) {
|
|
|
+ sta_ds->vht_160mhz_nss = nss / 2;
|
|
|
+ sta_ds->vht_80p80mhz_nss = nss / 2;
|
|
|
+ } else if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_80_3QUART_NSS_80P80) {
|
|
|
+ sta_ds->vht_160mhz_nss = (nss * 3) / 4;
|
|
|
+ sta_ds->vht_80p80mhz_nss = (nss * 3) / 4;
|
|
|
+ } else {
|
|
|
+ sta_ds->vht_160mhz_nss = 0;
|
|
|
+ sta_ds->vht_80p80mhz_nss = 0;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case VHT_CAP_160_SUPP:
|
|
|
+ sta_ds->vht_160mhz_nss = nss;
|
|
|
+ if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_160_HALF_NSS_80P80) {
|
|
|
+ sta_ds->vht_80p80mhz_nss = nss / 2;
|
|
|
+ } else if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_160_3QUART_NSS_80P80) {
|
|
|
+ sta_ds->vht_80p80mhz_nss = (nss * 3) / 4;
|
|
|
+ } else if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_2X_NSS_160_1X_NSS_80P80) {
|
|
|
+ if (nss > (VHT_MAX_NSS / 2)) {
|
|
|
+ pe_debug("Invalid extnd nss bw support val");
|
|
|
+ sta_ds->vht_80p80mhz_nss = nss / 2;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ sta_ds->vht_160mhz_nss = nss * 2;
|
|
|
+ if (session->nss == MAX_VDEV_NSS)
|
|
|
+ break;
|
|
|
+ if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2)
|
|
|
+ break;
|
|
|
+ session->nss *= 2;
|
|
|
+ } else {
|
|
|
+ sta_ds->vht_80p80mhz_nss = 0;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case VHT_CAP_160_AND_80P80_SUPP:
|
|
|
+ if (vht_caps->extended_nss_bw_supp ==
|
|
|
+ VHT_EXTD_NSS_2X_NSS_80_1X_NSS_80P80) {
|
|
|
+ if (nss > (VHT_MAX_NSS / 2)) {
|
|
|
+ pe_debug("Invalid extnd nss bw support val");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (session->nss == MAX_VDEV_NSS)
|
|
|
+ break;
|
|
|
+ if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2)
|
|
|
+ break;
|
|
|
+ session->nss *= 2;
|
|
|
+ } else {
|
|
|
+ sta_ds->vht_160mhz_nss = nss;
|
|
|
+ sta_ds->vht_80p80mhz_nss = nss;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ sta_ds->vht_160mhz_nss = 0;
|
|
|
+ sta_ds->vht_80p80mhz_nss = 0;
|
|
|
+ }
|
|
|
+ pe_debug("AP Nss config: 160MHz: %d, 80P80MHz %d",
|
|
|
+ sta_ds->vht_160mhz_nss, sta_ds->vht_80p80mhz_nss);
|
|
|
+ sta_ds->vht_160mhz_nss = QDF_MIN(sta_ds->vht_160mhz_nss, session->nss);
|
|
|
+ sta_ds->vht_80p80mhz_nss = QDF_MIN(sta_ds->vht_80p80mhz_nss,
|
|
|
+ session->nss);
|
|
|
+ pe_debug("Session Nss config: 160MHz: %d, 80P80MHz %d, session Nss %d",
|
|
|
+ sta_ds->vht_160mhz_nss, sta_ds->vht_80p80mhz_nss,
|
|
|
+ session->nss);
|
|
|
+}
|
|
|
+
|
|
|
QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
|
|
|
struct supported_rates *rates,
|
|
|
tDot11fIEVHTCaps *peer_vht_caps,
|
|
|
struct pe_session *session_entry,
|
|
|
- uint8_t nss)
|
|
|
+ uint8_t nss,
|
|
|
+ struct sDphHashNode *sta_ds)
|
|
|
{
|
|
|
uint32_t self_sta_dot11mode = 0;
|
|
|
uint16_t mcs_map_mask = MCSMAPMASK1x1;
|
|
@@ -1375,6 +1488,9 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
|
|
|
if (!IS_DOT11_MODE_VHT(self_sta_dot11mode))
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
|
|
|
+ if (!peer_vht_caps || !peer_vht_caps->present)
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+
|
|
|
vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info;
|
|
|
|
|
|
rates->vhtRxMCSMap = (uint16_t)vht_cap_info->rx_mcs_map;
|
|
@@ -1412,9 +1528,6 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if ((!peer_vht_caps) || (!peer_vht_caps->present))
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
rates->vhtTxHighestDataRate =
|
|
|
QDF_MIN(rates->vhtTxHighestDataRate,
|
|
|
peer_vht_caps->txSupDataRate);
|
|
@@ -1428,24 +1541,19 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
|
|
|
if ((peer_vht_caps->txMCSMap & mcs_map_mask) <
|
|
|
(rates->vhtRxMCSMap & mcs_map_mask)) {
|
|
|
rates->vhtRxMCSMap &= ~(mcs_map_mask);
|
|
|
- rates->vhtRxMCSMap |=
|
|
|
- (peer_vht_caps->txMCSMap & mcs_map_mask);
|
|
|
+ rates->vhtRxMCSMap |= (peer_vht_caps->txMCSMap & mcs_map_mask);
|
|
|
}
|
|
|
if ((peer_vht_caps->rxMCSMap & mcs_map_mask) <
|
|
|
(rates->vhtTxMCSMap & mcs_map_mask)) {
|
|
|
rates->vhtTxMCSMap &= ~(mcs_map_mask);
|
|
|
- rates->vhtTxMCSMap |=
|
|
|
- (peer_vht_caps->rxMCSMap & mcs_map_mask);
|
|
|
+ rates->vhtTxMCSMap |= (peer_vht_caps->rxMCSMap & mcs_map_mask);
|
|
|
}
|
|
|
|
|
|
if (mcs_map_mask2x2) {
|
|
|
-
|
|
|
uint16_t peer_mcs_map, self_mcs_map;
|
|
|
|
|
|
- peer_mcs_map =
|
|
|
- peer_vht_caps->txMCSMap & mcs_map_mask2x2;
|
|
|
- self_mcs_map =
|
|
|
- rates->vhtRxMCSMap & mcs_map_mask2x2;
|
|
|
+ peer_mcs_map = peer_vht_caps->txMCSMap & mcs_map_mask2x2;
|
|
|
+ self_mcs_map = rates->vhtRxMCSMap & mcs_map_mask2x2;
|
|
|
|
|
|
if ((self_mcs_map != mcs_map_mask2x2) &&
|
|
|
((peer_mcs_map == mcs_map_mask2x2) ||
|
|
@@ -1454,10 +1562,8 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
|
|
|
rates->vhtRxMCSMap |= peer_mcs_map;
|
|
|
}
|
|
|
|
|
|
- peer_mcs_map =
|
|
|
- (peer_vht_caps->rxMCSMap & mcs_map_mask2x2);
|
|
|
- self_mcs_map =
|
|
|
- (rates->vhtTxMCSMap & mcs_map_mask2x2);
|
|
|
+ peer_mcs_map = (peer_vht_caps->rxMCSMap & mcs_map_mask2x2);
|
|
|
+ self_mcs_map = (rates->vhtTxMCSMap & mcs_map_mask2x2);
|
|
|
|
|
|
if ((self_mcs_map != mcs_map_mask2x2) &&
|
|
|
((peer_mcs_map == mcs_map_mask2x2) ||
|
|
@@ -1466,18 +1572,24 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
|
|
|
rates->vhtTxMCSMap |= peer_mcs_map;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
pe_debug("enable2x2 - %d nss %d vhtRxMCSMap - %x vhtTxMCSMap - %x",
|
|
|
vht_cap_info->enable2x2, nss,
|
|
|
rates->vhtRxMCSMap, rates->vhtTxMCSMap);
|
|
|
|
|
|
- if (session_entry) {
|
|
|
- session_entry->supported_nss_1x1 =
|
|
|
- ((rates->vhtTxMCSMap & VHT_MCS_1x1) ==
|
|
|
- VHT_MCS_1x1) ? true : false;
|
|
|
- pe_debug("VHT supported nss 1x1: %d",
|
|
|
- session_entry->supported_nss_1x1);
|
|
|
- }
|
|
|
+ if (!session_entry)
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+
|
|
|
+ session_entry->supported_nss_1x1 =
|
|
|
+ ((rates->vhtTxMCSMap & VHT_MCS_1x1) == VHT_MCS_1x1) ?
|
|
|
+ true : false;
|
|
|
+ pe_debug("VHT supported nss 1x1: %d", session_entry->supported_nss_1x1);
|
|
|
+
|
|
|
+ if (!sta_ds || CH_WIDTH_80MHZ >= session_entry->ch_width)
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+
|
|
|
+ sta_ds->vht_extended_nss_bw_cap =
|
|
|
+ peer_vht_caps->vht_extended_nss_bw_cap;
|
|
|
+ lim_get_vht_gt80_nss(mac_ctx, sta_ds, peer_vht_caps, session_entry);
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
@@ -1605,8 +1717,8 @@ QDF_STATUS lim_populate_own_rate_set(struct mac_context *mac_ctx,
|
|
|
for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++)
|
|
|
pe_debug("%x ", rates->supportedMCSSet[i]);
|
|
|
}
|
|
|
- lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps,
|
|
|
- session_entry, session_entry->nss);
|
|
|
+ lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps, session_entry,
|
|
|
+ session_entry->nss, NULL);
|
|
|
lim_populate_he_mcs_set(mac_ctx, rates, he_caps,
|
|
|
session_entry, session_entry->nss);
|
|
|
|
|
@@ -1641,7 +1753,8 @@ QDF_STATUS lim_populate_peer_rate_set(struct mac_context *mac,
|
|
|
uint8_t basicOnly,
|
|
|
struct pe_session *pe_session,
|
|
|
tDot11fIEVHTCaps *pVHTCaps,
|
|
|
- tDot11fIEhe_cap *he_caps)
|
|
|
+ tDot11fIEhe_cap *he_caps,
|
|
|
+ struct sDphHashNode *sta_ds)
|
|
|
{
|
|
|
tSirMacRateSet tempRateSet;
|
|
|
tSirMacRateSet tempRateSet2;
|
|
@@ -1772,8 +1885,8 @@ QDF_STATUS lim_populate_peer_rate_set(struct mac_context *mac,
|
|
|
pe_debug("HT supported nss 1x1: %d",
|
|
|
pe_session->supported_nss_1x1);
|
|
|
}
|
|
|
- lim_populate_vht_mcs_set(mac, pRates, pVHTCaps,
|
|
|
- pe_session, pe_session->nss);
|
|
|
+ lim_populate_vht_mcs_set(mac, pRates, pVHTCaps, pe_session,
|
|
|
+ pe_session->nss, sta_ds);
|
|
|
|
|
|
lim_populate_he_mcs_set(mac, pRates, he_caps,
|
|
|
pe_session, pe_session->nss);
|
|
@@ -2012,7 +2125,7 @@ QDF_STATUS lim_populate_matching_rate_set(struct mac_context *mac_ctx,
|
|
|
}
|
|
|
}
|
|
|
lim_populate_vht_mcs_set(mac_ctx, &sta_ds->supportedRates, vht_caps,
|
|
|
- session_entry, session_entry->nss);
|
|
|
+ session_entry, session_entry->nss, sta_ds);
|
|
|
lim_populate_he_mcs_set(mac_ctx, &sta_ds->supportedRates, he_caps,
|
|
|
session_entry, session_entry->nss);
|
|
|
/*
|
|
@@ -2074,8 +2187,8 @@ static uint32_t lim_populate_vht_caps(tDot11fIEVHTCaps input_caps)
|
|
|
SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) |
|
|
|
(input_caps.txAntPattern <<
|
|
|
SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) |
|
|
|
- (input_caps.reserved1 <<
|
|
|
- SIR_MAC_VHT_CAP_RESERVED2));
|
|
|
+ (input_caps.extended_nss_bw_supp <<
|
|
|
+ SIR_MAC_VHT_CAP_EXTD_NSS_BW));
|
|
|
|
|
|
return vht_caps;
|
|
|
}
|
|
@@ -2259,7 +2372,7 @@ lim_add_sta(struct mac_context *mac_ctx,
|
|
|
add_sta_params->maxAmpduSize = sta_ds->htMaxRxAMpduFactor;
|
|
|
add_sta_params->fShortGI20Mhz = sta_ds->htShortGI20Mhz;
|
|
|
add_sta_params->fShortGI40Mhz = sta_ds->htShortGI40Mhz;
|
|
|
- add_sta_params->ch_width = sta_ds->htSupportedChannelWidthSet;
|
|
|
+ add_sta_params->ch_width = sta_ds->ch_width;
|
|
|
add_sta_params->mimoPS = sta_ds->htMIMOPSState;
|
|
|
|
|
|
pe_debug("maxAmpduDensity: %d maxAmpduDensity: %d",
|
|
@@ -3414,8 +3527,8 @@ static void lim_update_vhtcaps_assoc_resp(struct mac_context *mac_ctx,
|
|
|
SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) |
|
|
|
(vht_caps->txAntPattern <<
|
|
|
SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) |
|
|
|
- (vht_caps->reserved1 <<
|
|
|
- SIR_MAC_VHT_CAP_RESERVED2));
|
|
|
+ (vht_caps->extended_nss_bw_supp <<
|
|
|
+ SIR_MAC_VHT_CAP_EXTD_NSS_BW));
|
|
|
|
|
|
pAddBssParams->staContext.maxAmpduSize =
|
|
|
SIR_MAC_GET_VHT_MAX_AMPDU_EXPO(
|
|
@@ -3665,6 +3778,19 @@ QDF_STATUS lim_sta_send_add_bss(struct mac_context *mac, tpSirAssocRsp pAssocRsp
|
|
|
if (vht_caps && pAddBssParams->staContext.stbc_capable)
|
|
|
pAddBssParams->staContext.stbc_capable =
|
|
|
vht_caps->rxSTBC;
|
|
|
+ if (pe_session->ch_width == CH_WIDTH_160MHZ ||
|
|
|
+ pe_session->ch_width == CH_WIDTH_80P80MHZ) {
|
|
|
+ sta_context->vht_160mhz_nss =
|
|
|
+ sta->vht_160mhz_nss;
|
|
|
+ sta_context->vht_80p80mhz_nss =
|
|
|
+ sta->vht_80p80mhz_nss;
|
|
|
+ sta_context->vht_extended_nss_bw_cap =
|
|
|
+ sta->vht_extended_nss_bw_cap;
|
|
|
+ } else {
|
|
|
+ sta_context->vht_160mhz_nss = 0;
|
|
|
+ sta_context->vht_80p80mhz_nss = 0;
|
|
|
+ sta_context->vht_extended_nss_bw_cap = 0;
|
|
|
+ }
|
|
|
}
|
|
|
if (lim_is_session_he_capable(pe_session) &&
|
|
|
pAssocRsp->he_cap.present) {
|
|
@@ -4166,7 +4292,7 @@ QDF_STATUS lim_sta_send_add_bss_pre_assoc(struct mac_context *mac,
|
|
|
pBeaconStruct->HTCaps.supportedMCSSet,
|
|
|
false, pe_session,
|
|
|
&pBeaconStruct->VHTCaps,
|
|
|
- &pBeaconStruct->he_cap);
|
|
|
+ &pBeaconStruct->he_cap, NULL);
|
|
|
|
|
|
pAddBssParams->staContext.encryptType = pe_session->encryptType;
|
|
|
|