diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-06-28 04:04:52 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-06-28 04:04:52 -0600 |
| commit | 40b5475e8b378f2b804e1cf2619523bf69b867bd (patch) | |
| tree | df9f8451f31521a86223c4fbf712dc636ed194a0 | |
| parent | 05e466a76f1864fe082aeb4751dc73ba79674440 (diff) | |
| parent | ef65cf4adc4d15ca88bab1a7136a367cb4f54504 (diff) | |
Promotion of wlan-cld3.driver.lnx.1.1-00024.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1029145 I302ad442f660feb795d7a8f1353b5d820d26aac8 qcacld-3.0: Populate extended caps coming for each phy t
1029145 I3ad9b474c281f3dd371eb2b88b71e8af59fcd66d qcacld-3.0: Derive HT and VHT caps from given per PHY ca
688141 Ib5358ac9729a133e413d2f86d11a09b1e86c7416 Release 5.1.0.13
1025390 I8b3df2259f71cf51b8ffc8b9a50edad7fea81d13 qcacld-3.0: Don't set operating channel before ROC gets
869026 I5cbf17a14ab6becad6cf5765ae5039fc284dc309 qcacld-3.0: Add support for NSS configurability
1031855 I4a08717abce2a0ecbe4055360fd8d31c3e50a701 qcacld-3.0: Sanitize SAP context before extracting the h
996988 I995ea9c391372515faabe5086b638f254b6b93d7 qcacld-3.0: Add TDLS connection tracker in WLAN host
1031855 I6f722dcc4ab671fef010c816a7c7d38fc1bdebe4 qcacld-3.0: Validate SAP context before access in callba
1016872 I55028533ebbf03910755da1b35c2fa57d97ce43b qcacld-3.0: Send disconnect event to upper layers upon d
1020291 I220d2c1909a44fd7edb46127daec1165fca71ebe qcacld-3.0: Include appropriate auth info for roaming
1017437 Ia59fa5ba326504eb54e14d44f42a335c6b835ee4 qcacld-3.0: Enhance data path related statistics
1029145 I8a3659f20414851cb394395225c301a90cd94f64 qcacld-3.0: Reset gEnableRXLDPC to mitigate hardware lim
930870 I4632c1b4770e6b2f301d67f37005585aef401ab6 qcacld-3.0: Implement cfg80211 abort scan API
1033129 I3b752c365e09f08104fa871c29e2629c1873b3fc qcacld-3.0: Send wow wake event bitmap properly to fw
Change-Id: I0b8f99f01cafa482541354bfbebf92eb823b2847
CRs-Fixed: 1025390, 1016872, 996988, 1020291, 688141, 1017437, 930870, 869026, 1031855, 1033129, 1029145
58 files changed, 3078 insertions, 310 deletions
diff --git a/config/WCNSS_qcom_cfg.ini b/config/WCNSS_qcom_cfg.ini index e0b3a3d56ea1..51a4cc7b9559 100644 --- a/config/WCNSS_qcom_cfg.ini +++ b/config/WCNSS_qcom_cfg.ini @@ -366,7 +366,7 @@ gEnableRXSTBC=1 gEnableTXSTBC=1 # 1=enable rx LDPC; 0=disable -gEnableRXLDPC=1 +gEnableRXLDPC=0 #Enable/Disable Tx beamforming gTxBFEnable=1 diff --git a/core/cds/inc/cds_concurrency.h b/core/cds/inc/cds_concurrency.h index e7132c8700da..08e4d8fe4bbf 100644 --- a/core/cds/inc/cds_concurrency.h +++ b/core/cds/inc/cds_concurrency.h @@ -554,6 +554,7 @@ struct cds_conc_connection_info { bool cds_is_connection_in_progress(void); void cds_dump_concurrency_info(void); +void cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx); void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode); void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode); uint32_t cds_get_connection_count(void); diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c index ec9360ce10fb..7fb5455f0b8b 100644 --- a/core/cds/src/cds_concurrency.c +++ b/core/cds/src/cds_concurrency.c @@ -3372,6 +3372,41 @@ void cds_dump_concurrency_info(void) } /** + * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode + * @hdd_ctx: hdd context + * + * This routine is called to set the tdls connection tracker operation status + * + * Return: NONE + */ +void cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx) +{ + bool state = false; + + /* If any concurrency is detected, skip tdls pkt tracker */ + if (((1 << QDF_STA_MODE) == hdd_ctx->concurrency_mode) && + (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] == 1) && + (hdd_ctx->config->fEnableTDLSImplicitTrigger) && + (eTDLS_SUPPORT_DISABLED != hdd_ctx->tdls_mode)) { + if (hdd_ctx->config->fTDLSExternalControl) { + if (hdd_ctx->tdls_external_peer_count) + state = true; + goto set_state; + } else { + state = true; + } + } + +set_state: + mutex_lock(&hdd_ctx->tdls_lock); + hdd_ctx->enable_tdls_connection_tracker = state; + mutex_unlock(&hdd_ctx->tdls_lock); + + cds_info("enable_tdls_connection_tracker %d", + hdd_ctx->enable_tdls_connection_tracker); +} + +/** * cds_set_concurrency_mode() - To set concurrency mode * @mode: adapter mode * @@ -3402,6 +3437,10 @@ void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode) default: break; } + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(hdd_ctx); + cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", hdd_ctx->concurrency_mode, mode, hdd_ctx->no_of_open_sessions[mode]); @@ -3438,6 +3477,10 @@ void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode) default: break; } + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(hdd_ctx); + cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", hdd_ctx->concurrency_mode, mode, hdd_ctx->no_of_open_sessions[mode]); @@ -3550,8 +3593,13 @@ void cds_incr_active_session(enum tQDF_ADAPTER_MODE mode, default: break; } + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(hdd_ctx); + cds_info("No.# of active sessions for mode %d = %d", mode, hdd_ctx->no_of_active_sessions[mode]); + /* * Get PCL logic makes use of the connection info structure. * Let us set the PCL to the FW before updating the connection @@ -3826,8 +3874,13 @@ void cds_decr_active_session(enum tQDF_ADAPTER_MODE mode, default: break; } + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(hdd_ctx); + cds_info("No.# of active sessions for mode %d = %d", mode, hdd_ctx->no_of_active_sessions[mode]); + cds_decr_connection_count(session_id); qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); } diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c index 0a1d82983175..641e2c09a65c 100644 --- a/core/dp/htt/htt_rx.c +++ b/core/dp/htt/htt_rx.c @@ -1940,7 +1940,7 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, uint8_t *rx_ind_data; uint32_t *msg_word; unsigned int msdu_count = 0; - uint8_t offload_ind; + uint8_t offload_ind, frag_ind; struct htt_host_rx_desc_base *rx_desc; uint8_t peer_id; @@ -1952,11 +1952,12 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, *(u_int32_t *)rx_ind_data); offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word); /* Get the total number of MSDUs */ msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); HTT_RX_CHECK_MSDU_COUNT(msdu_count); - ol_rx_update_histogram_stats(msdu_count); + ol_rx_update_histogram_stats(msdu_count, frag_ind, offload_ind); msg_word = (uint32_t *) (rx_ind_data + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES); diff --git a/core/dp/ol/inc/ol_txrx_stats.h b/core/dp/ol/inc/ol_txrx_stats.h index 27a49ef03c09..842924e1c861 100644 --- a/core/dp/ol/inc/ol_txrx_stats.h +++ b/core/dp/ol/inc/ol_txrx_stats.h @@ -53,6 +53,9 @@ struct ol_txrx_stats_tso_msdu { struct qdf_tso_seg_t tso_segs[NUM_MAX_TSO_SEGS]; uint8_t num_seg; uint8_t tso_seg_idx; + uint32_t total_len; + uint32_t gso_size; + uint8_t nr_frags; }; struct ol_txrx_stats_tso_info { @@ -81,6 +84,15 @@ struct ol_txrx_stats_tx_dropped { struct ol_txrx_stats_elem no_ack; }; +struct ol_txrx_tso_histogram { + uint32_t pkts_1; + uint32_t pkts_2_5; + uint32_t pkts_6_10; + uint32_t pkts_11_15; + uint32_t pkts_16_20; + uint32_t pkts_20_plus; +}; + struct ol_txrx_stats_tx_histogram { uint32_t pkts_1; uint32_t pkts_2_10; @@ -95,12 +107,15 @@ struct ol_txrx_stats_tx_tso { struct ol_txrx_stats_elem tso_pkts; #if defined(FEATURE_TSO) struct ol_txrx_stats_tso_info tso_info; + struct ol_txrx_tso_histogram tso_hist; #endif }; struct ol_txrx_stats_tx { /* MSDUs given to the txrx layer by the management stack */ struct ol_txrx_stats_elem mgmt; + /* MSDUs received from the stack */ + struct ol_txrx_stats_elem from_stack; /* MSDUs successfully sent across the WLAN */ struct ol_txrx_stats_elem delivered; struct ol_txrx_stats_tx_dropped dropped; @@ -139,6 +154,8 @@ struct ol_txrx_stats_rx { struct ol_txrx_stats_elem dropped_peer_invalid; struct ol_txrx_stats_rx_ibss_fwd intra_bss_fwd; struct ol_txrx_stats_rx_histogram rx_ind_histogram; + uint32_t msdus_with_frag_ind; + uint32_t msdus_with_offload_ind; }; struct ol_txrx_stats { struct ol_txrx_stats_tx tx; diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c index 52b894a49a53..db52497615f8 100644 --- a/core/dp/txrx/ol_rx.c +++ b/core/dp/txrx/ol_rx.c @@ -104,10 +104,13 @@ void ol_rx_trigger_restore(htt_pdev_handle htt_pdev, qdf_nbuf_t head_msdu, /** * ol_rx_update_histogram_stats() - update rx histogram statistics * @msdu_count: msdu count + * @frag_ind: fragment indication set + * @offload_ind: offload indication set * * Return: none */ -void ol_rx_update_histogram_stats(uint32_t msdu_count) +void ol_rx_update_histogram_stats(uint32_t msdu_count, uint8_t frag_ind, + uint8_t offload_ind) { struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); @@ -134,6 +137,13 @@ void ol_rx_update_histogram_stats(uint32_t msdu_count) } else if (msdu_count == 1) { TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_1, 1); } + + if (frag_ind) + TXRX_STATS_ADD(pdev, pub.rx.msdus_with_frag_ind, msdu_count); + + if (offload_ind) + TXRX_STATS_ADD(pdev, pub.rx.msdus_with_offload_ind, msdu_count); + } static void ol_rx_process_inv_peer(ol_txrx_pdev_handle pdev, diff --git a/core/dp/txrx/ol_rx.h b/core/dp/txrx/ol_rx.h index 5c6045e1ff8f..786f94e2feaf 100644 --- a/core/dp/txrx/ol_rx.h +++ b/core/dp/txrx/ol_rx.h @@ -58,7 +58,8 @@ void ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, uint32_t msdu_count, uint32_t *msg_word); -void ol_rx_update_histogram_stats(uint32_t msdu_count); +void ol_rx_update_histogram_stats(uint32_t msdu_count, + uint8_t frag_ind, uint8_t offload_ind); void ol_rx_mic_error_handler( diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c index c2c79fb0b232..40374f043050 100644 --- a/core/dp/txrx/ol_tx.c +++ b/core/dp/txrx/ol_tx.c @@ -247,6 +247,14 @@ qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) } segments = msdu_info.tso_info.num_segs; + TXRX_STATS_TSO_HISTOGRAM(vdev->pdev, segments); + TXRX_STATS_TSO_GSO_SIZE_UPDATE(vdev->pdev, + qdf_nbuf_tcp_tso_size(msdu)); + TXRX_STATS_TSO_TOTAL_LEN_UPDATE(vdev->pdev, + qdf_nbuf_len(msdu)); + TXRX_STATS_TSO_NUM_FRAGS_UPDATE(vdev->pdev, + qdf_nbuf_get_nr_frags(msdu)); + /* * The netbuf may get linked into a different list inside the @@ -275,6 +283,8 @@ qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu); + /* * If debug display is enabled, show the meta-data being * downloaded to the target via the HTT tx descriptor. @@ -328,6 +338,8 @@ qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) msdu_info.peer = NULL; ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu); + /* * If debug display is enabled, show the meta-data being * downloaded to the target via the HTT tx descriptor. @@ -531,6 +543,13 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) } segments = msdu_info.tso_info.num_segs; + TXRX_STATS_TSO_HISTOGRAM(vdev->pdev, segments); + TXRX_STATS_TSO_GSO_SIZE_UPDATE(vdev->pdev, + qdf_nbuf_tcp_tso_size(msdu)); + TXRX_STATS_TSO_TOTAL_LEN_UPDATE(vdev->pdev, + qdf_nbuf_len(msdu)); + TXRX_STATS_TSO_NUM_FRAGS_UPDATE(vdev->pdev, + qdf_nbuf_get_nr_frags(msdu)); /* * The netbuf may get linked into a different list @@ -580,6 +599,8 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) pkt_download_len, ep_id, &msdu_info); + TXRX_STATS_MSDU_INCR(pdev, tx.from_stack, msdu); + if (qdf_likely(tx_desc)) { DPTRACE(qdf_dp_trace_ptr(msdu, QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, @@ -684,6 +705,8 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) pkt_download_len, ep_id, &msdu_info); + TXRX_STATS_MSDU_INCR(pdev, tx.from_stack, msdu); + if (qdf_likely(tx_desc)) { DPTRACE(qdf_dp_trace_ptr(msdu, QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 04d18c49da80..8da961622a9b 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/core/dp/txrx/ol_tx_desc.c @@ -236,8 +236,8 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, ol_tx_desc_sanity_checks(pdev, tx_desc); ol_tx_desc_compute_delay(tx_desc); } else { + pool->pkt_drop_no_desc++; qdf_spin_unlock_bh(&pool->flow_pool_lock); - pdev->pool_stats.pkt_drop_no_desc++; } } else { pdev->pool_stats.pkt_drop_no_pool++; diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 09cffd3d559a..fcd1831a99ec 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -3521,16 +3521,41 @@ void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) int seg_idx; QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "TSO pkts %lld, bytes %lld\n", pdev->stats.pub.tx.tso.tso_pkts.pkts, pdev->stats.pub.tx.tso.tso_pkts.bytes); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO Histogram for numbers of segments:\n" + "Single segment %d\n" + " 2-5 segments %d\n" + " 6-10 segments %d\n" + "11-15 segments %d\n" + "16-20 segments %d\n" + " 20+ segments %d\n", + pdev->stats.pub.tx.tso.tso_hist.pkts_1, + pdev->stats.pub.tx.tso.tso_hist.pkts_2_5, + pdev->stats.pub.tx.tso.tso_hist.pkts_6_10, + pdev->stats.pub.tx.tso.tso_hist.pkts_11_15, + pdev->stats.pub.tx.tso.tso_hist.pkts_16_20, + pdev->stats.pub.tx.tso.tso_hist.pkts_20_plus); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO History Buffer: Total size %d, current_index %d", + NUM_MAX_TSO_MSDUS, + TXRX_STATS_TSO_MSDU_IDX(pdev)); + for (msdu_idx = 0; msdu_idx < NUM_MAX_TSO_MSDUS; msdu_idx++) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "curr msdu idx: %d curr seg idx: %d num segs %d\n", - TXRX_STATS_TSO_MSDU_IDX(pdev), - TXRX_STATS_TSO_SEG_IDX(pdev), - TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx)); + "jumbo pkt idx: %d num segs %d gso_len %d total_len %d nr_frags %d", + msdu_idx, + TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, msdu_idx)); + for (seg_idx = 0; ((seg_idx < TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx)) && (seg_idx < NUM_MAX_TSO_SEGS)); @@ -3539,24 +3564,23 @@ void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "msdu idx: %d seg idx: %d\n", - msdu_idx, seg_idx); + "seg idx: %d", seg_idx); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "tso_enable: %d\n", + "tso_enable: %d", tso_seg.tso_flags.tso_enable); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "fin %d syn %d rst %d psh %d ack %d\n" - "urg %d ece %d cwr %d ns %d\n", + "fin %d syn %d rst %d psh %d ack %d urg %d ece %d cwr %d ns %d", tso_seg.tso_flags.fin, tso_seg.tso_flags.syn, tso_seg.tso_flags.rst, tso_seg.tso_flags.psh, tso_seg.tso_flags.ack, tso_seg.tso_flags.urg, tso_seg.tso_flags.ece, tso_seg.tso_flags.cwr, tso_seg.tso_flags.ns); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "tcp_seq_num: 0x%x ip_id: %d\n", + "tcp_seq_num: 0x%x ip_id: %d", tso_seg.tso_flags.tcp_seq_num, tso_seg.tso_flags.ip_id); } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "\n"); } } #else @@ -3605,9 +3629,9 @@ void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "TX PATH Statistics:"); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "sent %lld msdus (%lld B), rejected %lld (%lld B), dropped %lld (%lld B)", - pdev->stats.pub.tx.delivered.pkts, - pdev->stats.pub.tx.delivered.bytes, + "sent %lld msdus (%lld B), host rejected %lld (%lld B), dropped %lld (%lld B)", + pdev->stats.pub.tx.from_stack.pkts, + pdev->stats.pub.tx.from_stack.bytes, pdev->stats.pub.tx.dropped.host_reject.pkts, pdev->stats.pub.tx.dropped.host_reject.bytes, pdev->stats.pub.tx.dropped.download_fail.pkts @@ -3617,9 +3641,12 @@ void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) + pdev->stats.pub.tx.dropped.target_discard.bytes + pdev->stats.pub.tx.dropped.no_ack.bytes); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - " download fail: %lld (%lld B), " + "successfully delivered: %lld (%lld B), " + "download fail: %lld (%lld B), " "target discard: %lld (%lld B), " "no ack: %lld (%lld B)", + pdev->stats.pub.tx.delivered.pkts, + pdev->stats.pub.tx.delivered.bytes, pdev->stats.pub.tx.dropped.download_fail.pkts, pdev->stats.pub.tx.dropped.download_fail.bytes, pdev->stats.pub.tx.dropped.target_discard.pkts, @@ -3627,7 +3654,7 @@ void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) pdev->stats.pub.tx.dropped.no_ack.pkts, pdev->stats.pub.tx.dropped.no_ack.bytes); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Tx completion per interrupt:\n" + "Tx completions per HTT message:\n" "Single Packet %d\n" " 2-10 Packets %d\n" "11-20 Packets %d\n" @@ -3644,11 +3671,13 @@ void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) pdev->stats.pub.tx.comp_histogram.pkts_41_50, pdev->stats.pub.tx.comp_histogram.pkts_51_60, pdev->stats.pub.tx.comp_histogram.pkts_61_plus); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "RX PATH Statistics:"); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "%lld ppdus, %lld mpdus, %lld msdus, %lld bytes\n" - "dropped: err %lld (%lld B), peer_invalid %lld (%lld B), mic_err %lld (%lld B)", + "dropped: err %lld (%lld B), peer_invalid %lld (%lld B), mic_err %lld (%lld B)\n" + "msdus with frag_ind: %d msdus with offload_ind: %d", pdev->stats.priv.rx.normal.ppdus, pdev->stats.priv.rx.normal.mpdus, pdev->stats.pub.rx.delivered.pkts, @@ -3658,8 +3687,9 @@ void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) pdev->stats.pub.rx.dropped_peer_invalid.pkts, pdev->stats.pub.rx.dropped_peer_invalid.bytes, pdev->stats.pub.rx.dropped_mic_err.pkts, - pdev->stats.pub.rx.dropped_mic_err.bytes); - + pdev->stats.pub.rx.dropped_mic_err.bytes, + pdev->stats.pub.rx.msdus_with_frag_ind, + pdev->stats.pub.rx.msdus_with_offload_ind); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, " fwd to stack %d, fwd to fw %d, fwd to stack & fw %d\n", @@ -3668,7 +3698,7 @@ void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) pdev->stats.pub.rx.intra_bss_fwd.packets_stack_n_fwd); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "rx packets per HTT indication:\n" + "Rx packets per HTT message:\n" "Single Packet %d\n" " 2-10 Packets %d\n" "11-20 Packets %d\n" @@ -4086,6 +4116,36 @@ void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev) } #endif /* IPA_UC_OFFLOAD */ +/** + * ol_txrx_display_stats_help() - print statistics help + * + * Return: none + */ +static void ol_txrx_display_stats_help(void) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "iwpriv wlan0 dumpStats [option] - dump statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "iwpriv wlan0 clearStats [option] - clear statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "options:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 1 -- TXRX Layer statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 2 -- Bandwidth compute timer stats"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 3 -- TSO statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 4 -- Network queue statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 5 -- Flow control statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 6 -- Per Layer statistics"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 7 -- Copy engine interrupt statistics"); + +} + void ol_txrx_display_stats(uint16_t value) { ol_txrx_pdev_handle pdev; @@ -4131,8 +4191,7 @@ void ol_txrx_display_stats(uint16_t value) #endif #endif default: - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Unknown value", __func__); + ol_txrx_display_stats_help(); break; } } @@ -4175,8 +4234,7 @@ void ol_txrx_clear_stats(uint16_t value) break; #endif default: - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Unknown value", __func__); + ol_txrx_display_stats_help(); break; } } diff --git a/core/dp/txrx/ol_txrx_flow_control.c b/core/dp/txrx/ol_txrx_flow_control.c index 920f825f1ef5..fff6b114bfb1 100644 --- a/core/dp/txrx/ol_txrx_flow_control.c +++ b/core/dp/txrx/ol_txrx_flow_control.c @@ -156,22 +156,18 @@ void ol_tx_dump_flow_pool_info(void) struct ol_tx_flow_pool_t tmp_pool; - TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Global Pool\n"); - TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Total %d :: Available %d\n", + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Global Pool"); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Total %d :: Available %d", pdev->tx_desc.pool_size, pdev->tx_desc.num_free); - TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid flow_pool %d\n", + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid flow_pool %d", pdev->tx_desc.num_invalid_bin); - - TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool map received %d\n", + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool map received %d", pdev->pool_stats.pool_map_count); - TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool unmap received %d\n", + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool unmap received %d", pdev->pool_stats.pool_unmap_count); TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "Pkt dropped due to unavailablity of pool %d\n", + "Pkt dropped due to unavailablity of pool %d", pdev->pool_stats.pkt_drop_no_pool); - TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "Pkt dropped due to unavailablity of descriptors %d\n", - pdev->pool_stats.pkt_drop_no_desc); /* * Nested spin lock. @@ -185,19 +181,23 @@ void ol_tx_dump_flow_pool_info(void) qdf_mem_copy(&tmp_pool, pool, sizeof(tmp_pool)); qdf_spin_unlock_bh(&pool->flow_pool_lock); qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "\n"); TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "Flow_pool_id %d :: status %d\n", + "Flow_pool_id %d :: status %d", tmp_pool.flow_pool_id, tmp_pool.status); TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "Total %d :: Available %d :: Deficient %d\n", + "Total %d :: Available %d :: Deficient %d", tmp_pool.flow_pool_size, tmp_pool.avail_desc, tmp_pool.deficient_desc); TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "Start_TH %d :: Stop_TH %d\n", + "Start threshold %d :: Stop threshold %d", tmp_pool.start_th, tmp_pool.stop_th); TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "Member flow_id %d :: flow_type %d\n", + "Member flow_id %d :: flow_type %d", tmp_pool.member_flow_id, tmp_pool.flow_type); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Pkt dropped due to unavailablity of descriptors %d", + tmp_pool.pkt_drop_no_desc); qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); } qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); diff --git a/core/dp/txrx/ol_txrx_internal.h b/core/dp/txrx/ol_txrx_internal.h index e84632201042..cb7368124328 100644 --- a/core/dp/txrx/ol_txrx_internal.h +++ b/core/dp/txrx/ol_txrx_internal.h @@ -689,6 +689,28 @@ NOT_IP_TCP: #endif #if defined(FEATURE_TSO_DEBUG) +#define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) \ + do { \ + if (_p_cntrs == 1) { \ + TXRX_STATS_ADD(_pdev, pub.tx.tso.tso_hist.pkts_1, 1); \ + } else if (_p_cntrs > 2 && _p_cntrs <= 5) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_2_5, 1); \ + } else if (_p_cntrs > 5 && _p_cntrs <= 10) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_6_10, 1); \ + } else if (_p_cntrs > 10 && _p_cntrs <= 15) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_11_15, 1); \ + } else if (_p_cntrs > 15 && _p_cntrs <= 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_16_20, 1); \ + } else if (_p_cntrs > 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_20_plus, 1); \ + } \ + } while (0) + #define TXRX_STATS_TSO_RESET_MSDU(pdev) \ do { \ int idx = TXRX_STATS_TSO_MSDU_IDX(pdev);\ @@ -705,6 +727,15 @@ NOT_IP_TCP: #define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) \ pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg +#define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].gso_size + +#define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].total_len + +#define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].nr_frags + #define TXRX_STATS_TSO_CURR_MSDU(pdev) \ TXRX_STATS_TSO_MSDU(pdev, TXRX_STATS_TSO_MSDU_IDX(pdev)) @@ -718,7 +749,11 @@ NOT_IP_TCP: TXRX_STATS_TSO_CURR_MSDU(pdev).tso_seg_idx #define TXRX_STATS_TSO_INC_SEG(pdev) \ - TXRX_STATS_TSO_CURR_MSDU(pdev).num_seg++ + do { \ + TXRX_STATS_TSO_CURR_MSDU(pdev).num_seg++; \ + TXRX_STATS_TSO_CURR_MSDU(pdev).num_seg &= \ + NUM_MAX_TSO_SEGS_MASK; \ + } while (0) #define TXRX_STATS_TSO_RST_SEG(pdev) \ TXRX_STATS_TSO_CURR_MSDU(pdev).num_seg = 0 @@ -742,7 +777,17 @@ NOT_IP_TCP: #define TXRX_STATS_TSO_SEG_UPDATE(pdev, tso_seg) \ (TXRX_STATS_TSO_CURR_SEG(pdev) = tso_seg) +#define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, size) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev).gso_size = size) + +#define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, len) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev).total_len = len) + +#define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, frags) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev).nr_frags = frags) + #else +#define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) /* no-op */ #define TXRX_STATS_TSO_RESET_MSDU(pdev) /* no-op */ #define TXRX_STATS_TSO_MSDU_IDX(pdev) /* no-op */ #define TXRX_STATS_TSO_MSDU(pdev, idx) /* no-op */ @@ -757,6 +802,12 @@ NOT_IP_TCP: #define TXRX_STATS_TSO_INC_SEG(pdev) /* no-op */ #define TXRX_STATS_TSO_RST_SEG(pdev) /* no-op */ #define TXRX_STATS_TSO_RST_SEG_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, size) /* no-op */ +#define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, len) /* no-op */ +#define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, frags) /* no-op */ +#define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) /* no-op */ #endif /* FEATURE_TSO_DEBUG */ diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index 25cdcff4a80f..bc219d2e05d4 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -443,13 +443,11 @@ enum flow_pool_status { * @pool_map_count: flow pool map received * @pool_unmap_count: flow pool unmap received * @pkt_drop_no_pool: packets dropped due to unavailablity of pool - * @pkt_drop_no_desc: packets dropped due to unavailablity of descriptors */ struct ol_txrx_pool_stats { uint16_t pool_map_count; uint16_t pool_unmap_count; uint16_t pkt_drop_no_pool; - uint16_t pkt_drop_no_desc; }; /** @@ -466,6 +464,7 @@ struct ol_txrx_pool_stats { * @stop_th: stop threshold * @start_th: start threshold * @freelist: tx descriptor freelist + * @pkt_drop_no_desc: drop due to no descriptors */ struct ol_tx_flow_pool_t { TAILQ_ENTRY(ol_tx_flow_pool_t) flow_pool_list_elem; @@ -480,6 +479,7 @@ struct ol_tx_flow_pool_t { uint16_t stop_th; uint16_t start_th; union ol_tx_desc_list_elem_t *freelist; + uint16_t pkt_drop_no_desc; }; #endif diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index f0212b7476d3..367d702cd845 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -1119,6 +1119,27 @@ typedef enum { #define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX (1) #define CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT (0) +/* + * NSS cfg bit definition. + * STA BIT[0:1] + * SAP BIT[2:3] + * P2P_GO BIT[4:5] + * P2P_CLIENT BIT[6:7] + * IBSS BIT[8:9] + * TDLS BIT[10:11] + * P2P_DEVICE BIT[12:13] + * OCB BIT[14:15] + */ +#define CFG_VDEV_TYPE_NSS_2G "gVdevTypeNss_2g" +#define CFG_VDEV_TYPE_NSS_2G_MIN (0x5555) +#define CFG_VDEV_TYPE_NSS_2G_MAX (0xAAAA) +#define CFG_VDEV_TYPE_NSS_2G_DEFAULT (0xAAAA) + +#define CFG_VDEV_TYPE_NSS_5G "gVdevTypeNss_5g" +#define CFG_VDEV_TYPE_NSS_5G_MIN (0x5555) +#define CFG_VDEV_TYPE_NSS_5G_MAX (0xAAAA) +#define CFG_VDEV_TYPE_NSS_5G_DEFAULT (0xAAAA) + #define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE "gEnableMuBformee" #define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN (0) #define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX (1) @@ -3681,6 +3702,8 @@ struct hdd_config { uint8_t vhtRxMCS2x2; uint8_t vhtTxMCS2x2; bool enable2x2; + uint32_t vdev_type_nss_2g; + uint32_t vdev_type_nss_5g; bool txchainmask1x1; bool rxchainmask1x1; bool enableMuBformee; diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index aebcf8c3d769..c4df74ab4d6a 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -319,12 +319,6 @@ extern spinlock_t hdd_context_lock; #define WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 100 #define WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH 14 -#define HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 -#define HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 -#define HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 -#define HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 - - #define NUM_TX_RX_HISTOGRAM 1024 #define NUM_TX_RX_HISTOGRAM_MASK (NUM_TX_RX_HISTOGRAM - 1) @@ -805,6 +799,7 @@ typedef struct multicast_addr_list { struct hdd_netif_queue_stats { uint16_t pause_count; uint16_t unpause_count; + qdf_time_t total_pause_time; }; /** @@ -1257,10 +1252,13 @@ struct hdd_context_s { uint16_t connected_peer_count; tdls_scan_context_t tdls_scan_ctxt; /* Lock to avoid race condition during TDLS operations */ + qdf_spinlock_t tdls_ct_spinlock; struct mutex tdls_lock; uint8_t tdls_off_channel; uint16_t tdls_channel_offset; int32_t tdls_fw_off_chan_mode; + bool enable_tdls_connection_tracker; + uint8_t tdls_external_peer_count; #endif void *hdd_ipa; diff --git a/core/hdd/inc/wlan_hdd_tdls.h b/core/hdd/inc/wlan_hdd_tdls.h index 2d446b4fe504..7b770ac9e37a 100644 --- a/core/hdd/inc/wlan_hdd_tdls.h +++ b/core/hdd/inc/wlan_hdd_tdls.h @@ -63,8 +63,12 @@ #define TDLS_PEER_LIST_SIZE 256 +#define TDLS_CT_MAC_AGE_OUT_TIME (30*60*1000) /* Age out time is 30 mins */ + #define EXTTDLS_EVENT_BUF_SIZE (4096) +#define TDLS_CT_MAC_MAX_TABLE_SIZE 8 + /** * struct tdls_config_params_t - tdls config params * @@ -72,6 +76,7 @@ * @tx_period_t: tx period * @tx_packet_n: tx packets number * @discovery_tries_n: discovery tries + * @idle_timeout_t: idle traffic time out value * @idle_packet_n: idle packet number * @rssi_trigger_threshold: rssi trigger threshold * @rssi_teardown_threshold: rssi tear down threshold @@ -82,6 +87,7 @@ typedef struct { uint32_t tx_period_t; uint32_t tx_packet_n; uint32_t discovery_tries_n; + uint32_t idle_timeout_t; uint32_t idle_packet_n; int32_t rssi_trigger_threshold; int32_t rssi_teardown_threshold; @@ -286,10 +292,24 @@ typedef struct { struct _hddTdlsPeer_t; /** + * struct tdls_ct_mac_table - connection tracker peer mac address table + * @mac_address: peer mac address + * @tx_packet_cnt: number of tx pkts + * @rx_packet_cnt: number of rx pkts + * @peer_timestamp_ms: time stamp of latest peer traffic + */ +struct tdls_ct_mac_table { + struct qdf_mac_addr mac_address; + uint32_t tx_packet_cnt; + uint32_t rx_packet_cnt; + uint32_t peer_timestamp_ms; +}; +/** * struct tdlsCtx_t - tdls context * * @peer_list: peer list * @pAdapter: pointer to adapter + * @peer_update_timer: connection tracker timer * @peerDiscoverTimer: peer discovery timer * @peerDiscoveryTimeoutTimer: peer discovery timeout timer * @threshold_config: threshold config @@ -298,12 +318,15 @@ struct _hddTdlsPeer_t; * @ap_rssi: ap rssi * @curr_candidate: current candidate * @implicit_setup: implicit setup work queue + * @ct_peer_mac_table: linear mac address table for counting the packets + * @valid_mac_entries: number of valid mac entry in @ct_peer_mac_table * @magic: magic * */ typedef struct { struct list_head peer_list[TDLS_PEER_LIST_SIZE]; hdd_adapter_t *pAdapter; + qdf_mc_timer_t peer_update_timer; qdf_mc_timer_t peerDiscoveryTimeoutTimer; tdls_config_params_t threshold_config; int32_t discovery_peer_cnt; @@ -311,6 +334,8 @@ typedef struct { int8_t ap_rssi; struct _hddTdlsPeer_t *curr_candidate; struct work_struct implicit_setup; + struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE]; + uint8_t valid_mac_entries; uint32_t magic; } tdlsCtx_t; @@ -342,6 +367,8 @@ typedef struct { * @op_class_for_pref_off_chan: op class for preferred off channel * @pref_off_chan_num: preferred off channel number * @op_class_for_pref_off_chan_is_set: op class for preferred off channel set + * @peer_idle_timer: time to check idle traffic in tdls peers + * @is_peer_idle_timer_initialised: Flag to check idle timer init * @reason: reason * @state_change_notification: state change notification */ @@ -371,6 +398,8 @@ typedef struct _hddTdlsPeer_t { uint8_t op_class_for_pref_off_chan; uint8_t pref_off_chan_num; uint8_t op_class_for_pref_off_chan_is_set; + qdf_mc_timer_t peer_idle_timer; + bool is_peer_idle_timer_initialised; tTDLSLinkReason reason; cfg80211_exttdls_callback state_change_notification; } hddTdlsPeer_t; @@ -451,14 +480,16 @@ int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter, tCsrTdlsLinkEstablishParams * tdlsLinkEstablishParams); hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, - const uint8_t *mac); + const uint8_t *mac, + bool need_mutex_lock); int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, tTDLSCapType cap); void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, tTDLSLinkStatus status, - tTDLSLinkReason reason); + tTDLSLinkReason reason, + bool lock_needed); void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, const uint8_t *mac, tTDLSLinkStatus linkStatus, @@ -503,7 +534,8 @@ void wlan_hdd_tdls_tncrement_peer_count(hdd_adapter_t *pAdapter); void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter); hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, - const uint8_t *mac, uint8_t skip_self); + const uint8_t *mac, uint8_t skip_self, + bool need_lock); int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, struct wiphy *wiphy, @@ -630,10 +662,13 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter); int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel); int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset); int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode); +void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb); +void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb); int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val); void hdd_tdls_context_init(hdd_context_t *hdd_ctx); void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx); - #else static inline void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter, hdd_context_t *hddctx) @@ -646,7 +681,14 @@ wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) static inline void wlan_hdd_tdls_exit(hdd_adapter_t *adapter) { } - +static inline void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ +} +static inline void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ +} static inline void hdd_tdls_context_init(hdd_context_t *hdd_ctx) { } static inline void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx) { } #endif /* End of FEATURE_WLAN_TDLS */ diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 85debbd99df0..28a98c5db86e 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -1066,7 +1066,7 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, /* HDD has initiated disconnect, do not send disconnect indication * to kernel. Sending disconnected event to kernel for userspace - * initiated disconnect will be handled by hdd_DisConnectHandler call + * initiated disconnect will be handled by disconnect handler call * to cfg80211_disconnected. */ if ((eConnectionState_Disconnecting == @@ -1104,19 +1104,14 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, if (pRoamInfo->reasonCode == eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON) pr_info("wlan: disconnected due to poor signal, rssi is %d dB\n", pRoamInfo->rxRssi); - cfg80211_disconnected(dev, pRoamInfo-> - reasonCode, NULL, 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || defined(WITH_BACKPORTS) - true, -#endif - GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect( + dev, false, + pRoamInfo->reasonCode); } else { - cfg80211_disconnected(dev, - WLAN_REASON_UNSPECIFIED, NULL, 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || defined(WITH_BACKPORTS) - true, -#endif - GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect( + dev, false, + WLAN_REASON_UNSPECIFIED + ); } hdd_info("sent disconnected event to nl80211, rssi: %d", @@ -3315,7 +3310,8 @@ hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter, curr_peer = wlan_hdd_tdls_get_peer(pAdapter, - pRoamInfo->peerMac.bytes); + pRoamInfo->peerMac.bytes, + true); if (!curr_peer) { hddLog(LOGE, FL("curr_peer is null")); status = QDF_STATUS_E_FAILURE; diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index 137a719c1548..af43bf1f7df7 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -2094,6 +2094,20 @@ REG_TABLE_ENTRY g_registry_table[] = { CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN, CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX), + REG_VARIABLE(CFG_VDEV_TYPE_NSS_2G, WLAN_PARAM_Integer, + struct hdd_config, vdev_type_nss_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VDEV_TYPE_NSS_2G_DEFAULT, + CFG_VDEV_TYPE_NSS_2G_MIN, + CFG_VDEV_TYPE_NSS_2G_MAX), + + REG_VARIABLE(CFG_VDEV_TYPE_NSS_5G, WLAN_PARAM_Integer, + struct hdd_config, vdev_type_nss_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VDEV_TYPE_NSS_5G_DEFAULT, + CFG_VDEV_TYPE_NSS_5G_MIN, + CFG_VDEV_TYPE_NSS_5G_MAX), + REG_VARIABLE(CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, struct hdd_config, enableMuBformee, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, @@ -6478,48 +6492,6 @@ bool hdd_update_config_dat(hdd_context_t *pHddCtx) if ((pConfig->dot11Mode == eHDD_DOT11_MODE_AUTO) || (pConfig->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) || (pConfig->dot11Mode == eHDD_DOT11_MODE_11ac)) { - uint32_t temp = 0; - - sme_cfg_get_int(pHddCtx->hHal, - WNI_CFG_VHT_BASIC_MCS_SET, &temp); - temp = (temp & 0xFFFC) | pConfig->vhtRxMCS; - if (pConfig->enable2x2) - temp = (temp & 0xFFF3) | (pConfig->vhtRxMCS2x2 << 2); - if (sme_cfg_set_int(pHddCtx->hHal, - WNI_CFG_VHT_BASIC_MCS_SET, temp) == - QDF_STATUS_E_FAILURE) { - fStatus = false; - hddLog(LOGE, - "Could not pass on WNI_CFG_VHT_BASIC_MCS_SET to CFG"); - } - - sme_cfg_get_int(pHddCtx->hHal, WNI_CFG_VHT_RX_MCS_MAP, - &temp); - temp = (temp & 0xFFFC) | pConfig->vhtRxMCS; - if (pConfig->enable2x2) - temp = (temp & 0xFFF3) | (pConfig->vhtRxMCS2x2 << 2); - if (sme_cfg_set_int(pHddCtx->hHal, - WNI_CFG_VHT_RX_MCS_MAP, temp) - == QDF_STATUS_E_FAILURE) { - fStatus = false; - hddLog(LOGE, - "Could not pass on WNI_CFG_VHT_RX_MCS_MAP to CFG"); - } - sme_cfg_get_int(pHddCtx->hHal, WNI_CFG_VHT_TX_MCS_MAP, &temp); - temp = (temp & 0xFFFC) | pConfig->vhtTxMCS; - if (pConfig->enable2x2) - temp = (temp & 0xFFF3) | (pConfig->vhtTxMCS2x2 << 2); - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH, - "vhtRxMCS2x2 - %x temp - %u enable2x2 %d", - pConfig->vhtRxMCS2x2, temp, - pConfig->enable2x2); - - if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_TX_MCS_MAP, - temp) == QDF_STATUS_E_FAILURE) { - fStatus = false; - hddLog(LOGE, - "Could not pass on WNI_CFG_VHT_TX_MCS_MAP to CFG"); - } /* Currently shortGI40Mhz is used for shortGI80Mhz */ if (sme_cfg_set_int (pHddCtx->hHal, WNI_CFG_VHT_SHORT_GI_80MHZ, @@ -6542,9 +6514,9 @@ bool hdd_update_config_dat(hdd_context_t *pHddCtx) /* Change MU Bformee only when TxBF is enabled */ if (pConfig->enableTxBF) { sme_cfg_get_int(pHddCtx->hHal, - WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &temp); + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &val); - if (temp != pConfig->enableMuBformee) { + if (val != pConfig->enableMuBformee) { if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_MU_BEAMFORMEE_CAP, pConfig->enableMuBformee @@ -7299,12 +7271,12 @@ QDF_STATUS hdd_update_nss(hdd_context_t *hdd_ctx, uint8_t nss) if (!hdd_config->enable2x2) { /* 1x1 */ - rx_supp_data_rate = HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; - tx_supp_data_rate = HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; } else { /* 2x2 */ - rx_supp_data_rate = HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; - tx_supp_data_rate = HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; } /* Update Rx Highest Long GI data Rate */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index fd05af138484..5f695e28a98a 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -4484,6 +4484,9 @@ static int __wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, return -EINVAL; } + if (0 != wlan_hdd_check_remain_on_channel(adapter)) + hdd_warn("Remain On Channel Pending"); + if (hdd_ctx->config->policy_manager_enabled) { ret = qdf_reset_connection_update(); if (!QDF_IS_STATUS_SUCCESS(ret)) @@ -9896,11 +9899,8 @@ disconnected: * is handled by __cfg80211_disconnect call to __cfg80211_disconnected */ hddLog(LOG1, FL("Send disconnected event to userspace")); - cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED, NULL, 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || defined(WITH_BACKPORTS) - false, -#endif - GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect(pAdapter->dev, true, + WLAN_REASON_UNSPECIFIED); #endif return result; @@ -12361,4 +12361,8 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = { .channel_switch = wlan_hdd_cfg80211_channel_switch, #endif .set_monitor_channel = wlan_hdd_cfg80211_set_mon_ch, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) + .abort_scan = wlan_hdd_cfg80211_abort_scan, +#endif }; diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index c91fa417f92c..a3ab7485feb7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -2551,4 +2551,23 @@ int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, void hdd_get_bpf_offload_cb(void *hdd_context, struct sir_bpf_get_offload *); void hdd_init_bpf_completion(void); + +#if defined(CFG80211_DISCONNECTED_V2) || \ +(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + locally_generated, GFP_KERNEL); +} +#else +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + GFP_KERNEL); +} +#endif #endif diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index bd2cda48baae..00b8365073ca 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -2202,6 +2202,10 @@ static int __iw_softap_set_two_ints_getnone(struct net_device *dev, value[1], value[2]); if (value[1] == DUMP_DP_TRACE) qdf_dp_trace_dump_all(value[2]); + else if (value[1] == ENABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_enable_live_mode(); + else if (value[1] == CLEAR_DP_TRACE_BUFFER) + qdf_dp_trace_clear_buffer(); break; case QCSAP_ENABLE_FW_PROFILE: hddLog(LOG1, "QCSAP_ENABLE_FW_PROFILE: %d %d", diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index c1ae84d90920..a9245e006903 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -816,6 +816,29 @@ static void hdd_update_tgt_services(hdd_context_t *hdd_ctx, } +/** + * hdd_update_vdev_nss() - sets the vdev nss + * @hdd_ctx: HDD context + * + * Sets the Nss per vdev type based on INI + * + * Return: None + */ +static void hdd_update_vdev_nss(hdd_context_t *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + uint8_t max_supp_nss = 1; + + if (cfg_ini->enable2x2) + max_supp_nss = 2; + + sme_update_vdev_type_nss(hdd_ctx->hHal, max_supp_nss, + cfg_ini->vdev_type_nss_2g, eCSR_BAND_24); + + sme_update_vdev_type_nss(hdd_ctx->hHal, max_supp_nss, + cfg_ini->vdev_type_nss_5g, eCSR_BAND_5G); +} + static void hdd_update_tgt_ht_cap(hdd_context_t *hdd_ctx, struct wma_tgt_ht_cap *cfg) { @@ -888,7 +911,7 @@ static void hdd_update_tgt_ht_cap(hdd_context_t *hdd_ctx, /* Update Rx Highest Long GI data Rate */ if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, - HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1) + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1) == QDF_STATUS_E_FAILURE) { hddLog(LOGE, FL( @@ -900,12 +923,11 @@ static void hdd_update_tgt_ht_cap(hdd_context_t *hdd_ctx, if (sme_cfg_set_int (hdd_ctx->hHal, WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, - HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1) == + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1) == QDF_STATUS_E_FAILURE) { hddLog(LOGE, FL( - "Could not pass on HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 to CCM" - )); + "VHT_TX_HIGHEST_SUPP_RATE_1_1 to CCM fail")); } } if (!(cfg->ht_tx_stbc && pconfig->enable2x2)) @@ -950,6 +972,7 @@ static void hdd_update_tgt_vht_cap(hdd_context_t *hdd_ctx, struct wiphy *wiphy = hdd_ctx->wiphy; struct ieee80211_supported_band *band_5g = wiphy->bands[IEEE80211_BAND_5GHZ]; + uint32_t temp = 0; /* Get the current MPDU length */ status = @@ -988,9 +1011,41 @@ static void hdd_update_tgt_vht_cap(hdd_context_t *hdd_ctx, value = 0; } + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtRxMCS; + + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtRxMCS2x2 << 2); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass VHT_BASIC_MCS_SET to CCM"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtRxMCS; + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtRxMCS2x2 << 2); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass WNI_CFG_VHT_RX_MCS_MAP to CCM"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtTxMCS; + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtTxMCS2x2 << 2); + + hdd_info("vhtRxMCS2x2 - %x temp - %u enable2x2 %d", + pconfig->vhtRxMCS2x2, temp, pconfig->enable2x2); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass WNI_CFG_VHT_TX_MCS_MAP to CCM"); + } /* Get the current RX LDPC setting */ - status = - sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, &value); if (status != QDF_STATUS_SUCCESS) { @@ -1319,6 +1374,8 @@ void hdd_update_tgt_cfg(void *context, void *param) hdd_ctx->ap_arpns_support = cfg->ap_arpns_support; hdd_update_tgt_services(hdd_ctx, &cfg->services); + hdd_update_vdev_nss(hdd_ctx); + hdd_update_tgt_ht_cap(hdd_ctx, &cfg->ht_cap); hdd_update_tgt_vht_cap(hdd_ctx, &cfg->vht_cap); @@ -2164,6 +2221,7 @@ QDF_STATUS hdd_init_station_mode(hdd_adapter_t *adapter) INIT_COMPLETION(adapter->session_open_comp_var); sme_set_curr_device_mode(hdd_ctx->hHal, adapter->device_mode); + sme_set_pdev_ht_vht_ies(hdd_ctx->hHal, hdd_ctx->config->enable2x2); status = cds_get_vdev_types(adapter->device_mode, &type, &subType); if (QDF_STATUS_SUCCESS != status) { hddLog(LOGE, FL("failed to get vdev type")); @@ -3262,13 +3320,9 @@ QDF_STATUS hdd_start_all_adapters(hdd_context_t *hdd_ctx) hdd_ReassocScenario = false; /* indicate disconnected event to nl80211 */ - cfg80211_disconnected(adapter->dev, - WLAN_REASON_UNSPECIFIED, - NULL, 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || defined(WITH_BACKPORTS) - true, -#endif - GFP_KERNEL); + wlan_hdd_cfg80211_indicate_disconnect( + adapter->dev, false, + WLAN_REASON_UNSPECIFIED); } else if (eConnectionState_Connecting == connState) { /* * Indicate connect failure to supplicant if we were in the @@ -4184,6 +4238,8 @@ void hdd_wlan_exit(hdd_context_t *hdd_ctx) /* Proceed and complete the clean up */ } + wlansap_global_deinit(); + free_hdd_ctx: wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); @@ -4782,6 +4838,23 @@ void wlan_hdd_deinit_tx_rx_histogram(hdd_context_t *hdd_ctx) } } +static uint8_t *convert_level_to_string(uint32_t level) +{ + switch (level) { + /* initialize the wlan sub system */ + case WLAN_SVC_TP_NONE: + return "NONE"; + case WLAN_SVC_TP_LOW: + return "LOW"; + case WLAN_SVC_TP_MEDIUM: + return "MED"; + case WLAN_SVC_TP_HIGH: + return "HIGH"; + default: + return "INVAL"; + } +} + /** * wlan_hdd_display_tx_rx_histogram() - display tx rx histogram @@ -4794,32 +4867,42 @@ void wlan_hdd_display_tx_rx_histogram(hdd_context_t *hdd_ctx) int i; #ifdef MSM_PLATFORM - hddLog(QDF_TRACE_LEVEL_ERROR, "BW Interval: %d curr_index %d", - hdd_ctx->config->busBandwidthComputeInterval, - hdd_ctx->hdd_txrx_hist_idx); + hddLog(QDF_TRACE_LEVEL_ERROR, "BW compute Interval: %dms", + hdd_ctx->config->busBandwidthComputeInterval); hddLog(QDF_TRACE_LEVEL_ERROR, "BW High TH: %d BW Med TH: %d BW Low TH: %d", hdd_ctx->config->busBandwidthHighThreshold, hdd_ctx->config->busBandwidthMediumThreshold, hdd_ctx->config->busBandwidthLowThreshold); + hddLog(QDF_TRACE_LEVEL_ERROR, "Enable TCP DEL ACK: %d", + hdd_ctx->config->enable_tcp_delack); hddLog(QDF_TRACE_LEVEL_ERROR, "TCP DEL High TH: %d TCP DEL Low TH: %d", hdd_ctx->config->tcpDelackThresholdHigh, hdd_ctx->config->tcpDelackThresholdLow); + hddLog(QDF_TRACE_LEVEL_ERROR, + "TCP TX HIGH TP TH: %d (Use to set tcp_output_bytes_limit)", + hdd_ctx->config->tcp_tx_high_tput_thres); #endif + hddLog(QDF_TRACE_LEVEL_ERROR, "Total entries: %d Current index: %d", + NUM_TX_RX_HISTOGRAM, hdd_ctx->hdd_txrx_hist_idx); + hddLog(QDF_TRACE_LEVEL_ERROR, - "index, total_rx, interval_rx, total_tx, interval_tx, next_vote_level, next_rx_level, next_tx_level"); + "index, total_rx, interval_rx, total_tx, interval_tx, bus_bw_level, RX TP Level, TX TP Level"); for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) { hddLog(QDF_TRACE_LEVEL_ERROR, - "%d: %llu, %llu, %llu, %llu, %d, %d, %d", + "%d: %llu, %llu, %llu, %llu, %s, %s, %s", i, hdd_ctx->hdd_txrx_hist[i].total_rx, hdd_ctx->hdd_txrx_hist[i].interval_rx, hdd_ctx->hdd_txrx_hist[i].total_tx, hdd_ctx->hdd_txrx_hist[i].interval_tx, - hdd_ctx->hdd_txrx_hist[i].next_vote_level, - hdd_ctx->hdd_txrx_hist[i].next_rx_level, - hdd_ctx->hdd_txrx_hist[i].next_tx_level); + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i].next_vote_level), + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i].next_rx_level), + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i].next_tx_level)); } return; } @@ -4850,29 +4933,27 @@ void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx) hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; QDF_STATUS status; int i; - qdf_time_t total, pause, unpause, curr_time; + qdf_time_t total, pause, unpause, curr_time, delta; status = hdd_get_front_adapter(hdd_ctx, &adapter_node); while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { adapter = adapter_node->pAdapter; hddLog(QDF_TRACE_LEVEL_ERROR, + "\nNetif queue operation statistics:"); + hddLog(QDF_TRACE_LEVEL_ERROR, "Session_id %d device mode %d", adapter->sessionId, adapter->device_mode); - - hddLog(QDF_TRACE_LEVEL_ERROR, - "Netif queue operation statistics:"); hddLog(QDF_TRACE_LEVEL_ERROR, "Current pause_map value %x", adapter->pause_map); curr_time = qdf_system_ticks(); total = curr_time - adapter->start_time; + delta = curr_time - adapter->last_time; if (adapter->pause_map) { - pause = adapter->total_pause_time + - curr_time - adapter->last_time; + pause = adapter->total_pause_time + delta; unpause = adapter->total_unpause_time; } else { - unpause = adapter->total_unpause_time + - curr_time - adapter->last_time; + unpause = adapter->total_unpause_time + delta; pause = adapter->total_pause_time; } hddLog(QDF_TRACE_LEVEL_ERROR, @@ -4881,19 +4962,30 @@ void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx) qdf_system_ticks_to_msecs(pause), qdf_system_ticks_to_msecs(unpause)); hddLog(QDF_TRACE_LEVEL_ERROR, - "reason_type: pause_cnt: unpause_cnt"); + "reason_type: pause_cnt: unpause_cnt: pause_time"); + + for (i = WLAN_CONTROL_PATH; i < WLAN_REASON_TYPE_MAX; i++) { + qdf_time_t pause_delta = 0; + + if (adapter->pause_map & (1 << i)) + pause_delta = delta; - for (i = 1; i < WLAN_REASON_TYPE_MAX; i++) { hddLog(QDF_TRACE_LEVEL_ERROR, - "%s: %d: %d", + "%s: %d: %d: %ums", hdd_reason_type_to_string(i), adapter->queue_oper_stats[i].pause_count, - adapter->queue_oper_stats[i].unpause_count); + adapter->queue_oper_stats[i].unpause_count, + qdf_system_ticks_to_msecs( + adapter->queue_oper_stats[i].total_pause_time + + pause_delta)); } hddLog(QDF_TRACE_LEVEL_ERROR, - "Netif queue operation history: current index %d", - adapter->history_index); + "\nNetif queue operation history:"); + hddLog(QDF_TRACE_LEVEL_ERROR, + "Total entries: %d current index %d", + WLAN_HDD_MAX_HISTORY_ENTRY, adapter->history_index); + hddLog(QDF_TRACE_LEVEL_ERROR, "index: time: action_type: reason_type: pause_map"); @@ -6590,13 +6682,17 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc) status = wlan_hdd_disable_all_dual_mac_features(hdd_ctx); if (status != QDF_STATUS_SUCCESS) { hdd_err("Failed to disable dual mac features"); - goto err_exit_nl_srv; + goto err_debugfs_exit; } } ret = hdd_register_notifiers(hdd_ctx); if (ret) - goto err_exit_nl_srv; + goto err_debugfs_exit; + + status = wlansap_global_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto err_debugfs_exit; memdump_init(); diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 21756643bc8a..598c3d33b4d7 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1442,6 +1442,8 @@ QDF_STATUS hdd_wlan_shutdown(void) so setting it to NULL in hdd context */ pHddCtx->hHal = (tHalHandle) NULL; + wlansap_global_deinit(); + hddLog(QDF_TRACE_LEVEL_FATAL, "%s: WLAN driver shutdown complete", __func__); return QDF_STATUS_SUCCESS; @@ -1664,6 +1666,7 @@ QDF_STATUS hdd_wlan_re_init(void *hif_sc) pHddCtx->target_hw_version, pHddCtx->target_hw_name); #endif + wlansap_global_init(); hddLog(LOGE, "%s: WLAN host driver reinitiation completed!", __func__); diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 7e3acd7d3e84..484a78c562b6 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -1923,13 +1923,13 @@ int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, return ret; } + /** * wlan_hdd_scan_abort() - abort ongoing scan * @pAdapter: Pointer to interface adapter * * Return: 0 for success, non zero for failure */ -#ifdef FEATURE_WLAN_SCAN_PNO int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter) { hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); @@ -1955,6 +1955,7 @@ int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter) return 0; } +#ifdef FEATURE_WLAN_SCAN_PNO /** * hdd_sched_scan_callback - scheduled scan callback * @callbackContext: Callback context @@ -2439,6 +2440,60 @@ int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, } #endif /*FEATURE_WLAN_SCAN_PNO */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) +/** + * __wlan_hdd_cfg80211_abort_scan() - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * This function is used to abort an ongoing scan + * + * Return: None + */ +static void __wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (!ret) + return; + + wlan_hdd_scan_abort(adapter); + + EXIT(); +} + +/** + * wlan_hdd_cfg80211_abort_scan - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * Wrapper to __wlan_hdd_cfg80211_abort_scan() - + * function is used to abort an ongoing scan + * + * Return: None + */ +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + cds_ssr_protect(__func__); + __wlan_hdd_cfg80211_abort_scan(wiphy, wdev); + cds_ssr_unprotect(__func__); +} +#endif + /** * hdd_cleanup_scan_queue() - remove entries in scan queue * diff --git a/core/hdd/src/wlan_hdd_scan.h b/core/hdd/src/wlan_hdd_scan.h index 50a6a8ddf273..3f8235dfa73d 100644 --- a/core/hdd/src/wlan_hdd_scan.h +++ b/core/hdd/src/wlan_hdd_scan.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -71,5 +71,11 @@ int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, int data_len); void hdd_cleanup_scan_queue(hdd_context_t *hdd_ctx); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev); +#endif #endif /* end #if !defined(WLAN_HDD_SCAN_H) */ diff --git a/core/hdd/src/wlan_hdd_tdls.c b/core/hdd/src/wlan_hdd_tdls.c index 6d458c3b94b5..e1bb1e3dd9a1 100644 --- a/core/hdd/src/wlan_hdd_tdls.c +++ b/core/hdd/src/wlan_hdd_tdls.c @@ -44,12 +44,15 @@ #include "wlan_hdd_cfg80211.h" #include "cds_sched.h" #include "wma_types.h" +#include "cds_concurrency.h" + static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t * pHddTdlsCtx); static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx); int wpa_tdls_is_allowed_force_peer(tdlsCtx_t *pHddTdlsCtx, u8 *mac); static void wlan_hdd_tdls_pre_setup(struct work_struct *work); +static void wlan_hdd_tdls_ct_handler(void *user_data); /* * wlan_hdd_tdls_determine_channel_opclass() - determine channel and opclass @@ -434,7 +437,8 @@ static void wlan_hdd_tdls_discovery_timeout_peer_cb(void *userData) MAC_ADDR_ARRAY(tmp->peerMac)); wlan_hdd_tdls_set_peer_link_status(tmp, eTDLS_LINK_IDLE, - eTDLS_LINK_NOT_SUPPORTED); + eTDLS_LINK_NOT_SUPPORTED, + true); mutex_lock(&pHddCtx->tdls_lock); } } @@ -548,6 +552,42 @@ static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx) } /** + * wlan_hdd_tdls_peer_idle_timers_stop() - stop peer idle timers + * @hdd_tdls_ctx: TDLS context + * + * Loop through the idle peer list and stop their timers + * + * Return: None + */ +static void wlan_hdd_tdls_peer_idle_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + int i; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + } + } +} + +/** + * wlan_hdd_tdls_ct_timers_stop() - stop tdls connection tracker timers + * @hdd_tdls_ctx: TDLS context + * + * Return: None + */ +static void wlan_hdd_tdls_ct_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer); + wlan_hdd_tdls_peer_idle_timers_stop(hdd_tdls_ctx); +} + +/** * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running * @hdd_tdls_ctx: TDLS context * @@ -556,6 +596,7 @@ static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx) static void wlan_hdd_tdls_timers_stop(tdlsCtx_t *hdd_tdls_ctx) { wlan_hdd_tdls_monitor_timers_stop(hdd_tdls_ctx); + wlan_hdd_tdls_ct_timers_stop(hdd_tdls_ctx); } /** @@ -599,6 +640,7 @@ static void wlan_hdd_tdls_del_non_forced_peers(tdlsCtx_t *hdd_tdls_ctx) void hdd_tdls_context_init(hdd_context_t *hdd_ctx) { mutex_init(&hdd_ctx->tdls_lock); + qdf_spinlock_create(&hdd_ctx->tdls_ct_spinlock); } /** @@ -612,6 +654,7 @@ void hdd_tdls_context_init(hdd_context_t *hdd_ctx) void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx) { mutex_destroy(&hdd_ctx->tdls_lock); + qdf_spinlock_destroy(&hdd_ctx->tdls_ct_spinlock); } /** @@ -675,6 +718,11 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter) /* initialize TDLS pAdater context */ qdf_mem_zero(pHddTdlsCtx, sizeof(tdlsCtx_t)); + /* Initialize connection tracker timer */ + qdf_mc_timer_init(&pHddTdlsCtx->peer_update_timer, + QDF_TIMER_TYPE_SW, + wlan_hdd_tdls_ct_handler, + pAdapter); qdf_mc_timer_init(&pHddTdlsCtx->peerDiscoveryTimeoutTimer, QDF_TIMER_TYPE_SW, wlan_hdd_tdls_discovery_timeout_peer_cb, @@ -702,6 +750,7 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter) pHddCtx->tdls_scan_ctxt.attempt = 0; pHddCtx->tdls_scan_ctxt.reject = 0; pHddCtx->tdls_scan_ctxt.scan_request = NULL; + pHddCtx->tdls_external_peer_count = 0; if (pHddCtx->config->fEnableTDLSSleepSta || pHddCtx->config->fEnableTDLSBufferSta || @@ -723,6 +772,12 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter) pHddTdlsCtx->curr_candidate = NULL; pHddTdlsCtx->magic = 0; + pHddTdlsCtx->valid_mac_entries = 0; + + /* This flag will set be true, only when device operates in + * standalone STA mode + */ + pHddCtx->enable_tdls_connection_tracker = false; /* remember configuration even if it is not used right now. it could be used later */ pHddTdlsCtx->threshold_config.tx_period_t = @@ -731,6 +786,8 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter) pHddCtx->config->fTDLSTxPacketThreshold; pHddTdlsCtx->threshold_config.discovery_tries_n = pHddCtx->config->fTDLSMaxDiscoveryAttempt; + pHddTdlsCtx->threshold_config.idle_timeout_t = + pHddCtx->config->tdls_idle_timeout; pHddTdlsCtx->threshold_config.idle_packet_n = pHddCtx->config->fTDLSIdlePacketThreshold; pHddTdlsCtx->threshold_config.rssi_trigger_threshold = @@ -919,6 +976,7 @@ void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter) } pHddTdlsCtx->magic = 0; + pHddCtx->tdls_external_peer_count = 0; pHddTdlsCtx->pAdapter = NULL; qdf_mem_free(pHddTdlsCtx); @@ -930,6 +988,46 @@ done: } /** + * wlan_hdd_tdls_peer_idle_timers_destroy() - destroy peer idle timers + * @hdd_tdls_ctx: TDLS context + * + * Loop through the idle peer list and destroy their timers + * + * Return: None + */ +static void wlan_hdd_tdls_peer_idle_timers_destroy(tdlsCtx_t *hdd_tdls_ctx) +{ + int i; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + hdd_info(MAC_ADDRESS_STR ": destroy idle timer", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + qdf_mc_timer_destroy(&curr_peer->peer_idle_timer); + } + } +} + +/** + * wlan_hdd_tdls_ct_timers_destroy() - destroy tdls connection tracker timers + * @hdd_tdls_ctx: TDLS context + * + * Return: None + */ +static void wlan_hdd_tdls_ct_timers_destroy(tdlsCtx_t *hdd_tdls_ctx) +{ + qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer); + qdf_mc_timer_destroy(&hdd_tdls_ctx->peer_update_timer); + wlan_hdd_tdls_peer_idle_timers_destroy(hdd_tdls_ctx); +} + +/** * wlan_hdd_tdls_monitor_timers_destroy() - destroy all tdls monitoring timers * @pHddTdlsCtx: TDLS context * @@ -950,19 +1048,22 @@ static void wlan_hdd_tdls_monitor_timers_destroy(tdlsCtx_t *pHddTdlsCtx) static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx) { wlan_hdd_tdls_monitor_timers_destroy(pHddTdlsCtx); + wlan_hdd_tdls_ct_timers_destroy(pHddTdlsCtx); } /** * wlan_hdd_tdls_get_peer() - find or add an peer given mac address * @pAdapter: HDD adapter * @mac: MAC address used to find or create peer + * @need_mutex_lock: flag identify whether mutex needed or not * * Search peer given an MAC address and create one if not found. * * Return: Pointer to peer if mac address exist or peer creation * succeeds; NULL if peer creation fails */ -hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac) +hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac, + bool need_mutex_lock) { struct list_head *head; hddTdlsPeer_t *peer; @@ -974,7 +1075,7 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac) return NULL; /* if already there, just update */ - peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true); + peer = wlan_hdd_tdls_find_peer(pAdapter, mac, need_mutex_lock); if (peer != NULL) { return peer; } @@ -987,13 +1088,15 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac) return NULL; } - mutex_lock(&pHddCtx->tdls_lock); + if (need_mutex_lock) + mutex_lock(&pHddCtx->tdls_lock); pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); if (NULL == pHddTdlsCtx) { qdf_mem_free(peer); - mutex_unlock(&pHddCtx->tdls_lock); + if (need_mutex_lock) + mutex_unlock(&pHddCtx->tdls_lock); hddLog(LOG1, FL("pHddTdlsCtx is NULL")); return NULL; } @@ -1010,7 +1113,9 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac) pHddCtx->config->fTDLSPrefOffChanBandwidth); list_add_tail(&peer->node, head); - mutex_unlock(&pHddCtx->tdls_lock); + + if (need_mutex_lock) + mutex_unlock(&pHddCtx->tdls_lock); return peer; } @@ -1028,7 +1133,7 @@ int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, { hddTdlsPeer_t *curr_peer; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1049,7 +1154,8 @@ int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, */ void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, tTDLSLinkStatus status, - tTDLSLinkReason reason) + tTDLSLinkReason reason, + bool lock_needed) { uint32_t state = 0; int32_t res = 0; @@ -1072,7 +1178,9 @@ void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, "tdls set peer " MAC_ADDRESS_STR " link status to %u", MAC_ADDR_ARRAY(curr_peer->peerMac), status); - mutex_lock(&pHddCtx->tdls_lock); + if (lock_needed) + mutex_lock(&pHddCtx->tdls_lock); + curr_peer->link_status = status; /* If TDLS link status is already passed the discovery state @@ -1082,7 +1190,9 @@ void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, curr_peer->discovery_attempt = 0; } - mutex_unlock(&pHddCtx->tdls_lock); + if (lock_needed) + mutex_unlock(&pHddCtx->tdls_lock); + if (curr_peer->isForcedPeer && curr_peer->state_change_notification) { uint32_t opclass; uint32_t channel; @@ -1184,7 +1294,7 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, if (0 != (wlan_hdd_validate_context(pHddCtx))) return -EINVAL; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (NULL == curr_peer) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1214,7 +1324,8 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, rssi_trigger_threshold) { wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_DISCOVERED, - eTDLS_LINK_SUCCESS); + eTDLS_LINK_SUCCESS, + true); hddLog(LOG1, "Rssi Threshold met: " MAC_ADDRESS_STR " rssi = %d threshold= %d", @@ -1236,7 +1347,8 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, rssi_trigger_threshold); wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_IDLE, - eTDLS_LINK_UNSPECIFIED); + eTDLS_LINK_UNSPECIFIED, + true); /* if RSSI threshold is not met then allow further discovery * attempts by decrementing count for the last attempt @@ -1268,7 +1380,7 @@ int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter, { hddTdlsPeer_t *curr_peer; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1310,7 +1422,7 @@ int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter, { hddTdlsPeer_t *curr_peer; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1378,7 +1490,7 @@ int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac, { hddTdlsPeer_t *curr_peer; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1402,7 +1514,7 @@ int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac, { hddTdlsPeer_t *curr_peer; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1414,18 +1526,6 @@ int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac, } /** - * wlan_hdd_tdls_extract_da() - Extract destination address from socket buffer - * @skb: socket buffer - * @mac: output mac address buffer to store the destination address - * - * Return: Void - */ -void wlan_hdd_tdls_extract_da(struct sk_buff *skb, uint8_t *mac) -{ - memcpy(mac, skb->data, 6); -} - -/** * wlan_hdd_tdls_extract_sa() - Extract source address from socket buffer * @skb: socket buffer * @mac: output mac address buffer to store the source address @@ -1455,7 +1555,7 @@ int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, eTDLS_SUPPORT_EXTERNAL_CONTROL != pHddCtx->tdls_mode) return -EINVAL; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOG1, FL("curr_peer is NULL")); return -EINVAL; @@ -1592,6 +1692,11 @@ static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx) wlan_tdd_tdls_reset_tx_rx(pHddTdlsCtx); wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + /* Restart the connection tracker timer */ + wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter, + &pHddTdlsCtx->peer_update_timer, + pHddTdlsCtx->threshold_config.tx_period_t); + } /** @@ -1875,7 +1980,7 @@ int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac, { hddTdlsPeer_t *curr_peer; - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -1999,7 +2104,6 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, tdlsCtx_t *pHddTdlsCtx; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - ENTER(); if (0 != (wlan_hdd_validate_context(pHddCtx))) return NULL; @@ -2031,7 +2135,7 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, } if (mutexLock) mutex_unlock(&pHddCtx->tdls_lock); - EXIT(); + return NULL; } @@ -2087,7 +2191,7 @@ int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac) pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (curr_peer == NULL) { hddLog(LOGE, FL("curr_peer is NULL")); return -EINVAL; @@ -2111,7 +2215,8 @@ int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac) wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_IDLE, - eTDLS_LINK_UNSPECIFIED); + eTDLS_LINK_UNSPECIFIED, + true); curr_peer->staId = 0; return 0; @@ -2240,6 +2345,7 @@ void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter) { tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + uint32_t tx_period_t; if ((NULL == pHddCtx) || (NULL == pHddTdlsCtx)) { QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, @@ -2247,17 +2353,23 @@ void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter) return; } - mutex_lock(&pHddCtx->tdls_lock); + tx_period_t = pHddTdlsCtx->threshold_config.tx_period_t; hddLog(LOG1, FL("update %d"), pHddTdlsCtx->threshold_config.tx_period_t); + mutex_lock(&pHddCtx->tdls_lock); + if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode || eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode) { wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx); pHddTdlsCtx->discovery_sent_cnt = 0; wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + /* Start the connection tracker timer */ + wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter, + &pHddTdlsCtx->peer_update_timer, + tx_period_t); } mutex_unlock(&pHddCtx->tdls_lock); @@ -2294,7 +2406,7 @@ void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter) pHddTdlsCtx->discovery_sent_cnt = 0; wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); - wlan_hdd_tdls_monitor_timers_stop(pHddTdlsCtx); + wlan_hdd_tdls_timers_stop(pHddTdlsCtx); wlan_hdd_tdls_free_list(pHddTdlsCtx); pHddTdlsCtx->curr_candidate = NULL; @@ -2431,11 +2543,14 @@ static hddTdlsPeer_t *wlan_hdd_tdls_find_progress_peer(hdd_adapter_t *pAdapter, * @pHddCtx: HDD context * @mac: mac address of the peer * @skip_self: if 1, skip checking self. If 0, search includes self + * @need_lock: flag to indicate, whether the caller acquired the mutex or not * * Return: TDLS peer if found; NULL otherwise */ hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, - const uint8_t *mac, uint8_t skip_self) + const uint8_t *mac, + uint8_t skip_self, + bool need_lock) { hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; hdd_adapter_t *pAdapter = NULL; @@ -2443,7 +2558,8 @@ hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, hddTdlsPeer_t *curr_peer = NULL; QDF_STATUS status = 0; - mutex_lock(&pHddCtx->tdls_lock); + if (need_lock) + mutex_lock(&pHddCtx->tdls_lock); status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { @@ -2455,14 +2571,18 @@ hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, wlan_hdd_tdls_find_progress_peer(pAdapter, mac, skip_self); if (curr_peer) { - mutex_unlock(&pHddCtx->tdls_lock); + if (need_lock) + mutex_unlock(&pHddCtx->tdls_lock); return curr_peer; } } status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); pAdapterNode = pNext; } - mutex_unlock(&pHddCtx->tdls_lock); + + if (need_lock) + mutex_unlock(&pHddCtx->tdls_lock); + return NULL; } @@ -2515,7 +2635,7 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work) mutex_unlock(&pHddCtx->tdls_lock); - temp_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0); + temp_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, true); if (NULL != temp_peer) { hddLog(LOG1, @@ -2527,7 +2647,8 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work) if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support) wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_DISCOVERING, - eTDLS_LINK_SUCCESS); + eTDLS_LINK_SUCCESS, + true); mutex_lock(&pHddCtx->tdls_lock); @@ -2563,7 +2684,8 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work) mutex_unlock(&pHddCtx->tdls_lock); wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_DISCOVERING, - eTDLS_LINK_SUCCESS); + eTDLS_LINK_SUCCESS, + true); status = wlan_hdd_cfg80211_send_tdls_discover_req(pHddTdlsCtx->pAdapter-> @@ -2589,7 +2711,8 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work) mutex_unlock(&pHddCtx->tdls_lock); wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_IDLE, - eTDLS_LINK_UNSPECIFIED); + eTDLS_LINK_UNSPECIFIED, + true); mutex_lock(&pHddCtx->tdls_lock); } goto done; @@ -2717,7 +2840,7 @@ int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy, if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) return 1; - curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0); + curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, true); if (NULL != curr_peer) { if (pHddCtx->tdls_scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) { pHddCtx->tdls_scan_ctxt.reject = 0; @@ -2729,7 +2852,8 @@ int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy, wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_IDLE, - eTDLS_LINK_UNSPECIFIED); + eTDLS_LINK_UNSPECIFIED, + true); return 1; } hddLog(LOGW, @@ -2953,7 +3077,8 @@ void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_TEARING, - eTDLS_LINK_UNSPECIFIED); + eTDLS_LINK_UNSPECIFIED, + true); hdd_info("Teardown reason %d", reason); cfg80211_tdls_oper_request(pAdapter->dev, curr_peer->peerMac, @@ -3531,7 +3656,7 @@ int wlan_hdd_tdls_add_station(struct wiphy *wiphy, return -ENOTSUPP; } - pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac); + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac, true); if (NULL == pTdlsPeer) { hddLog(LOGE, @@ -3567,7 +3692,7 @@ int wlan_hdd_tdls_add_station(struct wiphy *wiphy, } /* when others are on-going, we want to change link_status to idle */ - if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true)) { + if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true, true)) { hddLog(LOG1, "%s: " MAC_ADDRESS_STR " TDLS setup is ongoing. Request declined.", @@ -3821,7 +3946,8 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, } if (WLAN_IS_TDLS_SETUP_ACTION(action_code)) { - if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer, true)) { + if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer, + true, true)) { QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, "%s: " MAC_ADDRESS_STR " TDLS setup is ongoing. action %d declined.", @@ -4118,7 +4244,7 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, __func__); return -ENOTSUPP; } - pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer); + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer, true); if (pTdlsPeer == NULL) { QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, "%s: peer " MAC_ADDRESS_STR " does not exist", @@ -4140,6 +4266,11 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, return -EINVAL; } + pHddCtx->tdls_external_peer_count++; + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(pHddCtx); + /* validate if off channel is DFS channel */ if (CDS_IS_DFS_CH(chan)) { hdd_err("Resetting TDLS off-channel from %d to %d", @@ -4204,6 +4335,7 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, "%s Failed", __func__); return -EINVAL; } + /* Update the peer mac to firmware, so firmware * could update the connection table */ @@ -4213,6 +4345,13 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, MAC_ADDR_ARRAY(peer)); return -EINVAL; } + + if (pHddCtx->tdls_external_peer_count) + pHddCtx->tdls_external_peer_count--; + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(pHddCtx); + if (0 != wlan_hdd_set_callback(pTdlsPeer, NULL)) { QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, "%s TDLS set callback Failed", __func__); @@ -4345,7 +4484,8 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, } wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, eTDLS_LINK_CONNECTED, - eTDLS_LINK_SUCCESS); + eTDLS_LINK_SUCCESS, + true); /* start TDLS client registration with TL */ status = hdd_roam_register_tdlssta(pAdapter, peer, @@ -4558,7 +4698,8 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, (pTdlsPeer->link_status == eTDLS_LINK_TEARING) ? eTDLS_LINK_UNSPECIFIED : - eTDLS_LINK_DROPPED_BY_REMOTE); + eTDLS_LINK_DROPPED_BY_REMOTE, + true); } else { QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, @@ -4937,6 +5078,646 @@ int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode) } /** + * wlan_hdd_tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample + * @adapter: pointer to hdd adapter + * @hdd_ctx: hdd context + * @tdls_ctx: tdls context + * + * Function to update data traffic information in tdls connection + * tracker data structure for connection tracker operation + * + * Return: None + */ +static void wlan_hdd_tdls_ct_sampling_tx_rx(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + tdlsCtx_t *tdls_ctx) +{ + hddTdlsPeer_t *curr_peer; + uint8_t mac[QDF_MAC_ADDR_SIZE]; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE]; + + qdf_spin_lock(&hdd_ctx->tdls_ct_spinlock); + + if (0 == tdls_ctx->valid_mac_entries) { + qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock); + return; + } + + valid_mac_entries = tdls_ctx->valid_mac_entries; + + memcpy(ct_peer_mac_table, tdls_ctx->ct_peer_mac_table, + (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries); + + memset(tdls_ctx->ct_peer_mac_table, 0, + (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries); + + tdls_ctx->valid_mac_entries = 0; + + qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock); + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + memcpy(mac, ct_peer_mac_table[mac_cnt].mac_address.bytes, + QDF_MAC_ADDR_SIZE); + curr_peer = wlan_hdd_tdls_get_peer(adapter, mac, false); + if (NULL != curr_peer) { + curr_peer->tx_pkt = + ct_peer_mac_table[mac_cnt].tx_packet_cnt; + curr_peer->rx_pkt = + ct_peer_mac_table[mac_cnt].rx_packet_cnt; + } + } +} + +/** + * wlan_hdd_tdls_update_rx_pkt_cnt() - Update rx packet count + * @adapter: pointer to hdd adapter + * @skb: pointer to sk_buff + * + * Increase the rx packet count, if the sender is not bssid and the packet is + * not broadcast and muticast packet + * + * This sampling information will be used in TDLS connection tracker + * + * This function expected to be called in an atomic context so blocking APIs + * not allowed + * + * Return: None + */ +void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *hdd_sta_ctx; + tdlsCtx_t *tdls_ctx; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct qdf_mac_addr *mac_addr; + + mac_addr = (struct qdf_mac_addr *)(skb->data+QDF_MAC_ADDR_SIZE); + if (qdf_is_macaddr_group(mac_addr)) + return; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) + return; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx; + + qdf_spin_lock(&hdd_ctx->tdls_ct_spinlock); + valid_mac_entries = tdls_ctx->valid_mac_entries; + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + if (memcmp(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) { + tdls_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt++; + goto rx_cnt_return; + } + } + + /* If we have more than 8 peers within 30 mins. we will + * stop tracking till the old entries are removed + */ + if (mac_cnt < TDLS_CT_MAC_MAX_TABLE_SIZE) { + memcpy(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + tdls_ctx->valid_mac_entries = mac_cnt+1; + tdls_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt = 1; + } + +rx_cnt_return: + qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock); + return; +} + +/** + * wlan_hdd_tdls_update_tx_pkt_cnt() - update tx packet + * @adapter: pointer to hdd adapter + * @skb: pointer to sk_buff + * + * Increase the tx packet count, if the sender is not bssid and the packet is + * not broadcast and muticast packet + * + * This sampling information will be used in TDLS connection tracker + * + * This function expected to be called in an atomic context so blocking APIs + * not allowed + * + * Return: None + */ +void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *hdd_sta_ctx; + tdlsCtx_t *tdls_ctx; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct qdf_mac_addr *mac_addr; + + mac_addr = (struct qdf_mac_addr *)skb->data; + if (qdf_is_macaddr_group(mac_addr)) + return; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes, mac_addr, + QDF_MAC_ADDR_SIZE) == 0) + return; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx; + + qdf_spin_lock(&hdd_ctx->tdls_ct_spinlock); + valid_mac_entries = tdls_ctx->valid_mac_entries; + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + if (memcmp(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) { + tdls_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt++; + goto tx_cnt_return; + } + } + + /* If we have more than 8 peers within 30 mins. we will + * stop tracking till the old entries are removed + */ + if (mac_cnt < TDLS_CT_MAC_MAX_TABLE_SIZE) { + memcpy(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + tdls_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt = 1; + tdls_ctx->valid_mac_entries++; + } + +tx_cnt_return: + qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock); + return; +} + +/** + * wlan_hdd_tdls_implicit_send_discovery_request() - send discovery request + * @hdd_tdls_ctx: tdls context + * + * Return: None + */ +static +void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t *hdd_tdls_ctx) +{ + hdd_context_t *hdd_ctx; + hddTdlsPeer_t *curr_peer, *temp_peer; + + ENTER(); + if (NULL == hdd_tdls_ctx) { + hdd_info("hdd_tdls_ctx is NULL"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(hdd_tdls_ctx->pAdapter); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + curr_peer = hdd_tdls_ctx->curr_candidate; + if (NULL == curr_peer) { + hdd_err("curr_peer is NULL"); + return; + } + + /* This function is called in mutex_lock */ + temp_peer = wlan_hdd_tdls_is_progress(hdd_ctx, NULL, 0, false); + if (NULL != temp_peer) { + hdd_info(MAC_ADDRESS_STR " ongoing. pre_setup ignored", + MAC_ADDR_ARRAY(temp_peer->peerMac)); + goto done; + } + + if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support) + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_DISCOVERING, + eTDLS_LINK_SUCCESS, + false); + + hdd_info("Implicit TDLS, Send Discovery request event"); + cfg80211_tdls_oper_request(hdd_tdls_ctx->pAdapter->dev, + curr_peer->peerMac, + NL80211_TDLS_DISCOVERY_REQ, + false, + GFP_KERNEL); + hdd_tdls_ctx->discovery_sent_cnt++; + + wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter, + &hdd_tdls_ctx->peerDiscoveryTimeoutTimer, + hdd_tdls_ctx->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); + + hdd_info("discovery count %u timeout %u msec", + hdd_tdls_ctx->discovery_sent_cnt, + hdd_tdls_ctx->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); +done: + hdd_tdls_ctx->curr_candidate = NULL; + hdd_tdls_ctx->magic = 0; + EXIT(); + return; +} + +/** + * wlan_hdd_get_conn_info() - get the tdls connection information. + * @hdd_ctx: hdd context + * @hdd_ctx: sta id + * + * Function to check tdls sta index + * + * Return: None + */ +static tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *hdd_ctx, + uint8_t idx) +{ + uint8_t sta_idx; + + /* check if there is available index for this new TDLS STA */ + for (sta_idx = 0; sta_idx < HDD_MAX_NUM_TDLS_STA; sta_idx++) { + if (idx == hdd_ctx->tdlsConnInfo[sta_idx].staId) { + hdd_info("tdls peer with staIdx %u exists", idx); + return &hdd_ctx->tdlsConnInfo[sta_idx]; + } + } + hdd_err("tdls peer with staIdx %u not exists", idx); + return NULL; +} + +/** + * wlan_hdd_tdls_idle_handler() - Check tdls idle traffic + * @user_data: data from tdls idle timer + * + * Function to check the tdls idle traffic and make a decision about + * tdls teardown + * + * Return: None + */ +static void wlan_hdd_tdls_idle_handler(void *user_data) +{ + tdlsConnInfo_t *tdls_info = (tdlsConnInfo_t *) user_data; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *hdd_tdls_ctx; + hdd_context_t *hdd_ctx; + v_CONTEXT_t cds_context; + hdd_adapter_t *adapter; + + if (!tdls_info->staId) { + hdd_err("peer (staidx %u) doesn't exists", tdls_info->staId); + return; + } + + cds_context = cds_get_global_context(); + if (NULL == cds_context) { + hdd_err("cds_context points to NULL"); + return; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, + tdls_info->sessionId); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + + curr_peer = wlan_hdd_tdls_find_peer(adapter, + (u8 *) &tdls_info->peerMac.bytes[0], true); + + if (NULL == curr_peer) { + hdd_err("Invalid tdls idle timer expired"); + goto error_idle_return; + } + + hdd_tdls_ctx = curr_peer->pHddTdlsCtx; + if (NULL == hdd_tdls_ctx) { + hdd_err("Invalid hdd_tdls_ctx context"); + goto error_idle_return; + } + + hdd_info(MAC_ADDRESS_STR " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->tx_pkt, + curr_peer->rx_pkt, + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n); + + /* Check tx/rx statistics on this tdls link for recent activities and + * then decide whether to tear down the link or keep it. + */ + if ((curr_peer->tx_pkt >= + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n) || + (curr_peer->rx_pkt >= + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n)) { + /* this tdls link got back to normal, so keep it */ + hdd_info("tdls link to " MAC_ADDRESS_STR + " back to normal, will stay", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + } else { + /* this tdls link needs to get torn down */ + hdd_info("trigger tdls link to "MAC_ADDRESS_STR + " down", MAC_ADDR_ARRAY(curr_peer->peerMac)); + wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + } +error_idle_return: + return; +} + +/** + * tdls_ct_process_idle_and_discovery() - process the traffic data + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function to check the peer traffic data in idle link and tdls + * discovering link + * + * Return: None + */ +static void tdls_ct_process_idle_and_discovery(hddTdlsPeer_t *curr_peer, + tdlsCtx_t *hdd_tdls_ctx) +{ + uint16_t valid_peers; + + valid_peers = wlan_hdd_tdls_connected_peers(hdd_tdls_ctx->pAdapter); + + if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >= + hdd_tdls_ctx->threshold_config.tx_packet_n) { + if (HDD_MAX_NUM_TDLS_STA > valid_peers) { + hdd_info("Tput trigger TDLS pre-setup"); + hdd_tdls_ctx->curr_candidate = curr_peer; + wlan_hdd_tdls_implicit_send_discovery_request( + hdd_tdls_ctx); + } else { + hdd_info("Maximum peers connected already! %d", + valid_peers); + } + } +} + + +/** + * tdls_ct_process_connected_link() - process the traffic + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function to check the peer traffic data in active STA + * session + * + * Return: None + */ +static void tdls_ct_process_connected_link(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + if ((int32_t)curr_peer->rssi < + (int32_t)hdd_tdls_ctx->threshold_config.rssi_teardown_threshold) { + hdd_warn("Tear down - low RSSI: " MAC_ADDRESS_STR "!", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + /* unlock the mutex here, it may used in caller function */ + mutex_unlock(&hdd_ctx->tdls_lock); + wlan_hdd_tdls_indicate_teardown(hdd_tdls_ctx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + mutex_lock(&hdd_ctx->tdls_lock); + return; + } + + /* Only teardown based on non zero idle packet threshold, to address + * a use case where this threshold does not get consider for TEAR DOWN + */ + if ((0 != hdd_tdls_ctx->threshold_config.idle_packet_n) && + ((curr_peer->tx_pkt < + hdd_tdls_ctx->threshold_config.idle_packet_n) && + (curr_peer->rx_pkt < + hdd_tdls_ctx->threshold_config.idle_packet_n))) { + if (!curr_peer->is_peer_idle_timer_initialised) { + uint8_t staId = (uint8_t)curr_peer->staId; + tdlsConnInfo_t *tdls_info; + tdls_info = wlan_hdd_get_conn_info(hdd_ctx, staId); + qdf_mc_timer_init(&curr_peer->peer_idle_timer, + QDF_TIMER_TYPE_SW, + wlan_hdd_tdls_idle_handler, + tdls_info); + curr_peer->is_peer_idle_timer_initialised = true; + } + if (QDF_TIMER_STATE_RUNNING != + curr_peer->peer_idle_timer.state) { + hdd_warn("Tx/Rx Idle timer start: " MAC_ADDRESS_STR "!", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter, + &curr_peer->peer_idle_timer, + hdd_tdls_ctx->threshold_config.idle_timeout_t); + } + } else if (QDF_TIMER_STATE_RUNNING == + curr_peer->peer_idle_timer.state) { + hdd_warn("Tx/Rx Idle timer stop: " MAC_ADDRESS_STR "!", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + } +} + +/** + * wlan_hdd_tdls_ct_process_cap_supported() - process TDLS supported peer. + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function to check the peer traffic data for tdls supported peer + * + * Return: None + */ +static void wlan_hdd_tdls_ct_process_cap_supported(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + hdd_info("tx %d, rx %d (thr.pkt %d/idle %d), rssi %d (thr.trig %d/tear %d)", + curr_peer->tx_pkt, curr_peer->rx_pkt, + hdd_tdls_ctx->threshold_config.tx_packet_n, + hdd_tdls_ctx->threshold_config.idle_packet_n, + curr_peer->rssi, + hdd_tdls_ctx->threshold_config.rssi_trigger_threshold, + hdd_tdls_ctx->threshold_config.rssi_teardown_threshold); + + switch (curr_peer->link_status) { + case eTDLS_LINK_IDLE: + case eTDLS_LINK_DISCOVERING: + if (hdd_ctx->config->fTDLSExternalControl && + (!curr_peer->isForcedPeer)) + break; + tdls_ct_process_idle_and_discovery(curr_peer, hdd_tdls_ctx); + break; + case eTDLS_LINK_CONNECTED: + tdls_ct_process_connected_link(curr_peer, hdd_ctx, + hdd_tdls_ctx); + break; + default: + break; + } +} + +/** + * wlan_hdd_tdls_ct_process_cap_unknown() - process unknown peer + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function check the peer traffic data , when tdls capability is unknown + * + * Return: None + */ +static void wlan_hdd_tdls_ct_process_cap_unknown(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + if (hdd_ctx->config->fTDLSExternalControl && + (!curr_peer->isForcedPeer)) { + return; + } + + hdd_info("threshold_config.tx_packet_n = %d curr_peer->tx_pkt = %d curr_peer->rx_pkt = %d ", + hdd_tdls_ctx->threshold_config.tx_packet_n, curr_peer->tx_pkt, + curr_peer->rx_pkt); + + if (!TDLS_IS_CONNECTED(curr_peer) && + ((curr_peer->tx_pkt + curr_peer->rx_pkt) >= + hdd_tdls_ctx->threshold_config.tx_packet_n)) { + /* Ignore discovery attempt if External Control is enabled, that + * is, peer is forced. In that case, continue discovery attempt + * regardless attempt count + */ + hdd_info("TDLS UNKNOWN pre discover "); + if (curr_peer->isForcedPeer || curr_peer->discovery_attempt++ < + hdd_tdls_ctx->threshold_config.discovery_tries_n) { + hdd_info("TDLS UNKNOWN discover "); + hdd_tdls_ctx->curr_candidate = curr_peer; + wlan_hdd_tdls_implicit_send_discovery_request(hdd_tdls_ctx); + } else { + curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED; + wlan_hdd_tdls_set_peer_link_status( + curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_NOT_SUPPORTED, + false); + } + } +} + + +/** + * wlan_hdd_tdls_ct_process_peers() - process the peer + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * This function check the peer capability and process the metadata from + * the peer + * + * Return: None + */ +static void wlan_hdd_tdls_ct_process_peers(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + hdd_info(MAC_ADDRESS_STR " link_status %d tdls_support %d", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->link_status, curr_peer->tdls_support); + + switch (curr_peer->tdls_support) { + case eTDLS_CAP_SUPPORTED: + wlan_hdd_tdls_ct_process_cap_supported(curr_peer, hdd_ctx, + hdd_tdls_ctx); + break; + + case eTDLS_CAP_UNKNOWN: + wlan_hdd_tdls_ct_process_cap_unknown(curr_peer, hdd_ctx, + hdd_tdls_ctx); + break; + default: + break; + } + +} + +/** + * wlan_hdd_tdls_ct_handler() - TDLS connection tracker handler + * @user_data: user data from timer + * + * tdls connection tracker timer starts, when the STA connected to AP + * and it's scan the traffic between two STA peers and make TDLS + * connection and teardown, based on the traffic threshold + * + * Return: None + */ +static void wlan_hdd_tdls_ct_handler(void *user_data) +{ + int i; + hdd_adapter_t *adapter; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *hdd_tdls_ctx; + hdd_context_t *hdd_ctx; + + adapter = (hdd_adapter_t *)user_data; + + if (NULL == adapter) { + hdd_err("Invalid adapter context"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + hdd_tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx; + + if (NULL == hdd_tdls_ctx) { + hdd_err("Invalid hdd_tdls_ctx context"); + return; + } + + /* If any concurrency is detected */ + if (!hdd_ctx->enable_tdls_connection_tracker) + goto restart_return; + + mutex_lock(&hdd_ctx->tdls_lock); + + /* Update tx rx traffic sample in tdls data structures */ + wlan_hdd_tdls_ct_sampling_tx_rx(adapter, hdd_ctx, + hdd_tdls_ctx); + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + wlan_hdd_tdls_ct_process_peers(curr_peer, hdd_ctx, + hdd_tdls_ctx); + curr_peer->tx_pkt = 0; + curr_peer->rx_pkt = 0; + } + } + + mutex_unlock(&hdd_ctx->tdls_lock); + +restart_return: + wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter, + &hdd_tdls_ctx->peer_update_timer, + hdd_tdls_ctx->threshold_config.tx_period_t); +} + +/** * hdd_set_tdls_scan_type - set scan during active tdls session * @hdd_ctx: ptr to hdd context. * @val: scan type value: 0 or 1. diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 10897f1d4160..d8649a29b630 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -315,6 +315,10 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) bool granted; uint8_t STAId = WLAN_MAX_STA_COUNT; hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; +#ifdef QCA_PKT_PROTO_TRACE + uint8_t proto_type = 0; +#endif /* QCA_PKT_PROTO_TRACE */ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); #ifdef QCA_WIFI_FTM if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { @@ -466,7 +470,25 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) skb->queue_mapping = hdd_linux_up_to_ac_map[up]; } +#ifdef QCA_PKT_PROTO_TRACE + if ((hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) || + (hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) { + proto_type = cds_pkt_get_proto_type(skb, + hdd_ctx->config->gEnableDebugLog, + 0); + if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) { + cds_pkt_trace_buf_update("ST:T:EPL"); + } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) { + cds_pkt_trace_buf_update("ST:T:DHC"); + } + } +#endif /* QCA_PKT_PROTO_TRACE */ + pAdapter->stats.tx_bytes += skb->len; + + if (hdd_ctx->enable_tdls_connection_tracker) + wlan_hdd_tdls_update_tx_pkt_cnt(pAdapter, skb); + ++pAdapter->stats.tx_packets; /* Zero out skb's context buffer for the driver to use */ @@ -805,6 +827,9 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) qdf_nbuf_data_addr(rxBuf), sizeof(qdf_nbuf_data(rxBuf)), QDF_RX)); + if (pHddCtx->enable_tdls_connection_tracker) + wlan_hdd_tdls_update_rx_pkt_cnt(pAdapter, skb); + skb->dev = pAdapter->dev; skb->protocol = eth_type_trans(skb, skb->dev); ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; @@ -966,12 +991,25 @@ static void wlan_hdd_update_unpause_time(hdd_adapter_t *adapter) * * Return: none */ -static void wlan_hdd_update_pause_time(hdd_adapter_t *adapter) +static void wlan_hdd_update_pause_time(hdd_adapter_t *adapter, + uint32_t temp_map) { qdf_time_t curr_time = qdf_system_ticks(); + uint8_t i; + qdf_time_t pause_time; - adapter->total_pause_time += curr_time - adapter->last_time; + pause_time = curr_time - adapter->last_time; + adapter->total_pause_time += pause_time; adapter->last_time = curr_time; + + for (i = 0; i < WLAN_REASON_TYPE_MAX; i++) { + if (temp_map & (1 << i)) { + adapter->queue_oper_stats[i].total_pause_time += + pause_time; + break; + } + } + } /** @@ -989,6 +1027,7 @@ static void wlan_hdd_update_pause_time(hdd_adapter_t *adapter) void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, enum netif_action_type action, enum netif_reason_type reason) { + uint32_t temp_map; if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) || (!adapter->dev)) { @@ -1019,20 +1058,22 @@ void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, case WLAN_START_ALL_NETIF_QUEUE: spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; adapter->pause_map &= ~(1 << reason); if (!adapter->pause_map) { netif_tx_start_all_queues(adapter->dev); - wlan_hdd_update_pause_time(adapter); + wlan_hdd_update_pause_time(adapter, temp_map); } spin_unlock_bh(&adapter->pause_map_lock); break; case WLAN_WAKE_ALL_NETIF_QUEUE: spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; adapter->pause_map &= ~(1 << reason); if (!adapter->pause_map) { netif_tx_wake_all_queues(adapter->dev); - wlan_hdd_update_pause_time(adapter); + wlan_hdd_update_pause_time(adapter, temp_map); } spin_unlock_bh(&adapter->pause_map_lock); break; @@ -1052,10 +1093,11 @@ void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: spin_lock_bh(&adapter->pause_map_lock); netif_carrier_on(adapter->dev); + temp_map = adapter->pause_map; adapter->pause_map &= ~(1 << reason); if (!adapter->pause_map) { netif_tx_start_all_queues(adapter->dev); - wlan_hdd_update_pause_time(adapter); + wlan_hdd_update_pause_time(adapter, temp_map); } spin_unlock_bh(&adapter->pause_map_lock); break; diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 1024e51715e3..04c90f0bdf7a 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -9835,6 +9835,8 @@ static int __iw_set_two_ints_getnone(struct net_device *dev, qdf_dp_trace_dump_all(value[2]); else if (value[1] == ENABLE_DP_TRACE_LIVE_MODE) qdf_dp_trace_enable_live_mode(); + else if (value[1] == CLEAR_DP_TRACE_BUFFER) + qdf_dp_trace_clear_buffer(); break; case WE_SET_MON_MODE_CHAN: ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]); diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h index 1e70972a16d1..ec52065e6b7d 100644 --- a/core/mac/inc/ani_global.h +++ b/core/mac/inc/ani_global.h @@ -113,6 +113,27 @@ typedef struct sAniSirGlobal *tpAniSirGlobal; /* Minimum size of vendor IE = 3 bytes of oui_data + 1 byte of data */ #define IE_VENDOR_OUI_SIZE (4) +/* + * NSS cfg bit definition. + * STA BIT[0:1] + * SAP BIT[2:3] + * P2P_GO BIT[4:5] + * P2P_CLIENT BIT[6:7] + * IBSS BIT[8:9] + * TDLS BIT[10:11] + * P2P_DEVICE BIT[12:13] + * OCB BIT[14:15] + */ + +#define CFG_STA_NSS(_x) ((((_x) >> 0) & 0x3) ? (((_x) >> 0) & 0x3) : 1) +#define CFG_SAP_NSS(_x) ((((_x) >> 2) & 0x3) ? (((_x) >> 2) & 0x3) : 1) +#define CFG_P2P_GO_NSS(_x) ((((_x) >> 4) & 0x3) ? (((_x) >> 4) & 0x3) : 1) +#define CFG_P2P_CLI_NSS(_x) ((((_x) >> 6) & 0x3) ? (((_x) >> 6) & 0x3) : 1) +#define CFG_IBSS_NSS(_x) ((((_x) >> 8) & 0x3) ? (((_x) >> 8) & 0x3) : 1) +#define CFG_TDLS_NSS(_x) ((((_x) >> 10) & 0x3) ? (((_x) >> 10) & 0x3) : 1) +#define CFG_P2P_DEV_NSS(_x) ((((_x) >> 12) & 0x3) ? (((_x) >> 12) & 0x3) : 1) +#define CFG_OCB_NSS(_x) ((((_x) >> 14) & 0x3) ? (((_x) >> 14) & 0x3) : 1) + /** * enum log_event_type - Type of event initiating bug report * @WLAN_LOG_TYPE_NON_FATAL: Non fatal event @@ -966,6 +987,29 @@ enum auth_tx_ack_status { LIM_AUTH_ACK_RCD_SUCCESS, LIM_AUTH_ACK_RCD_FAILURE, }; +/** + * struct vdev_type_nss - vdev type nss structure + * @sta: STA Nss value. + * @sap: SAP Nss value. + * @p2p_go: P2P GO Nss value. + * @p2p_cli: P2P CLI Nss value. + * @p2p_dev: P2P device Nss value. + * @ibss: IBSS Nss value. + * @tdls: TDLS Nss value. + * @ocb: OCB Nss value. + * + * Holds the Nss values of different vdev types. + */ +struct vdev_type_nss { + uint8_t sta; + uint8_t sap; + uint8_t p2p_go; + uint8_t p2p_cli; + uint8_t p2p_dev; + uint8_t ibss; + uint8_t tdls; + uint8_t ocb; +}; /* ------------------------------------------------------------------- */ /* / MAC Sirius parameter structure */ @@ -1027,6 +1071,10 @@ typedef struct sAniSirGlobal { hdd_ftm_msg_processor ftm_msg_processor_callback; bool policy_manager_enabled; uint32_t fine_time_meas_cap; + /* per band chain mask support */ + bool per_band_chainmask_supp; + struct vdev_type_nss vdev_type_nss_2g; + struct vdev_type_nss vdev_type_nss_5g; /* 802.11p enable */ bool enable_dot11p; diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index b99b359f6dc0..4e07bf4e37cb 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -42,8 +42,8 @@ #define QWLAN_VERSION_MINOR 1 #define QWLAN_VERSION_PATCH 0 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 12 +#define QWLAN_VERSION_BUILD 13 -#define QWLAN_VERSIONSTR "5.1.0.12" +#define QWLAN_VERSIONSTR "5.1.0.13" #endif /* QWLAN_VERSION_H */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c0b33c94f2a1..c24ec17fcb3f 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -3657,6 +3657,9 @@ typedef struct sSirUpdateChanParam { typedef struct sSirUpdateChan { uint8_t numChan; + uint8_t ht_en; + uint8_t vht_en; + uint8_t vht_24_en; tSirUpdateChanParam chanParam[1]; } tSirUpdateChanList, *tpSirUpdateChanList; @@ -4712,6 +4715,24 @@ struct sir_ipa_offload_enable_disable { uint32_t enable; }; +/** + * struct sir_set_ht_vht_cfg - ht, vht IE config + * @msg_type: message type + * @len: message length + * @pdev_id: pdev id + * @nss: Nss value + * @dot11mode: Dot11 mode. + * + * Message wrapper structure for set HT/VHT IE req. + */ +struct sir_set_ht_vht_cfg { + uint16_t msg_type; + uint16_t len; + uint32_t pdev_id; + uint32_t nss; + uint32_t dot11mode; +}; + /*--------------------------------------------------------------------------- WLAN_HAL_LL_NOTIFY_STATS ---------------------------------------------------------------------------*/ diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h index 596f55889671..4aaac567966b 100644 --- a/core/mac/inc/sir_mac_prot_def.h +++ b/core/mac/inc/sir_mac_prot_def.h @@ -390,7 +390,13 @@ #define SIR_MAC_VHT_OPMODE_EID 199 #define SIR_MAC_MAX_SUPPORTED_MCS_SET 16 +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 + #define VHT_MCS_1x1 0xFFFC +#define VHT_MCS_2x2 0xFFF3 #ifdef FEATURE_AP_MCC_CH_AVOIDANCE #define SIR_MAC_QCOM_VENDOR_EID 200 diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index e6dfb2dda66a..160ada158e40 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -250,6 +250,7 @@ enum eWniMsgTypes { eWNI_SME_SET_ANTENNA_MODE_RESP, eWNI_SME_TSF_EVENT, eWNI_SME_MON_INIT_SESSION, + eWNI_SME_PDEV_SET_HT_VHT_IE, eWNI_SME_MSG_TYPES_END }; diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h index 215667673307..7019d99d319a 100644 --- a/core/mac/src/include/parser_api.h +++ b/core/mac/src/include/parser_api.h @@ -55,6 +55,9 @@ #define IS_2X2_CHAIN(__chain) ((__chain & 0x3) == 0x3) #define DISABLE_NSS2_MCS 0xC +#define NSS_1x1_MODE 1 +#define NSS_2x2_MODE 2 + #ifdef FEATURE_AP_MCC_CH_AVOIDANCE #define QCOM_VENDOR_IE_MCC_AVOID_CH 0x01 diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 476e4a68b752..26910c801fb4 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -611,6 +611,7 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_SET_WISA_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 343) #define SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 344) +#define SIR_HAL_SET_PDEV_IE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 345) #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) /* CFG message types */ diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h index a5bf8f77f0b3..8f3f118cd429 100644 --- a/core/mac/src/pe/include/lim_session.h +++ b/core/mac/src/pe/include/lim_session.h @@ -475,6 +475,7 @@ typedef struct sPESession /* Added to Support BT-AMP */ bool add_bss_failed; /* To hold OBSS Scan IE Parameters */ struct obss_scanparam obss_ht40_scanparam; + uint8_t vdev_nss; /* Supported NSS is intersection of self and peer NSS */ bool supported_nss_1x1; bool is_ext_caps_present; diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c index 7144f945af41..2a1dfec655e9 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.c +++ b/core/mac/src/pe/lim/lim_assoc_utils.c @@ -1409,8 +1409,8 @@ tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal mac_ctx, QDF_MIN(rates->vhtRxHighestDataRate, peer_vht_caps->rxHighSupDataRate); - if (mac_ctx->roam.configParam.enable2x2) { - if (session_entry && mac_ctx->lteCoexAntShare && + if (session_entry && session_entry->vdev_nss == 2) { + if (mac_ctx->lteCoexAntShare && IS_24G_CH(session_entry->currentOperChannel)) { if (IS_2X2_CHAIN(session_entry->chainMask)) mcs_map_mask2x2 = MCSMAPMASK2x2; @@ -1627,6 +1627,8 @@ lim_populate_own_rate_set(tpAniSirGlobal mac_ctx, return eSIR_FAILURE; } + if (session_entry->vdev_nss == 1) + rates->supportedMCSSet[1] = 0; /* * if supported MCS Set of the peer is passed in, * then do the intersection @@ -1766,8 +1768,12 @@ lim_populate_peer_rate_set(tpAniSirGlobal pMac, ) return eSIR_FAILURE; } - /* if supported MCS Set of the peer is passed in, then do the intersection */ - /* else use the MCS set from local CFG. */ + if (psessionEntry->vdev_nss == 1) + pRates->supportedMCSSet[1] = 0; + + /* if supported MCS Set of the peer is passed in, then do the + * intersection, else use the MCS set from local CFG. + */ if (pSupportedMCSSet != NULL) { for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) pRates->supportedMCSSet[i] &= @@ -1991,6 +1997,9 @@ tSirRetStatus lim_populate_matching_rate_set(tpAniSirGlobal mac_ctx, return eSIR_FAILURE; } + if (session_entry->vdev_nss == 1) + mcs_set[1] = 0; + for (i = 0; i < val; i++) sta_ds->supportedRates.supportedMCSSet[i] = mcs_set[i] & supported_mcs_set[i]; diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c index bebe8120dafc..d8031c2c5bfa 100644 --- a/core/mac/src/pe/lim/lim_process_message_queue.c +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -1414,6 +1414,7 @@ void lim_process_messages(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) msg->bodyptr = NULL; } break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: case eWNI_SME_SYS_READY_IND: case eWNI_SME_JOIN_REQ: case eWNI_SME_REASSOC_REQ: diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index e58f60020122..f2d1d99ad968 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -116,7 +116,6 @@ static void lim_process_update_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); extern void pe_register_wma_handle(tpAniSirGlobal pMac, tSirSmeReadyReq *ready_req); - static void lim_process_ext_change_channel(tpAniSirGlobal mac_ctx, uint32_t *msg); @@ -224,7 +223,7 @@ static QDF_STATUS lim_process_set_dual_mac_cfg_req(tpAniSirGlobal mac, req_msg = qdf_mem_malloc(len); if (!req_msg) { - lim_log(mac, LOGE, FL("vos_mem_malloc failed")); + lim_log(mac, LOGE, FL("qdf_mem_malloc failed")); /* Free the active command list * Probably the malloc is going to fail there as well?! */ @@ -631,6 +630,7 @@ __lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) uint8_t sme_session_id = 0; uint16_t sme_transaction_id = 0; uint32_t chanwidth; + struct vdev_type_nss *vdev_type_nss; tSirRetStatus cfg_get_wmi_dfs_master_param = eSIR_SUCCESS; /* FEATURE_WLAN_DIAG_SUPPORT */ @@ -779,10 +779,6 @@ __lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) session->vhtCapability); session->txLdpcIniFeatureEnabled = sme_start_bss_req->txLdpcIniFeatureEnabled; - if (mac_ctx->roam.configParam.enable2x2) - session->nss = 2; - else - session->nss = 1; #ifdef WLAN_FEATURE_11W session->limRmfEnabled = sme_start_bss_req->pmfCapable ? 1 : 0; @@ -797,6 +793,11 @@ __lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) (void *)&sme_start_bss_req->extendedRateSet, sizeof(tSirMacRateSet)); + if (IS_5G_CH(session->currentOperChannel)) + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + switch (sme_start_bss_req->bssType) { case eSIR_INFRA_AP_MODE: lim_configure_ap_start_bss_session(mac_ctx, session, @@ -806,6 +807,9 @@ __lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) sme_start_bss_req->txbf_ini_enabled; session->txbf_csn_value = sme_start_bss_req->txbf_csn_val; + session->vdev_nss = vdev_type_nss->sap; + } else { + session->vdev_nss = vdev_type_nss->p2p_go; } break; case eSIR_IBSS_MODE: @@ -819,6 +823,7 @@ __lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) * will be updated upon key installation */ session->encryptType = eSIR_ED_NONE; + session->vdev_nss = vdev_type_nss->ibss; break; @@ -834,6 +839,9 @@ __lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) break; } + lim_log(mac_ctx, LOG1, FL("persona - %d, nss - %d"), + session->pePersona, session->vdev_nss); + session->nss = session->vdev_nss; /* * Allocate memory for the array of * parsed (Re)Assoc request structure @@ -1202,7 +1210,8 @@ static QDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, uint8_t *ht_cap_ie; tSirMsgQ msg; uint16_t i, len; - uint16_t ht_cap_len = 0, addn_ie_len = 0; + uint16_t ht_cap_len = 0; + uint16_t addn_ie_len = 0; uint8_t *vht_cap_ie; uint16_t vht_cap_len = 0; tSirRetStatus status, rc = eSIR_SUCCESS; @@ -1236,29 +1245,30 @@ static QDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, * so allocate the memory for (numChannels - 1) and uIEFieldLen */ len = sizeof(tSirScanOffloadReq) + - (pScanReq->channelList.numChannels - 1) + pScanReq->uIEFieldLen; - - if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) { - lim_log(pMac, LOG1, - FL("Adding HT Caps IE since dot11mode=%d"), - pScanReq->dot11mode); - /* 2 bytes for EID and Length */ - ht_cap_len = 2 + sizeof(tHtCaps); - len += ht_cap_len; - addn_ie_len += ht_cap_len; - } + (pScanReq->channelList.numChannels - 1) + + pScanReq->uIEFieldLen; + if (!pMac->per_band_chainmask_supp) { + if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) { + lim_log(pMac, LOG1, FL( + "Adding HT Caps IE since dot11mode=%d"), + pScanReq->dot11mode); + /* 2 bytes for EID and Length */ + ht_cap_len = 2 + sizeof(tHtCaps); + len += ht_cap_len; + addn_ie_len += ht_cap_len; + } - if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) { - lim_log(pMac, LOG1, - FL("Adding VHT Caps IE since dot11mode=%d"), - pScanReq->dot11mode); - /* 2 bytes for EID and Length */ - vht_cap_len = 2 + sizeof(tSirMacVHTCapabilityInfo) + - sizeof(tSirVhtMcsInfo); - len += vht_cap_len; - addn_ie_len += vht_cap_len; + if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) { + lim_log(pMac, LOG1, FL( + "Adding VHT Caps IE since dot11mode=%d"), + pScanReq->dot11mode); + /* 2 bytes for EID and Length */ + vht_cap_len = 2 + sizeof(tSirMacVHTCapabilityInfo) + + sizeof(tSirVhtMcsInfo); + len += vht_cap_len; + addn_ie_len += vht_cap_len; + } } - pScanOffloadReq = qdf_mem_malloc(len); if (NULL == pScanOffloadReq) { lim_log(pMac, LOGE, @@ -1331,33 +1341,33 @@ static QDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, pScanOffloadReq->uIEFieldOffset, (uint8_t *) pScanReq + pScanReq->uIEFieldOffset, pScanReq->uIEFieldLen); + if (!pMac->per_band_chainmask_supp) { + /* Copy HT Capability info if dot11mode is HT */ + if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) { + /* Populate EID and Length field here */ + ht_cap_ie = (uint8_t *) pScanOffloadReq + + pScanOffloadReq->uIEFieldOffset + + pScanOffloadReq->uIEFieldLen; + qdf_mem_set(ht_cap_ie, ht_cap_len, 0); + *ht_cap_ie = SIR_MAC_HT_CAPABILITIES_EID; + *(ht_cap_ie + 1) = ht_cap_len - 2; + lim_set_ht_caps(pMac, NULL, ht_cap_ie, ht_cap_len); + pScanOffloadReq->uIEFieldLen += ht_cap_len; + } - /* Copy HT Capability info if dot11mode is HT */ - if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) { - /* Populate EID and Length field here */ - ht_cap_ie = (uint8_t *) pScanOffloadReq + - pScanOffloadReq->uIEFieldOffset + - pScanOffloadReq->uIEFieldLen; - qdf_mem_set(ht_cap_ie, ht_cap_len, 0); - *ht_cap_ie = SIR_MAC_HT_CAPABILITIES_EID; - *(ht_cap_ie + 1) = ht_cap_len - 2; - lim_set_ht_caps(pMac, NULL, ht_cap_ie, ht_cap_len); - pScanOffloadReq->uIEFieldLen += ht_cap_len; - } - - /* Copy VHT Capability info if dot11mode is VHT Capable */ - if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) { - /* Populate EID and Length field here */ - vht_cap_ie = (uint8_t *) pScanOffloadReq + - pScanOffloadReq->uIEFieldOffset + - pScanOffloadReq->uIEFieldLen; - qdf_mem_set(vht_cap_ie, vht_cap_len, 0); - *vht_cap_ie = SIR_MAC_VHT_CAPABILITIES_EID; - *(vht_cap_ie + 1) = vht_cap_len - 2; - lim_set_vht_caps(pMac, NULL, vht_cap_ie, vht_cap_len); - pScanOffloadReq->uIEFieldLen += vht_cap_len; + /* Copy VHT Capability info if dot11mode is VHT Capable */ + if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) { + /* Populate EID and Length field here */ + vht_cap_ie = (uint8_t *) pScanOffloadReq + + pScanOffloadReq->uIEFieldOffset + + pScanOffloadReq->uIEFieldLen; + qdf_mem_set(vht_cap_ie, vht_cap_len, 0); + *vht_cap_ie = SIR_MAC_VHT_CAPABILITIES_EID; + *(vht_cap_ie + 1) = vht_cap_len - 2; + lim_set_vht_caps(pMac, NULL, vht_cap_ie, vht_cap_len); + pScanOffloadReq->uIEFieldLen += vht_cap_len; + } } - rc = wma_post_ctrl_msg(pMac, &msg); if (rc != eSIR_SUCCESS) { lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure")); @@ -1570,6 +1580,7 @@ __lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) uint16_t ie_len; uint8_t *vendor_ie; tSirBssDescription *bss_desc; + struct vdev_type_nss *vdev_type_nss; /* FEATURE_WLAN_DIAG_SUPPORT */ #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM @@ -1750,10 +1761,23 @@ __lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) session->supported_nss_1x1, session->pePersona, sme_join_req->cbMode); - if (mac_ctx->roam.configParam.enable2x2) - session->nss = 2; + + /*Store Persona */ + session->pePersona = sme_join_req->staPersona; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("PE PERSONA=%d cbMode %u"), + session->pePersona, sme_join_req->cbMode); + /* Copy The channel Id to the session Table */ + session->currentOperChannel = bss_desc->channelId; + if (IS_5G_CH(session->currentOperChannel)) + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; else - session->nss = 1; + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + if (session->pePersona == QDF_P2P_CLIENT_MODE) + session->vdev_nss = vdev_type_nss->p2p_cli; + else + session->vdev_nss = vdev_type_nss->sta; + session->nss = session->vdev_nss; session->vhtCapability = IS_DOT11_MODE_VHT(session->dot11mode); if (session->vhtCapability) { @@ -1801,8 +1825,6 @@ __lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) /*Phy mode */ session->gLimPhyMode = bss_desc->nwType; handle_ht_capabilityand_ht_info(mac_ctx, session); - /* Copy The channel Id to the session Table */ - session->currentOperChannel = bss_desc->channelId; /* cbMode is already merged value of peer and self - * done by csr in csr_get_cb_mode_from_ies */ session->htSupportedChannelWidthSet = @@ -4698,6 +4720,179 @@ static void lim_register_mgmt_frame_ind_cb(tpAniSirGlobal mac_ctx, } /** + * lim_set_pdev_ht_ie() - sends the set HT IE req to FW + * @mac_ctx: Pointer to Global MAC structure + * @pdev_id: pdev id to set the IE. + * @nss: Nss values to prepare the HT IE. + * + * Prepares the HT IE with self capabilities for different + * Nss values and sends the set HT IE req to FW. + * + * Return: None + */ +static void lim_set_pdev_ht_ie(tpAniSirGlobal mac_ctx, uint8_t pdev_id, + uint8_t nss) +{ + struct set_ie_param *ie_params; + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + uint8_t *p_ie = NULL; + tHtCaps *p_ht_cap; + int i; + + for (i = nss; i > 0; i--) { + ie_params = qdf_mem_malloc(sizeof(*ie_params)); + if (NULL == ie_params) { + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + ie_params->nss = i; + ie_params->pdev_id = pdev_id; + ie_params->ie_type = DOT11_HT_IE; + /* 2 for IE len and EID */ + ie_params->ie_len = 2 + sizeof(tHtCaps); + ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len); + if (NULL == ie_params->ie_ptr) { + qdf_mem_free(ie_params); + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + *ie_params->ie_ptr = SIR_MAC_HT_CAPABILITIES_EID; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_ht_caps(mac_ctx, NULL, ie_params->ie_ptr, + ie_params->ie_len); + + if (NSS_1x1_MODE == i) { + p_ie = lim_get_ie_ptr_new(mac_ctx, ie_params->ie_ptr, + ie_params->ie_len, + DOT11F_EID_HTCAPS, ONE_BYTE); + p_ht_cap = (tHtCaps *)&p_ie[2]; + p_ht_cap->supportedMCSSet[1] = 0; + p_ht_cap->txSTBC = 0; + } + + msg.type = WMA_SET_PDEV_IE_REQ; + msg.bodyptr = ie_params; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("wma_post_ctrl_msg() return failure")); + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + return; + } + } +} + +/** + * lim_set_pdev_vht_ie() - sends the set VHT IE to req FW + * @mac_ctx: Pointer to Global MAC structure + * @pdev_id: pdev id to set the IE. + * @nss: Nss values to prepare the VHT IE. + * + * Prepares the VHT IE with self capabilities for different + * Nss values and sends the set VHT IE req to FW. + * + * Return: None + */ +static void lim_set_pdev_vht_ie(tpAniSirGlobal mac_ctx, uint8_t pdev_id, + uint8_t nss) +{ + struct set_ie_param *ie_params; + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + uint8_t *p_ie = NULL; + tSirMacVHTCapabilityInfo *vht_cap; + int i; + tSirVhtMcsInfo *vht_mcs; + + for (i = nss; i > 0; i--) { + ie_params = qdf_mem_malloc(sizeof(*ie_params)); + if (NULL == ie_params) { + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + ie_params->nss = i; + ie_params->pdev_id = pdev_id; + ie_params->ie_type = DOT11_VHT_IE; + /* 2 for IE len and EID */ + ie_params->ie_len = 2 + sizeof(tSirMacVHTCapabilityInfo) + + sizeof(tSirVhtMcsInfo); + ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len); + if (NULL == ie_params->ie_ptr) { + qdf_mem_free(ie_params); + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + *ie_params->ie_ptr = SIR_MAC_VHT_CAPABILITIES_EID; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_vht_caps(mac_ctx, NULL, ie_params->ie_ptr, + ie_params->ie_len); + + if (NSS_1x1_MODE == i) { + p_ie = lim_get_ie_ptr_new(mac_ctx, ie_params->ie_ptr, + ie_params->ie_len, + DOT11F_EID_VHTCAPS, ONE_BYTE); + vht_cap = (tSirMacVHTCapabilityInfo *)&p_ie[2]; + vht_cap->txSTBC = 0; + vht_mcs = + (tSirVhtMcsInfo *)&p_ie[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + vht_mcs->rxMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->rxHighest = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + vht_mcs->txMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->txHighest = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + msg.type = WMA_SET_PDEV_IE_REQ; + msg.bodyptr = ie_params; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("wma_post_ctrl_msg failure")); + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + return; + } + } +} + +/** + * lim_process_set_pdev_IEs() - process the set pdev IE req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to the SME message buffer + * + * This function is called by limProcessMessageQueue(). This + * function sets the PDEV IEs to the FW. + * + * Return: None + */ +static void lim_process_set_pdev_IEs(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + struct sir_set_ht_vht_cfg *ht_vht_cfg; + + ht_vht_cfg = (struct sir_set_ht_vht_cfg *)msg_buf; + + if (NULL == ht_vht_cfg) { + lim_log(mac_ctx, LOGE, FL("NULL ht_vht_cfg")); + return; + } + + lim_log(mac_ctx, LOG1, FL("rcvd set pdev ht vht ie req with nss = %d"), + ht_vht_cfg->nss); + lim_set_pdev_ht_ie(mac_ctx, ht_vht_cfg->pdev_id, ht_vht_cfg->nss); + + if (IS_DOT11_MODE_VHT(ht_vht_cfg->dot11mode)) + lim_set_pdev_vht_ie(mac_ctx, ht_vht_cfg->pdev_id, + ht_vht_cfg->nss); +} + +/** * lim_process_sme_req_messages() * ***FUNCTION: @@ -4938,6 +5133,9 @@ bool lim_process_sme_req_messages(tpAniSirGlobal pMac, tpSirMsgQ pMsg) case eWNI_SME_SET_ANTENNA_MODE_REQ: lim_process_set_antenna_mode_req(pMac, pMsgBuf); break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: + lim_process_set_pdev_IEs(pMac, pMsgBuf); + break; default: qdf_mem_free((void *)pMsg->bodyptr); pMsg->bodyptr = NULL; diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index b2ebe12ecef1..ec75fca557b2 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -804,8 +804,9 @@ QDF_STATUS wlansap_set_wps_ie(void *p_cds_gctx, tSap_WPSIE *pWPSIe); QDF_STATUS wlansap_update_wps_ie(void *p_cds_gctx); QDF_STATUS wlansap_stop_Wps(void *p_cds_gctx); QDF_STATUS wlansap_get_wps_state(void *p_cds_gctx, bool *pbWPSState); - void *wlansap_open(void *p_cds_gctx); +QDF_STATUS wlansap_global_init(void); +QDF_STATUS wlansap_global_deinit(void); QDF_STATUS wlansap_start(void *p_cds_gctx, enum tQDF_ADAPTER_MODE mode, uint8_t *addr, uint32_t *session_id); QDF_STATUS wlansap_stop(void *p_cds_gctx); diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c index a541031a9141..d0b3a00582c0 100644 --- a/core/sap/src/sap_api_link_cntl.c +++ b/core/sap/src/sap_api_link_cntl.c @@ -808,20 +808,24 @@ wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId, eRoamCmdStatus roam_status, eCsrRoamResult roam_result) { /* sap_ctx value */ - ptSapContext sap_ctx = (ptSapContext) ctx; + ptSapContext sap_ctx; /* State machine event */ tWLAN_SAPEvent sap_event; QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; - tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tHalHandle hal; tpAniSirGlobal mac_ctx = NULL; uint8_t intf; - if (NULL == hal) { + if (QDF_IS_STATUS_ERROR(wlansap_context_get((ptSapContext)ctx))) + return QDF_STATUS_E_FAILURE; + + sap_ctx = (ptSapContext) ctx; + hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + if (!hal) { QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, - FL("Invalid hal")); - qdf_ret_status = QDF_STATUS_E_NOMEM; - return qdf_ret_status; + FL("Invalid handle")); + return QDF_STATUS_E_NOMEM; } mac_ctx = PMAC_STRUCT(hal); @@ -1214,5 +1218,6 @@ wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId, roam_result); break; } + wlansap_context_put(sap_ctx); return qdf_ret_status; } diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c index 0db2f1e618fc..0297953b7144 100644 --- a/core/sap/src/sap_fsm.c +++ b/core/sap/src/sap_fsm.c @@ -2375,7 +2375,7 @@ QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context, * Return: QDF_STATUS */ -#define SAP_OPEN_SESSION_TIMEOUT 500 +#define SAP_OPEN_SESSION_TIMEOUT 2000 QDF_STATUS sap_open_session(tHalHandle hHal, ptSapContext sapContext, uint32_t *session_id) { diff --git a/core/sap/src/sap_internal.h b/core/sap/src/sap_internal.h index 435fcb52854e..29ae041764a8 100644 --- a/core/sap/src/sap_internal.h +++ b/core/sap/src/sap_internal.h @@ -269,8 +269,6 @@ typedef struct sSapContext { /*---------------------------------------------------------------------------- * External declarations for global context * -------------------------------------------------------------------------*/ -/* The main per-Physical Link (per WLAN association) context. */ -extern ptSapContext gp_sap_ctx; /*---------------------------------------------------------------------------- * SAP state machine event definition @@ -290,6 +288,8 @@ typedef struct sWLAN_SAPEvent { /*---------------------------------------------------------------------------- * Function Declarations and Documentation * -------------------------------------------------------------------------*/ +QDF_STATUS wlansap_context_get(ptSapContext ctx); +void wlansap_context_put(ptSapContext ctx); QDF_STATUS wlansap_scan_callback diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index b75f71e4d269..9965c2b8ff7c 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -44,6 +44,7 @@ * -------------------------------------------------------------------------*/ #include "qdf_trace.h" #include "qdf_util.h" +#include "qdf_atomic.h" /* Pick up the sme callback registration API */ #include "sme_api.h" @@ -73,11 +74,13 @@ * -------------------------------------------------------------------------*/ /* No! Get this from CDS. */ /* The main per-Physical Link (per WLAN association) context. */ -ptSapContext gp_sap_ctx; +static ptSapContext gp_sap_ctx[SAP_MAX_NUM_SESSION]; +static qdf_atomic_t sap_ctx_ref_count[SAP_MAX_NUM_SESSION]; /*---------------------------------------------------------------------------- * Static Variable Definitions * -------------------------------------------------------------------------*/ +static qdf_mutex_t sap_context_lock; /*---------------------------------------------------------------------------- * Static Function Declarations and Definitions @@ -92,6 +95,159 @@ ptSapContext gp_sap_ctx; * -------------------------------------------------------------------------*/ /** + * wlansap_global_init() - Initialize SAP globals + * + * Initializes the SAP global data structures + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_global_init(void) +{ + uint32_t i; + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create(&sap_context_lock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "failed to init sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + gp_sap_ctx[i] = NULL; + qdf_atomic_init(&sap_ctx_ref_count[i]); + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap global context initialized", __func__); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_global_deinit() - De-initialize SAP globals + * + * De-initializes the SAP global data structures + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_global_deinit(void) +{ + uint32_t i; + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i]) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "we could be leaking context:%d", i); + } + gp_sap_ctx[i] = NULL; + qdf_atomic_init(&sap_ctx_ref_count[i]); + } + + if (QDF_IS_STATUS_ERROR(qdf_mutex_destroy(&sap_context_lock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "failed to destroy sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap global context deinitialized", __func__); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_save_context() - Save the context in global SAP context + * @ctx: SAP context to be stored + * + * Stores the given SAP context in the global SAP context array + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlansap_save_context(ptSapContext ctx) +{ + uint32_t i; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i] == NULL) { + gp_sap_ctx[i] = ctx; + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap context saved at index:%d", + __func__, i); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to save sap context", __func__); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_context_get() - Verify SAP context and increment ref count + * @ctx: Context to be checked + * + * Verifies the SAP context and increments the reference count maintained for + * the corresponding SAP context. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_context_get(ptSapContext ctx) +{ + uint32_t i; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (ctx && (gp_sap_ctx[i] == ctx)) { + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: sap session is not valid", __func__); + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_context_put() - Check the reference count and free SAP context + * @ctx: SAP context to be checked and freed + * + * Checks the reference count and frees the SAP context + * + * Return: None + */ +void wlansap_context_put(ptSapContext ctx) +{ + uint32_t i; + + if (!ctx) + return; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i] == ctx) { + if (qdf_atomic_dec_and_test(&sap_ctx_ref_count[i])) { + qdf_mem_free(ctx); + gp_sap_ctx[i] = NULL; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s: sap session freed: %d", + __func__, i); + } + qdf_mutex_release(&sap_context_lock); + return; + } + } + qdf_mutex_release(&sap_context_lock); +} + +/** * wlansap_open() - WLAN SAP open function call * @p_cds_gctx: Pointer to the global cds context; a handle to SAP's * @@ -104,6 +260,7 @@ ptSapContext gp_sap_ctx; void *wlansap_open(void *p_cds_gctx) { ptSapContext pSapCtx = NULL; + QDF_STATUS status; /* dynamically allocate the sapContext */ pSapCtx = (ptSapContext) qdf_mem_malloc(sizeof(tSapContext)); @@ -122,8 +279,14 @@ void *wlansap_open(void *p_cds_gctx) /* Setup the "link back" to the CDS context */ pSapCtx->p_cds_gctx = p_cds_gctx; - /* Store a pointer to the SAP context provided by CDS */ - gp_sap_ctx = pSapCtx; + /* Save the SAP context pointer */ + status = wlansap_save_context(pSapCtx); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to save SAP context", __func__); + qdf_mem_free(pSapCtx); + return NULL; + } return pSapCtx; } /* wlansap_open */ @@ -296,7 +459,7 @@ QDF_STATUS wlansap_close(void *pCtx) /* empty queues/lists/pkts if any */ wlansap_clean_cb(pSapCtx, true); - qdf_mem_free(pSapCtx); + wlansap_context_put(pSapCtx); return QDF_STATUS_SUCCESS; } /* wlansap_close */ diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 6cebcff38770..11557c7b237f 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -82,6 +82,7 @@ #define SME_CONFIG_TO_ROAM_CONFIG 1 #define ROAM_CONFIG_TO_SME_CONFIG 2 +#define NUM_OF_BANDS 2 /*-------------------------------------------------------------------------- Type declarations ------------------------------------------------------------------------*/ @@ -1123,4 +1124,8 @@ uint32_t sme_get_wni_dot11_mode(tHalHandle hal); QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid); QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, struct adaptive_dwelltime_params *dwelltime_params); +void sme_set_pdev_ht_vht_ies(tHalHandle hHal, bool enable2x2); + +void sme_update_vdev_type_nss(tHalHandle hal, uint8_t max_supp_nss, + uint32_t vdev_type_nss, eCsrBand band); #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_inside.h b/core/sme/inc/sme_inside.h index cf5614ded55d..5a6600a7d983 100644 --- a/core/sme/inc/sme_inside.h +++ b/core/sme/inc/sme_inside.h @@ -230,6 +230,9 @@ QDF_STATUS oem_data_process_oem_data_req_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); #endif +void csr_get_vdev_type_nss(tpAniSirGlobal mac_ctx, + enum tQDF_ADAPTER_MODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g); QDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); QDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 011227bd8b6b..e8abaa9ed318 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -15112,6 +15112,7 @@ void sme_update_tgt_services(tHalHandle hal, struct wma_tgt_services *cfg) tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); mac_ctx->lteCoexAntShare = cfg->lte_coex_ant_share; + mac_ctx->per_band_chainmask_supp = cfg->per_band_chainmask_supp; mac_ctx->beacon_offload = cfg->beacon_offload; mac_ctx->pmf_offload = cfg->pmf_offload; QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, @@ -15576,7 +15577,6 @@ QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, tSirMacAddr bss_id) return status; } - /** * sme_set_adaptive_dwelltime_config() - Update Adaptive dwelltime configuration * @hal: The handle returned by macOpen @@ -15616,3 +15616,110 @@ QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, } return status; } +/** + * sme_set_pdev_ht_vht_ies() - sends the set pdev IE req + * @hal: Pointer to HAL + * @enable2x2: 1x1 or 2x2 mode. + * + * Sends the set pdev IE req with Nss value. + * + * Return: None + */ +void sme_set_pdev_ht_vht_ies(tHalHandle hal, bool enable2x2) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct sir_set_ht_vht_cfg *ht_vht_cfg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!mac_ctx->per_band_chainmask_supp) + return; + + if (!((mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY))) + return; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + ht_vht_cfg = qdf_mem_malloc(sizeof(*ht_vht_cfg)); + if (NULL == ht_vht_cfg) { + sms_log(mac_ctx, LOGE, + "%s: mem alloc failed for ht_vht_cfg", + __func__); + sme_release_global_lock(&mac_ctx->sme); + return; + } + + ht_vht_cfg->pdev_id = 0; + if (enable2x2) + ht_vht_cfg->nss = 2; + else + ht_vht_cfg->nss = 1; + ht_vht_cfg->dot11mode = + (uint8_t)csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + mac_ctx->roam.configParam.uCfgDot11Mode); + + ht_vht_cfg->msg_type = eWNI_SME_PDEV_SET_HT_VHT_IE; + ht_vht_cfg->len = sizeof(*ht_vht_cfg); + sms_log(mac_ctx, LOG1, + FL("SET_HT_VHT_IE with nss %d, dot11mode %d"), + ht_vht_cfg->nss, + ht_vht_cfg->dot11mode); + status = cds_send_mb_message_to_mac(ht_vht_cfg); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL( + "Send SME_PDEV_SET_HT_VHT_IE fail")); + qdf_mem_free(ht_vht_cfg); + } + sme_release_global_lock(&mac_ctx->sme); + } + return; +} + +/** + * sme_update_vdev_type_nss() - sets the nss per vdev type + * @hal: Pointer to HAL + * @max_supp_nss: max_supported Nss + * @band: 5G or 2.4G band + * + * Sets the per band Nss for each vdev type based on INI and configured + * chain mask value. + * + * Return: None + */ +void sme_update_vdev_type_nss(tHalHandle hal, uint8_t max_supp_nss, + uint32_t vdev_type_nss, eCsrBand band) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct vdev_type_nss *vdev_nss; + + if (eCSR_BAND_5G == band) + vdev_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_nss = &mac_ctx->vdev_type_nss_2g; + + vdev_nss->sta = QDF_MIN(max_supp_nss, CFG_STA_NSS(vdev_type_nss)); + vdev_nss->sap = QDF_MIN(max_supp_nss, CFG_SAP_NSS(vdev_type_nss)); + vdev_nss->p2p_go = QDF_MIN(max_supp_nss, + CFG_P2P_GO_NSS(vdev_type_nss)); + vdev_nss->p2p_cli = QDF_MIN(max_supp_nss, + CFG_P2P_CLI_NSS(vdev_type_nss)); + vdev_nss->p2p_dev = QDF_MIN(max_supp_nss, + CFG_P2P_DEV_NSS(vdev_type_nss)); + vdev_nss->ibss = QDF_MIN(max_supp_nss, CFG_IBSS_NSS(vdev_type_nss)); + vdev_nss->tdls = QDF_MIN(max_supp_nss, CFG_TDLS_NSS(vdev_type_nss)); + vdev_nss->ocb = QDF_MIN(max_supp_nss, CFG_OCB_NSS(vdev_type_nss)); + + sms_log(mac_ctx, LOG1, + "band %d NSS:sta %d sap %d cli %d go %d dev %d ibss %d tdls %d ocb %d", + band, vdev_nss->sta, vdev_nss->sap, vdev_nss->p2p_cli, + vdev_nss->p2p_go, vdev_nss->p2p_dev, vdev_nss->ibss, + vdev_nss->tdls, vdev_nss->ocb); +} diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index e2a35a7ca335..4de79eb91df9 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -754,6 +754,24 @@ QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, FL("Early Stop Scan Feature not supported")); + if ((pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY)) { + pChanList->vht_en = true; + if (pMac->roam.configParam.enableVhtFor24GHz) + pChanList->vht_24_en = true; + } + if ((pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY)) { + pChanList->ht_en = true; + } msg.type = WMA_UPDATE_CHAN_LIST_REQ; msg.reserved = 0; msg.bodyptr = pChanList; @@ -14853,6 +14871,59 @@ QDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) return QDF_STATUS_SUCCESS; } +/** + * csr_get_vdev_type_nss() - gets the nss value based on vdev type + * @mac_ctx: Pointer to Global MAC structure + * @dev_mode: current device operating mode. + * @nss2g: Pointer to the 2G Nss parameter. + * @nss5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on device mode. + * + * Return: None + */ +void csr_get_vdev_type_nss(tpAniSirGlobal mac_ctx, + enum tQDF_ADAPTER_MODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + switch (dev_mode) { + case QDF_STA_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.sta; + *nss_5g = mac_ctx->vdev_type_nss_5g.sta; + break; + case QDF_SAP_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.sap; + *nss_5g = mac_ctx->vdev_type_nss_5g.sap; + break; + case QDF_P2P_CLIENT_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_cli; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_cli; + break; + case QDF_P2P_GO_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_go; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_go; + break; + case QDF_P2P_DEVICE_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_dev; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_dev; + break; + case QDF_IBSS_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ibss; + *nss_5g = mac_ctx->vdev_type_nss_5g.ibss; + break; + case QDF_OCB_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ocb; + *nss_5g = mac_ctx->vdev_type_nss_5g.ocb; + break; + default: + *nss_2g = 1; + *nss_5g = 1; + sms_log(mac_ctx, LOGE, FL("Unknown device mode")); + break; + } + sms_log(mac_ctx, LOG1, FL("mode - %d: nss_2g - %d, 5g - %d"), + dev_mode, *nss_2g, *nss_5g); +} QDF_STATUS csr_issue_add_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId, tSirMacAddr sessionMacAddr, uint32_t type, uint32_t subType) @@ -14888,6 +14959,8 @@ QDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, &pCommand->u.addStaSessionCmd; uint8_t sessionId = pCommand->sessionId; struct add_sta_self_params *add_sta_self_req; + uint8_t nss_2g; + uint8_t nss_5g; QDF_STATUS status = QDF_STATUS_E_NOMEM; tSirMsgQ msg; @@ -14899,12 +14972,16 @@ QDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, return status; } + csr_get_vdev_type_nss(pMac, pAddStaReq->currDeviceMode, + &nss_2g, &nss_5g); qdf_mem_copy(add_sta_self_req->self_mac_addr, pAddStaReq->selfMacAddr, sizeof(tSirMacAddr)); add_sta_self_req->curr_device_mode = pAddStaReq->currDeviceMode; add_sta_self_req->session_id = sessionId; add_sta_self_req->type = pAddStaReq->type; add_sta_self_req->sub_type = pAddStaReq->subType; + add_sta_self_req->nss_2g = nss_2g; + add_sta_self_req->nss_5g = nss_5g; msg.type = WMA_ADD_STA_SELF_REQ; msg.reserved = 0; diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 153cd68d7356..0850c946a6c8 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -466,6 +466,28 @@ enum wma_rx_exec_ctx { WMA_RX_TASKLET_CTX, WMA_RX_SERIALIZER_CTX }; + +/** + * enum wma_phy_idx + * @PHY1: to notify caller that PHY1 specific param needed + * @PHY2: to notify caller that PHY2 specific param needed + * @PHY1_PHY2: to notify caller that both PHY's param needed + * Note: Firmware sends phy map in terms of bitmask, so enum + * also needs to be defined that way. + * + * For example, 0x3 = 0011 = BIT0 corresponds to one phy and + * BIT1 coresponds to another phy. There is no direct relation between + * each bit to particular PHY (ex. PHYA or PHYB). + * + * In simple terms, 3 means referring both PHYs & 1 or 2 means + * referring to either PHYA or PHYB. + */ +enum wma_phy_idx { + PHY1 = 0x1, /* 0x1 */ + PHY2, /* 0x2 */ + PHY1_PHY2, /* 0x3 */ +}; + /** * struct wma_mem_chunk - memory chunks * @vaddr: virtual address @@ -913,6 +935,8 @@ struct wma_txrx_node { uint32_t mac_id; bool roaming_in_progress; int32_t roam_synch_delay; + uint8_t nss_2g; + uint8_t nss_5g; }; #if defined(QCA_WIFI_FTM) @@ -1061,6 +1085,34 @@ struct wma_valid_channels { uint8_t channel_list[MAX_NUM_CHAN]; }; +/** + * struct hw_mode_idx_to_mac_cap_idx - map between hw_mode to capabilities + * @num_of_macs: number of macs/PHYs for given hw_mode through hw_mode_id + * @mac_cap_idx: index of the mac/PHY for given hw_mode through hw_mode_id + * @hw_mode_id: given hw_mode id + */ +struct hw_mode_idx_to_mac_cap_idx { + uint8_t num_of_macs; + uint8_t mac_cap_idx; + uint8_t hw_mode_id; +}; + +/** + * struct extended_caps - new extended caps given by firmware + * @num_hw_modes: number of hardware modes for current SOC + * @each_hw_mode_cap: hw mode id to phy id mapping + * @each_phy_cap_per_hwmode: PHY's caps for each hw mode + * @num_phy_for_hal_reg_cap: number of phy for hal reg cap + * @hw_mode_to_mac_cap_map: map between hw_mode to capabilities + */ +struct extended_caps { + WMI_SOC_MAC_PHY_HW_MODE_CAPS num_hw_modes; + WMI_HW_MODE_CAPABILITIES *each_hw_mode_cap; + WMI_MAC_PHY_CAPABILITIES *each_phy_cap_per_hwmode; + WMI_SOC_HAL_REG_CAPABILITIES num_phy_for_hal_reg_cap; + WMI_HAL_REG_CAPABILITIES_EXT *each_phy_hal_reg_cap; + struct hw_mode_idx_to_mac_cap_idx *hw_mode_to_mac_cap_map; +}; /** * struct t_wma_handle - wma context @@ -1162,6 +1214,7 @@ struct wma_valid_channels { * @dbs_mode: DBS HW mode list * @old_hw_mode_index: Previous configured HW mode index * @new_hw_mode_index: Current configured HW mode index + * @extended_caps phy_caps: extended caps per hw mode * @peer_authorized_cb: peer authorized hdd callback * @ocb_callback: callback to OCB commands * @ocb_resp: response to OCB commands @@ -1322,6 +1375,7 @@ typedef struct { struct dbs_hw_mode_info hw_mode; uint32_t old_hw_mode_index; uint32_t new_hw_mode_index; + struct extended_caps phy_caps; qdf_atomic_t scan_id_counter; wma_peer_authorized_fp peer_authorized_cb; uint32_t wow_pno_match_wake_up_count; @@ -2055,9 +2109,16 @@ QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, int wma_get_bpf_caps_event_handler(void *handle, u_int8_t *cmd_param_info, u_int32_t len); +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask); QDF_STATUS wma_get_bpf_capabilities(tp_wma_handle wma); QDF_STATUS wma_set_bpf_instructions(tp_wma_handle wma, struct sir_bpf_set_offload *bpf_set_offload); +void wma_process_set_pdev_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); #endif struct wma_ini_config *wma_get_ini_handle(tp_wma_handle wma_handle); WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, diff --git a/core/wma/inc/wma_if.h b/core/wma/inc/wma_if.h index ea7be4ba6d09..1d3cb68d4468 100644 --- a/core/wma/inc/wma_if.h +++ b/core/wma/inc/wma_if.h @@ -509,6 +509,8 @@ typedef struct { uint8_t nonRoamReassoc; uint8_t wps_state; uint8_t nss; + uint8_t nss_2g; + uint8_t nss_5g; } tAddBssParams, *tpAddBssParams; /** @@ -1144,6 +1146,8 @@ typedef struct sMaxTxPowerPerBandParams { * @type: Vdev Type * @sub_type: Vdev Sub Type * @session_id: SME Session ID + * @nss_2g: vdev nss in 2.4G + * @nss_5g: vdev nss in 5G * @status: response status code */ struct add_sta_self_params { @@ -1152,9 +1156,32 @@ struct add_sta_self_params { uint32_t type; uint32_t sub_type; uint8_t session_id; + uint8_t nss_2g; + uint8_t nss_5g; uint32_t status; }; +/** + * struct set_ie_param - set IE params structure + * @pdev_id: pdev id + * @ie_type: IE type + * @nss: Nss value + * @ie_len: IE length + * @ie_ptr: Pointer to IE data + * + * Holds the set pdev IE req data. + */ +struct set_ie_param { + uint8_t pdev_id; + uint8_t ie_type; + uint8_t nss; + uint8_t ie_len; + uint8_t *ie_ptr; +}; + +#define DOT11_HT_IE 1 +#define DOT11_VHT_IE 2 + #ifdef FEATURE_WLAN_TDLS #define HAL_TDLS_MAX_SUPP_CHANNELS 128 diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 3ea0fe060e0c..a62a99cf6127 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -429,6 +429,11 @@ static inline bool wma_is_roam_synch_in_progress(tp_wma_handle wma, { return false; } +static inline uint32_t wma_roam_scan_get_cckm_mode( + struct sSirRoamOffloadScanReq *roam_req, uint32_t auth_mode) +{ + return WMI_AUTH_CCKM; +} #endif /* diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h index e6a8c86a9f80..0afcf52de27b 100644 --- a/core/wma/inc/wma_tgt_cfg.h +++ b/core/wma/inc/wma_tgt_cfg.h @@ -67,6 +67,8 @@ struct wma_tgt_services { #ifdef WLAN_FEATURE_ROAM_OFFLOAD bool en_roam_offload; #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + /* per band chain mask support */ + bool per_band_chainmask_supp; }; /** diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 53af2d267a25..3b2120ed9ee6 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -472,9 +472,10 @@ #define WMA_REMOVE_BCN_FILTER_CMDID SIR_HAL_REMOVE_BCN_FILTER_CMDID #define WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS -#define WDA_BPF_GET_CAPABILITIES_REQ SIR_HAL_BPF_GET_CAPABILITIES_REQ -#define WDA_BPF_SET_INSTRUCTIONS_REQ SIR_HAL_BPF_SET_INSTRUCTIONS_REQ +#define WDA_BPF_GET_CAPABILITIES_REQ SIR_HAL_BPF_GET_CAPABILITIES_REQ +#define WDA_BPF_SET_INSTRUCTIONS_REQ SIR_HAL_BPF_SET_INSTRUCTIONS_REQ +#define WMA_SET_PDEV_IE_REQ SIR_HAL_SET_PDEV_IE_REQ /* Bit 6 will be used to control BD rate for Management frames */ #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index d7040f577fca..e5fb871525a5 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -1485,6 +1485,8 @@ ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle, params.if_id = self_sta_req->session_id; params.type = self_sta_req->type; params.subtype = self_sta_req->sub_type; + params.nss_2g = self_sta_req->nss_2g; + params.nss_5g = self_sta_req->nss_5g; /* Create a vdev in target */ status = wmi_unified_vdev_create_send(wma_handle->wmi_handle, diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index d73b338bdb2b..6d96bf91e3de 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -3051,7 +3051,7 @@ static QDF_STATUS wma_add_wow_wakeup_event(tp_wma_handle wma, int ret; ret = wmi_unified_add_wow_wakeup_event_cmd(wma->wmi_handle, vdev_id, - enable, bitmap); + bitmap, enable); if (ret) { WMA_LOGE("Failed to config wow wakeup event"); return QDF_STATUS_E_FAILURE; diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index da68b5df928c..a62af7827aa0 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3112,6 +3112,46 @@ QDF_STATUS wma_wmi_work_close(void *cds_ctx) return QDF_STATUS_SUCCESS; } +/** + * wma_cleanup_dbs_phy_caps() - release memory allocated for holding ext cap + * @wma_handle: pointer to wma handle + * + * This function releases all the memory created for holding extended + * capabilities per hardware mode and per PHY + * + * Return: void + */ +static void wma_cleanup_dbs_phy_caps(t_wma_handle *wma_handle) +{ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + if (wma_handle->phy_caps.hw_mode_to_mac_cap_map) { + qdf_mem_free(wma_handle->phy_caps.hw_mode_to_mac_cap_map); + wma_handle->phy_caps.hw_mode_to_mac_cap_map = NULL; + WMA_LOGI("%s: hw_mode_to_mac_cap_map freed", __func__); + } + + if (wma_handle->phy_caps.each_hw_mode_cap) { + qdf_mem_free(wma_handle->phy_caps.each_hw_mode_cap); + wma_handle->phy_caps.each_hw_mode_cap = NULL; + WMA_LOGI("%s: each_hw_mode_cap freed", __func__); + } + + if (wma_handle->phy_caps.each_phy_cap_per_hwmode) { + qdf_mem_free(wma_handle->phy_caps.each_phy_cap_per_hwmode); + wma_handle->phy_caps.each_phy_cap_per_hwmode = NULL; + WMA_LOGI("%s: each_phy_cap_per_hwmode freed", __func__); + } + + if (wma_handle->phy_caps.each_phy_hal_reg_cap) { + qdf_mem_free(wma_handle->phy_caps.each_phy_hal_reg_cap); + wma_handle->phy_caps.each_phy_hal_reg_cap = NULL; + WMA_LOGI("%s: each_phy_hal_reg_cap freed", __func__); + } +} /** * wma_close() - wma close function. @@ -3148,7 +3188,7 @@ QDF_STATUS wma_close(void *cds_ctx) wma_handle->hw_mode.hw_mode_list = NULL; WMA_LOGI("%s: DBS list is freed", __func__); } - + wma_cleanup_dbs_phy_caps(wma_handle); if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { #ifdef FEATURE_WLAN_SCAN_PNO qdf_wake_lock_destroy(&wma_handle->pno_wake_lock); @@ -3397,6 +3437,9 @@ static inline void wma_update_target_services(tp_wma_handle wh, cfg->en_tdls_uapsd_sleep_sta = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_TDLS_UAPSD_SLEEP_STA); + cfg->per_band_chainmask_supp = + WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_PER_BAND_CHAINMASK_SUPPORT); #endif /* FEATURE_WLAN_TDLS */ if (WMI_SERVICE_IS_ENABLED (wh->wmi_service_bitmap, WMI_SERVICE_BEACON_OFFLOAD)) @@ -3519,6 +3562,301 @@ static inline void wma_update_target_vht_cap(tp_wma_handle wh, } /** + * wma_derive_ext_ht_cap() - Derive HT caps based on given value + * @wma_handle: pointer to wma_handle + * @ht_cap: given pointer to HT caps which needs to be updated + * @tx_chain: given tx chainmask value + * @rx_chain: given rx chainmask value + * @value: new HT cap info provided in form of bitmask + * + * This function takes the value provided in form of bitmask and decodes + * it. After decoding, what ever value it gets, it takes the union(max) or + * intersection(min) with previously derived values. + * + * Return: none + * + */ +static void wma_derive_ext_ht_cap(tp_wma_handle wma_handle, + struct wma_tgt_ht_cap *ht_cap, uint32_t value, + uint32_t tx_chain, uint32_t rx_chain) +{ + struct wma_tgt_ht_cap tmp = {0}; + + if (NULL == wma_handle || NULL == ht_cap) + return; + + if (0 == qdf_mem_cmp(ht_cap, &tmp, sizeof(struct wma_tgt_ht_cap))) { + ht_cap->ht_rx_stbc = (!!(value & WMI_HT_CAP_RX_STBC)); + ht_cap->ht_tx_stbc = (!!(value & WMI_HT_CAP_TX_STBC)); + ht_cap->mpdu_density = (!!(value & WMI_HT_CAP_MPDU_DENSITY)); + ht_cap->ht_rx_ldpc = (!!(value & WMI_HT_CAP_RX_LDPC)); + ht_cap->ht_sgi_20 = (!!(value & WMI_HT_CAP_HT20_SGI)); + ht_cap->ht_sgi_40 = (!!(value & WMI_HT_CAP_HT40_SGI)); + ht_cap->num_rf_chains = + QDF_MAX(wma_get_num_of_setbits_from_bitmask(tx_chain), + wma_get_num_of_setbits_from_bitmask(rx_chain)); + } else { + ht_cap->ht_rx_stbc = QDF_MIN(ht_cap->ht_rx_stbc, + (!!(value & WMI_HT_CAP_RX_STBC))); + ht_cap->ht_tx_stbc = QDF_MAX(ht_cap->ht_tx_stbc, + (!!(value & WMI_HT_CAP_TX_STBC))); + ht_cap->mpdu_density = QDF_MIN(ht_cap->mpdu_density, + (!!(value & WMI_HT_CAP_MPDU_DENSITY))); + ht_cap->ht_rx_ldpc = QDF_MIN(ht_cap->ht_rx_ldpc, + (!!(value & WMI_HT_CAP_RX_LDPC))); + ht_cap->ht_sgi_20 = QDF_MIN(ht_cap->ht_sgi_20, + (!!(value & WMI_HT_CAP_HT20_SGI))); + ht_cap->ht_sgi_40 = QDF_MIN(ht_cap->ht_sgi_40, + (!!(value & WMI_HT_CAP_HT40_SGI))); + ht_cap->num_rf_chains = + QDF_MAX(ht_cap->num_rf_chains, + QDF_MAX(wma_get_num_of_setbits_from_bitmask( + tx_chain), + wma_get_num_of_setbits_from_bitmask( + rx_chain))); + } +} + +/** + * wma_update_target_ext_ht_cap() - Update HT caps with given extended cap + * @wma_handle: pointer to wma_handle + * @ht_cap: HT cap structure to be filled + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * HT caps and derives the final cap. + * + * Return: none + * + */ +static void wma_update_target_ext_ht_cap(tp_wma_handle wma_handle, + struct wma_tgt_ht_cap *ht_cap) +{ + int i, j = 0, max_mac; + uint32_t ht_2g, ht_5g; + struct wma_tgt_ht_cap tmp_ht_cap = {0}, tmp_cap = {0}; + struct extended_caps *phy_caps; + WMI_MAC_PHY_CAPABILITIES *mac_cap; + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!wma_handle || + (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes)) { + WMA_LOGI("%s: No extended HT cap for current SOC", __func__); + return; + } + + phy_caps = &wma_handle->phy_caps; + for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) { + if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2) + max_mac = j + 2; + else + max_mac = j + 1; + for ( ; j < max_mac; j++) { + mac_cap = &phy_caps->each_phy_cap_per_hwmode[j]; + ht_2g = mac_cap->ht_cap_info_2G; + ht_5g = mac_cap->ht_cap_info_5G; + if (ht_2g) + wma_derive_ext_ht_cap(wma_handle, &tmp_ht_cap, + ht_2g, mac_cap->tx_chain_mask_2G, + mac_cap->rx_chain_mask_2G); + if (ht_5g) + wma_derive_ext_ht_cap(wma_handle, &tmp_ht_cap, + ht_5g, mac_cap->tx_chain_mask_5G, + mac_cap->rx_chain_mask_5G); + } + } + + if (0 != qdf_mem_cmp(&tmp_cap, &tmp_ht_cap, + sizeof(struct wma_tgt_ht_cap))) { + qdf_mem_copy(ht_cap, &tmp_ht_cap, + sizeof(struct wma_tgt_ht_cap)); + } + + WMA_LOGI("%s: [ext ht cap] ht_rx_stbc - %d, ht_tx_stbc - %d\n\ + mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n\ + ht_sgi_40 - %d num_rf_chains - %d ", __func__, + ht_cap->ht_rx_stbc, ht_cap->ht_tx_stbc, + ht_cap->mpdu_density, ht_cap->ht_rx_ldpc, + ht_cap->ht_sgi_20, ht_cap->ht_sgi_40, + ht_cap->num_rf_chains); +} + +/** + * wma_derive_ext_vht_cap() - Derive VHT caps based on given value + * @wma_handle: pointer to wma_handle + * @vht_cap: pointer to given VHT caps to be filled + * @value: new VHT cap info provided in form of bitmask + * + * This function takes the value provided in form of bitmask and decodes + * it. After decoding, what ever value it gets, it takes the union(max) or + * intersection(min) with previously derived values. + * + * Return: none + * + */ +static void wma_derive_ext_vht_cap(t_wma_handle *wma_handle, + struct wma_tgt_vht_cap *vht_cap, uint32_t value) +{ + struct wma_tgt_vht_cap tmp_cap = {0}; + uint32_t tmp = 0; + + if (NULL == wma_handle || NULL == vht_cap) + return; + + if (0 == qdf_mem_cmp(vht_cap, &tmp_cap, + sizeof(struct wma_tgt_vht_cap))) { + if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + vht_cap->vht_max_mpdu = 0; + + if (value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) { + vht_cap->supp_chan_width = + 1 << eHT_CHANNEL_WIDTH_80P80MHZ; + vht_cap->supp_chan_width |= + 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + vht_cap->supp_chan_width = + 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + vht_cap->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + vht_cap->vht_rx_ldpc = value & WMI_VHT_CAP_RX_LDPC; + vht_cap->vht_short_gi_80 = value & WMI_VHT_CAP_SGI_80MHZ; + vht_cap->vht_short_gi_160 = value & WMI_VHT_CAP_SGI_160MHZ; + vht_cap->vht_tx_stbc = value & WMI_VHT_CAP_TX_STBC; + vht_cap->vht_rx_stbc = + (value & WMI_VHT_CAP_RX_STBC_1SS) | + (value & WMI_VHT_CAP_RX_STBC_2SS) | + (value & WMI_VHT_CAP_RX_STBC_3SS); + vht_cap->vht_max_ampdu_len_exp = + (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >> + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT; + vht_cap->vht_su_bformer = value & WMI_VHT_CAP_SU_BFORMER; + vht_cap->vht_su_bformee = value & WMI_VHT_CAP_SU_BFORMEE; + vht_cap->vht_mu_bformer = value & WMI_VHT_CAP_MU_BFORMER; + vht_cap->vht_mu_bformee = value & WMI_VHT_CAP_MU_BFORMEE; + vht_cap->vht_txop_ps = value & WMI_VHT_CAP_TXOP_PS; + } else { + if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + tmp = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + tmp = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + tmp = 0; + vht_cap->vht_max_mpdu = QDF_MIN(vht_cap->vht_max_mpdu, tmp); + + if ((value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)) { + tmp = (1 << eHT_CHANNEL_WIDTH_80P80MHZ) | + (1 << eHT_CHANNEL_WIDTH_160MHZ); + } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + tmp = 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + tmp = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + vht_cap->supp_chan_width = + QDF_MAX(vht_cap->supp_chan_width, tmp); + vht_cap->vht_rx_ldpc = QDF_MIN(vht_cap->vht_rx_ldpc, + value & WMI_VHT_CAP_RX_LDPC); + vht_cap->vht_short_gi_80 = QDF_MAX(vht_cap->vht_short_gi_80, + value & WMI_VHT_CAP_SGI_80MHZ); + vht_cap->vht_short_gi_160 = QDF_MAX(vht_cap->vht_short_gi_160, + value & WMI_VHT_CAP_SGI_160MHZ); + vht_cap->vht_tx_stbc = QDF_MAX(vht_cap->vht_tx_stbc, + value & WMI_VHT_CAP_TX_STBC); + vht_cap->vht_rx_stbc = QDF_MIN(vht_cap->vht_rx_stbc, + (value & WMI_VHT_CAP_RX_STBC_1SS) | + (value & WMI_VHT_CAP_RX_STBC_2SS) | + (value & WMI_VHT_CAP_RX_STBC_3SS)); + vht_cap->vht_max_ampdu_len_exp = + QDF_MIN(vht_cap->vht_max_ampdu_len_exp, + (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >> + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT); + vht_cap->vht_su_bformer = QDF_MAX(vht_cap->vht_su_bformer, + value & WMI_VHT_CAP_SU_BFORMER); + vht_cap->vht_su_bformee = QDF_MAX(vht_cap->vht_su_bformee, + value & WMI_VHT_CAP_SU_BFORMEE); + vht_cap->vht_mu_bformer = QDF_MAX(vht_cap->vht_mu_bformer, + value & WMI_VHT_CAP_MU_BFORMER); + vht_cap->vht_mu_bformee = QDF_MAX(vht_cap->vht_mu_bformee, + value & WMI_VHT_CAP_MU_BFORMEE); + vht_cap->vht_txop_ps = QDF_MIN(vht_cap->vht_txop_ps, + value & WMI_VHT_CAP_TXOP_PS); + } +} + +/** + * wma_update_target_ext_vht_cap() - Update VHT caps with given extended cap + * @wma_handle: pointer to wma_handle + * @vht_cap: VHT cap structure to be filled + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * VHT caps and derives the final cap. + * + * Return: none + * + */ +static void wma_update_target_ext_vht_cap(t_wma_handle *wma_handle, + struct wma_tgt_vht_cap *vht_cap) +{ + int i, j = 0, max_mac; + uint32_t vht_cap_info_2g, vht_cap_info_5g; + struct wma_tgt_vht_cap tmp_vht_cap = {0}, tmp_cap = {0}; + struct extended_caps *phy_caps; + WMI_MAC_PHY_CAPABILITIES *mac_cap; + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!wma_handle || + (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes)) { + WMA_LOGI("%s: No extended VHT cap for current SOC", __func__); + return; + } + + phy_caps = &wma_handle->phy_caps; + for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) { + if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2) + max_mac = j + 2; + else + max_mac = j + 1; + for ( ; j < max_mac; j++) { + mac_cap = &phy_caps->each_phy_cap_per_hwmode[j]; + vht_cap_info_2g = mac_cap->vht_cap_info_2G; + vht_cap_info_5g = mac_cap->vht_cap_info_5G; + if (vht_cap_info_2g) + wma_derive_ext_vht_cap(wma_handle, &tmp_vht_cap, + vht_cap_info_2g); + if (vht_cap_info_5g) + wma_derive_ext_vht_cap(wma_handle, &tmp_vht_cap, + vht_cap_info_5g); + } + } + + if (0 != qdf_mem_cmp(&tmp_cap, &tmp_vht_cap, + sizeof(struct wma_tgt_vht_cap))) { + qdf_mem_copy(vht_cap, &tmp_vht_cap, + sizeof(struct wma_tgt_vht_cap)); + } + + WMA_LOGI("%s: [ext vhtcap] max_mpdu %d supp_chan_width %x rx_ldpc %x\n \ + short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n \ + su_bformee %x mu_bformee %x max_ampdu_len_exp %d", __func__, + vht_cap->vht_max_mpdu, vht_cap->supp_chan_width, + vht_cap->vht_rx_ldpc, vht_cap->vht_short_gi_80, + vht_cap->vht_tx_stbc, vht_cap->vht_rx_stbc, + vht_cap->vht_txop_ps, vht_cap->vht_su_bformee, + vht_cap->vht_mu_bformee, vht_cap->vht_max_ampdu_len_exp); +} + +/** * wma_update_hdd_cfg() - update HDD config * @wma_handle: wma handle * @@ -3557,6 +3895,12 @@ static void wma_update_hdd_cfg(tp_wma_handle wma_handle) wma_update_target_services(wma_handle, &tgt_cfg.services); wma_update_target_ht_cap(wma_handle, &tgt_cfg.ht_cap); wma_update_target_vht_cap(wma_handle, &tgt_cfg.vht_cap); + /* + * This will overwrite the structure filled by wma_update_target_ht_cap + * and wma_update_target_vht_cap APIs. + */ + wma_update_target_ext_ht_cap(wma_handle, &tgt_cfg.ht_cap); + wma_update_target_ext_vht_cap(wma_handle, &tgt_cfg.vht_cap); tgt_cfg.target_fw_version = wma_handle->target_fw_version; #ifdef WLAN_FEATURE_LPSS @@ -4047,6 +4391,225 @@ int wma_rx_service_ready_event(void *handle, uint8_t *cmd_param_info, } /** + * wma_print_populate_soc_caps() - Prints all the caps populated per hw mode + * @wma_handle: pointer to wma_handle + * + * This function prints all the caps populater per hw mode and per PHY + * + * Return: none + */ +static void wma_print_populate_soc_caps(t_wma_handle *wma_handle) +{ + int i, j = 0, max_mac; + WMI_MAC_PHY_CAPABILITIES *tmp; + + /* print number of hw modes */ + WMA_LOGI("%s: num of hw modes [%d]", __func__, + wma_handle->phy_caps.num_hw_modes.num_hw_modes); + WMA_LOGI("%s: <====== HW mode cap printing starts ======>", __func__); + /* print cap of each hw mode */ + for (i = 0; i < wma_handle->phy_caps.num_hw_modes.num_hw_modes; i++) { + WMA_LOGI("====>: hw mode id[%d], phy_id map[%d]", + wma_handle->phy_caps.each_hw_mode_cap[i].hw_mode_id, + wma_handle->phy_caps.each_hw_mode_cap[i].phy_id_map); + if (wma_handle->phy_caps.each_hw_mode_cap[i].phy_id_map == + PHY1_PHY2) + max_mac = j + 2; + else + max_mac = j + 1; + + for ( ; j < max_mac; j++) { + tmp = &wma_handle->phy_caps.each_phy_cap_per_hwmode[j]; + WMA_LOGI("\t: index j[%d]", j); + WMA_LOGI("\t: cap for hw_mode_id[%d]", tmp->hw_mode_id); + WMA_LOGI("\t: pdev_id[%d]", tmp->pdev_id); + WMA_LOGI("\t: phy_id[%d]", tmp->phy_id); + WMA_LOGI("\t: supports_11b[%d]", + WMI_SUPPORT_11B_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11g[%d]", + WMI_SUPPORT_11G_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11a[%d]", + WMI_SUPPORT_11A_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11n[%d]", + WMI_SUPPORT_11N_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11ac[%d]", + WMI_SUPPORT_11AC_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11ax[%d]", + WMI_SUPPORT_11AX_GET(tmp->supported_flags)); + WMA_LOGI("\t: supported_flags[%d]", + tmp->supported_flags); + WMA_LOGI("\t: supported_bands[%d]", + tmp->supported_bands); + WMA_LOGI("\t: ampdu_density[%d]", + tmp->ampdu_density); + WMA_LOGI("\t: max_bw_supported_2G[%d]", + tmp->max_bw_supported_2G); + WMA_LOGI("\t: ht_cap_info_2G[%d]", tmp->ht_cap_info_2G); + WMA_LOGI("\t: vht_cap_info_2G[%d]", + tmp->vht_cap_info_2G); + WMA_LOGI("\t: he_cap_info_2G[%d]", tmp->he_cap_info_2G); + WMA_LOGI("\t: vht_supp_mcs_2G[%d]", + tmp->vht_supp_mcs_2G); + WMA_LOGI("\t: he_supp_mcs_2G[%d]", tmp->he_supp_mcs_2G); + WMA_LOGI("\t: tx_chain_mask_2G[%d]", + tmp->tx_chain_mask_2G); + WMA_LOGI("\t: rx_chain_mask_2G[%d]", + tmp->rx_chain_mask_2G); + WMA_LOGI("\t: max_bw_supported_5G[%d]", + tmp->max_bw_supported_5G); + WMA_LOGI("\t: ht_cap_info_5G[%d]", + tmp->ht_cap_info_5G); + WMA_LOGI("\t: vht_cap_info_5G[%d]", + tmp->vht_cap_info_5G); + WMA_LOGI("\t: he_cap_info_5G[%d]", tmp->he_cap_info_5G); + WMA_LOGI("\t: vht_supp_mcs_5G[%d]", + tmp->vht_supp_mcs_5G); + WMA_LOGI("\t: he_supp_mcs_5G[%d]", tmp->he_supp_mcs_5G); + WMA_LOGI("\t: tx_chain_mask_5G[%d]", + tmp->tx_chain_mask_5G); + WMA_LOGI("\t: rx_chain_mask_5G[%d]", + tmp->rx_chain_mask_5G); + } + } + WMA_LOGI("%s: <====== HW mode cap printing ends ======>\n", __func__); +} + +/** + * wma_populate_soc_caps() - populate entire SOC's capabilities + * @wma_handle: pointer to wma global structure + * @param_buf: pointer to param of service ready extension event from fw + * + * This API populates all capabilities of entire SOC. For example, + * how many number of hw modes are supported by this SOC, what are the + * capabilities of each phy per hw mode, what are HAL reg capabilities per + * phy. + * + * Return: none + */ +static void wma_populate_soc_caps(t_wma_handle *wma_handle, + WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *param_buf) +{ + int i, num_of_mac_caps = 0, tmp = 0; + struct extended_caps *phy_caps; + struct hw_mode_idx_to_mac_cap_idx *map; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma_handle) { + WMA_LOGP("%s: Invalid WMA handle", __func__); + return; + } + + if (!param_buf) { + WMA_LOGP("%s: Invalid event", __func__); + return; + } + phy_caps = &wma_handle->phy_caps; + + /* + * first thing to do is to get how many number of hw modes are + * supported and populate in wma_handle global structure + */ + qdf_mem_copy(&phy_caps->num_hw_modes, + param_buf->soc_hw_mode_caps, + sizeof(WMI_SOC_MAC_PHY_HW_MODE_CAPS)); + if (0 == phy_caps->num_hw_modes.num_hw_modes) { + WMA_LOGE("%s: Invalid number of hw modes", __func__); + return; + } else { + WMA_LOGI("%s: Given number of hw modes[%d]", + __func__, phy_caps->num_hw_modes.num_hw_modes); + } + + /* + * next thing is to allocate the memory to map hw mode to phy/mac caps + */ + phy_caps->hw_mode_to_mac_cap_map = + qdf_mem_malloc(phy_caps->num_hw_modes.num_hw_modes * + sizeof(struct hw_mode_idx_to_mac_cap_idx)); + if (!phy_caps->hw_mode_to_mac_cap_map) { + WMA_LOGE("%s: Memory allocation failed", __func__); + return; + } + + /* + * next thing is to allocate the memory for per hw caps + */ + phy_caps->each_hw_mode_cap = + qdf_mem_malloc(phy_caps->num_hw_modes.num_hw_modes * + sizeof(WMI_HW_MODE_CAPABILITIES)); + if (!phy_caps->each_hw_mode_cap) { + WMA_LOGE("%s: Memory allocation failed", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + qdf_mem_copy(phy_caps->each_hw_mode_cap, + param_buf->hw_mode_caps, + phy_caps->num_hw_modes.num_hw_modes * + sizeof(WMI_HW_MODE_CAPABILITIES)); + /* + * next thing is to count the number of mac cap to populate per + * hw mode and generate map, so that our search can be done + * efficiently which is O(1) + */ + for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) { + map = &phy_caps->hw_mode_to_mac_cap_map[i]; + if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2) { + tmp = num_of_mac_caps; + num_of_mac_caps = num_of_mac_caps + 2; + map->num_of_macs = 2; + } else { + tmp = num_of_mac_caps; + num_of_mac_caps = num_of_mac_caps + 1; + map->num_of_macs = 1; + } + map->mac_cap_idx = tmp; + map->hw_mode_id = phy_caps->each_hw_mode_cap[i].hw_mode_id; + } + + /* + * next thing is to populate each phy caps per hw mode + */ + phy_caps->each_phy_cap_per_hwmode = + qdf_mem_malloc(num_of_mac_caps * + sizeof(WMI_MAC_PHY_CAPABILITIES)); + if (!phy_caps->each_phy_cap_per_hwmode) { + WMA_LOGE("%s: Memory allocation failed", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + qdf_mem_copy(phy_caps->each_phy_cap_per_hwmode, + param_buf->mac_phy_caps, + num_of_mac_caps * sizeof(WMI_MAC_PHY_CAPABILITIES)); + + /* + * next thing is to populate reg caps per phy + */ + qdf_mem_copy(&phy_caps->num_phy_for_hal_reg_cap, + param_buf->soc_hal_reg_caps, + sizeof(WMI_SOC_HAL_REG_CAPABILITIES)); + if (phy_caps->num_phy_for_hal_reg_cap.num_phy == 0) { + WMA_LOGE("%s: incorrect number of phys", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + phy_caps->each_phy_hal_reg_cap = + qdf_mem_malloc(phy_caps->num_phy_for_hal_reg_cap.num_phy * + sizeof(WMI_HAL_REG_CAPABILITIES_EXT)); + if (!phy_caps->each_phy_hal_reg_cap) { + WMA_LOGE("%s: Memory allocation failed", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + qdf_mem_copy(phy_caps->each_phy_hal_reg_cap, + param_buf->hal_reg_caps, + phy_caps->num_phy_for_hal_reg_cap.num_phy * + sizeof(WMI_HAL_REG_CAPABILITIES_EXT)); + wma_print_populate_soc_caps(wma_handle); + return; +} + +/** * wma_rx_service_ready_ext_event() - evt handler for sevice ready ext event. * @handle: wma handle * @event: params of the service ready extended event @@ -4093,6 +4656,7 @@ int wma_rx_service_ready_ext_event(void *handle, uint8_t *event, WMA_LOGP("Failed to stop the service ready ext timer"); return -EINVAL; } + wma_populate_soc_caps(wma_handle, param_buf); WMA_LOGA("WMA --> WMI_INIT_CMDID"); status = wmi_unified_send_saved_init_cmd(wma_handle->wmi_handle); @@ -4710,6 +5274,11 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) (wma_cli_set_cmd_t *) msg->bodyptr); qdf_mem_free(msg->bodyptr); break; + case WMA_SET_PDEV_IE_REQ: + wma_process_set_pdev_ie_req(wma_handle, + (struct set_ie_param *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; #if !defined(REMOVE_PKT_LOG) case WMA_PKTLOG_ENABLE_REQ: wma_pktlog_wmi_send_cmd(wma_handle, diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index 6bab3975213e..b581f2fd8cf5 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -649,6 +649,8 @@ QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, tchan_info = scan_ch_param.chan_info; scan_ch_param.num_scan_chans = chan_list->numChan; wma_handle->saved_chan.num_channels = chan_list->numChan; + WMA_LOGD("ht %d, vht %d, vht_24 %d", chan_list->ht_en, + chan_list->vht_en, chan_list->vht_24_en); for (i = 0; i < chan_list->numChan; ++i) { tchan_info->mhz = @@ -668,10 +670,21 @@ QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, chan_list->chanParam[i].dfsSet); } - if (tchan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) + if (tchan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) { WMI_SET_CHANNEL_MODE(tchan_info, MODE_11G); - else + if (chan_list->vht_en && chan_list->vht_24_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_VHT); + } else { WMI_SET_CHANNEL_MODE(tchan_info, MODE_11A); + if (chan_list->vht_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_VHT); + } + + if (chan_list->ht_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_HT); if (chan_list->chanParam[i].half_rate) WMI_SET_CHANNEL_FLAG(tchan_info, @@ -1017,8 +1030,9 @@ A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, #endif /* FEATURE_WLAN_WAPI */ #ifdef FEATURE_WLAN_ESE case eCSR_AUTH_TYPE_CCKM_WPA: + return WMI_AUTH_CCKM_WPA; case eCSR_AUTH_TYPE_CCKM_RSN: - return WMI_AUTH_CCKM; + return WMI_AUTH_CCKM_RSNA; #endif /* FEATURE_WLAN_ESE */ #ifdef WLAN_FEATURE_11W case eCSR_AUTH_TYPE_RSN_PSK_SHA256: @@ -1076,6 +1090,27 @@ A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr) } } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_scan_get_cckm_mode() - Get the CCKM auth mode + * @roam_req: Roaming request buffer + * @auth_mode: Auth mode to be converted + * + * Based on LFR2.0 or LFR3.0, return the proper auth type + * + * Return: if LFR2.0, then return WMI_AUTH_CCKM for backward compatibility + * if LFR3.0 then return the appropriate auth type + */ +static uint32_t wma_roam_scan_get_cckm_mode(tSirRoamOffloadScanReq *roam_req, + uint32_t auth_mode) +{ + if (roam_req->RoamOffloadEnabled) + return auth_mode; + else + return WMI_AUTH_CCKM; + +} +#endif /** * wma_roam_scan_fill_ap_profile() - fill ap_profile * @wma_handle: wma handle @@ -1092,6 +1127,7 @@ void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, tSirRoamOffloadScanReq *roam_req, wmi_ap_profile *ap_profile_p) { + uint32_t rsn_authmode; qdf_mem_zero(ap_profile_p, sizeof(wmi_ap_profile)); if (roam_req == NULL) { ap_profile_p->ssid.ssid_len = 0; @@ -1108,8 +1144,16 @@ void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, roam_req->ConnectedNetwork.ssId.ssId, ap_profile_p->ssid.ssid_len); ap_profile_p->rsn_authmode = - e_csr_auth_type_to_rsn_authmode(roam_req->ConnectedNetwork.authentication, - roam_req->ConnectedNetwork.encryption); + e_csr_auth_type_to_rsn_authmode( + roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + rsn_authmode = ap_profile_p->rsn_authmode; + + if ((rsn_authmode == WMI_AUTH_CCKM_WPA) || + (rsn_authmode == WMI_AUTH_CCKM_RSNA)) + ap_profile_p->rsn_authmode = + wma_roam_scan_get_cckm_mode( + roam_req, rsn_authmode); ap_profile_p->rsn_ucastcipherset = e_csr_encryption_type_to_rsn_cipherset(roam_req->ConnectedNetwork.encryption); ap_profile_p->rsn_mcastcipherset = @@ -1125,6 +1169,136 @@ void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, } /** + * wma_process_set_pdev_ie_req() - process the pdev set IE req + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * + * Sends the WMI req to set the IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + if (ie_params->ie_type == DOT11_HT_IE) + wma_process_set_pdev_ht_ie_req(wma, ie_params); + if (ie_params->ie_type == DOT11_VHT_IE) + wma_process_set_pdev_vht_ie_req(wma, ie_params); + + qdf_mem_free(ie_params->ie_ptr); +} + +/** + * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * @nss: Nss values to prepare the HT IE. + * + * Sends the WMI req to set the HT IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + int ret; + wmi_pdev_set_ht_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint16_t ie_len_pad; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); + len += ie_len_pad; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_ht_ie_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->ie_len = ie_params->ie_len; + cmd->tx_streams = ie_params->nss; + cmd->rx_streams = ie_params->nss; + WMA_LOGD("Setting pdev HT ie with Nss = %u", + ie_params->nss); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); + if (ie_params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)ie_params->ie_ptr, + ie_params->ie_len); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_HT_CAP_IE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } +} + +/** + * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * @nss: Nss values to prepare the VHT IE. + * + * Sends the WMI req to set the VHT IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + int ret; + wmi_pdev_set_vht_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint16_t ie_len_pad; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); + len += ie_len_pad; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_vht_ie_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->ie_len = ie_params->ie_len; + cmd->tx_streams = ie_params->nss; + cmd->rx_streams = ie_params->nss; + WMA_LOGD("Setting pdev VHT ie with Nss = %u", + ie_params->nss); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); + if (ie_params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)ie_params->ie_ptr, + ie_params->ie_len); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_VHT_CAP_IE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } +} + +/** * wma_roam_scan_scan_params() - fill roam scan params * @wma_handle: wma handle * @pMac: Mac ptr diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index d5cb5c1219d3..dc6475e1098d 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -3383,6 +3383,25 @@ uint32_t wma_get_vht_ch_width(void) } /** + * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask + * @mask: given bitmask + * + * This helper function should return number of setbits from bitmask + * + * Return: number of setbits from bitmask + */ +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask) +{ + uint32_t num_of_setbits = 0; + + while (mask) { + mask &= (mask - 1); + num_of_setbits++; + } + return num_of_setbits; +} + +/** * wma_config_debug_module_cmd - set debug log config * @wmi_handle: wmi layer handle * @param: debug log parameter |
