Merge "qcacmn: CFR: Process PPDU status TLVs and extract CFR information"
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index 3676d53..289df96 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -1869,6 +1869,12 @@
OL_ATH_PARAM_CHAN_COEX = 427,
/* Out of Band Advertisement feature */
OL_ATH_PARAM_OOB_ENABLE = 428,
+ /* set/get opmode-notification timer for hw-mode switch */
+ OL_ATH_PARAM_HW_MODE_SWITCH_OMN_TIMER = 429,
+ /* enable opmode-notification when doing hw-mode switch */
+ OL_ATH_PARAM_HW_MODE_SWITCH_OMN_ENABLE = 430,
+ /* set primary interface for hw-mode switch */
+ OL_ATH_PARAM_HW_MODE_SWITCH_PRIMARY_IF = 431,
};
#endif
/* Bitmasks for stats that can block */
diff --git a/dp/wifi3.0/dp_ipa.c b/dp/wifi3.0/dp_ipa.c
index 980e99e..c3f4fa3 100644
--- a/dp/wifi3.0/dp_ipa.c
+++ b/dp/wifi3.0/dp_ipa.c
@@ -1802,6 +1802,69 @@
#endif
/**
+ * dp_ipa_frag_nbuf_linearize - linearize nbuf for IPA
+ * @soc: soc
+ * @nbuf: source skb
+ *
+ * Return: new nbuf if success and otherwise NULL
+ */
+static qdf_nbuf_t dp_ipa_frag_nbuf_linearize(struct dp_soc *soc,
+ qdf_nbuf_t nbuf)
+{
+ uint8_t *src_nbuf_data;
+ uint8_t *dst_nbuf_data;
+ qdf_nbuf_t dst_nbuf;
+ qdf_nbuf_t temp_nbuf = nbuf;
+ uint32_t nbuf_len = qdf_nbuf_len(nbuf);
+ bool is_nbuf_head = true;
+ uint32_t copy_len = 0;
+
+ dst_nbuf = qdf_nbuf_alloc(soc->osdev, RX_BUFFER_SIZE,
+ RX_BUFFER_RESERVATION, RX_BUFFER_ALIGNMENT,
+ FALSE);
+
+ if (!dst_nbuf) {
+ dp_err_rl("nbuf allocate fail");
+ return NULL;
+ }
+
+ if ((nbuf_len + L3_HEADER_PADDING) > RX_BUFFER_SIZE) {
+ qdf_nbuf_free(dst_nbuf);
+ dp_err_rl("nbuf is jumbo data");
+ return NULL;
+ }
+
+ /* prepeare to copy all data into new skb */
+ dst_nbuf_data = qdf_nbuf_data(dst_nbuf);
+ while (temp_nbuf) {
+ src_nbuf_data = qdf_nbuf_data(temp_nbuf);
+ /* first head nbuf */
+ if (is_nbuf_head) {
+ qdf_mem_copy(dst_nbuf_data, src_nbuf_data,
+ RX_PKT_TLVS_LEN);
+ /* leave extra 2 bytes L3_HEADER_PADDING */
+ dst_nbuf_data += (RX_PKT_TLVS_LEN + L3_HEADER_PADDING);
+ src_nbuf_data += RX_PKT_TLVS_LEN;
+ copy_len = qdf_nbuf_headlen(temp_nbuf) -
+ RX_PKT_TLVS_LEN;
+ temp_nbuf = qdf_nbuf_get_ext_list(temp_nbuf);
+ is_nbuf_head = false;
+ } else {
+ copy_len = qdf_nbuf_len(temp_nbuf);
+ temp_nbuf = qdf_nbuf_queue_next(temp_nbuf);
+ }
+ qdf_mem_copy(dst_nbuf_data, src_nbuf_data, copy_len);
+ dst_nbuf_data += copy_len;
+ }
+
+ qdf_nbuf_set_len(dst_nbuf, nbuf_len);
+ /* copy is done, free original nbuf */
+ qdf_nbuf_free(nbuf);
+
+ return dst_nbuf;
+}
+
+/**
* dp_ipa_handle_rx_reo_reinject - Handle RX REO reinject skb buffer
* @soc: soc
* @nbuf: skb
@@ -1810,7 +1873,6 @@
*/
qdf_nbuf_t dp_ipa_handle_rx_reo_reinject(struct dp_soc *soc, qdf_nbuf_t nbuf)
{
- uint8_t *rx_pkt_tlvs;
if (!wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx))
return nbuf;
@@ -1819,33 +1881,11 @@
if (!qdf_atomic_read(&soc->ipa_pipes_enabled))
return nbuf;
- /* Linearize the skb since IPA assumes linear buffer */
- if (qdf_likely(qdf_nbuf_is_frag(nbuf))) {
- if (qdf_nbuf_linearize(nbuf)) {
- dp_err_rl("nbuf linearize failed");
- return NULL;
- }
- }
+ if (!qdf_nbuf_is_frag(nbuf))
+ return nbuf;
- rx_pkt_tlvs = qdf_mem_malloc(RX_PKT_TLVS_LEN);
- if (!rx_pkt_tlvs) {
- dp_err_rl("rx_pkt_tlvs alloc failed");
- return NULL;
- }
-
- qdf_mem_copy(rx_pkt_tlvs, qdf_nbuf_data(nbuf), RX_PKT_TLVS_LEN);
-
- /* Pad L3_HEADER_PADDING before ethhdr and after rx_pkt_tlvs */
- qdf_nbuf_push_head(nbuf, L3_HEADER_PADDING);
-
- qdf_mem_copy(qdf_nbuf_data(nbuf), rx_pkt_tlvs, RX_PKT_TLVS_LEN);
-
- /* L3_HEADDING_PADDING is not accounted for real skb length */
- qdf_nbuf_set_len(nbuf, qdf_nbuf_len(nbuf) - L3_HEADER_PADDING);
-
- qdf_mem_free(rx_pkt_tlvs);
-
- return nbuf;
+ /* linearize skb for IPA */
+ return dp_ipa_frag_nbuf_linearize(soc, nbuf);
}
#endif
diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c
index c07eb1b..a4eb54a 100644
--- a/dp/wifi3.0/dp_peer.c
+++ b/dp/wifi3.0/dp_peer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -1740,8 +1740,12 @@
} else {
dp_set_ssn_valid_flag(¶ms, 0);
}
- dp_reo_send_cmd(soc, CMD_UPDATE_RX_REO_QUEUE, ¶ms,
- dp_rx_tid_update_cb, rx_tid);
+
+ if (dp_reo_send_cmd(soc, CMD_UPDATE_RX_REO_QUEUE, ¶ms,
+ dp_rx_tid_update_cb, rx_tid)) {
+ dp_err_log("failed to send reo cmd CMD_UPDATE_RX_REO_QUEUE");
+ DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1);
+ }
rx_tid->ba_win_size = ba_window_size;
@@ -2071,6 +2075,7 @@
desc->free_ts = qdf_get_system_timestamp();
qdf_list_insert_back(&soc->reo_desc_freelist,
(qdf_list_node_t *)desc);
+ dp_err_log("failed to send reo cmd CMD_UPDATE_RX_REO_QUEUE");
DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1);
}
}
@@ -2158,9 +2163,10 @@
¶ms,
NULL,
NULL)) {
- dp_err_log("fail to send CMD_CACHE_FLUSH:"
- "tid %d desc %pK", rx_tid->tid,
- (void *)(rx_tid->hw_qdesc_paddr));
+ dp_err_rl("fail to send CMD_CACHE_FLUSH:"
+ "tid %d desc %pK", rx_tid->tid,
+ (void *)(rx_tid->hw_qdesc_paddr));
+ DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1);
}
}
@@ -2190,6 +2196,7 @@
dp_err_log("%s: fail to send REO cmd to flush cache: tid %d",
__func__, rx_tid->tid);
dp_reo_desc_clean_up(soc, desc, &reo_status);
+ DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1);
}
}
qdf_spin_unlock_bh(&soc->reo_desc_freelist_lock);
@@ -3017,9 +3024,16 @@
params.u.upd_queue_params.pn_127_96 = rx_pn[3];
}
rx_tid->pn_size = pn_size;
- dp_reo_send_cmd((struct dp_soc *)soc,
- CMD_UPDATE_RX_REO_QUEUE, ¶ms,
- dp_rx_tid_update_cb, rx_tid);
+ if (dp_reo_send_cmd(cdp_soc_t_to_dp_soc(soc),
+ CMD_UPDATE_RX_REO_QUEUE,
+ ¶ms, dp_rx_tid_update_cb,
+ rx_tid)) {
+ dp_err_log("fail to send CMD_UPDATE_RX_REO_QUEUE"
+ "tid %d desc %pK", rx_tid->tid,
+ (void *)(rx_tid->hw_qdesc_paddr));
+ DP_STATS_INC(cdp_soc_t_to_dp_soc(soc),
+ rx.err.reo_cmd_send_fail, 1);
+ }
} else {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH,
"PN Check not setup for TID :%d ", i);
@@ -3224,7 +3238,7 @@
}
peer->state = state;
- DP_TRACE(INFO, "peer %pK state %d", peer, peer->state);
+ dp_info("peer %pK state %d", peer, peer->state);
/* ref_cnt is incremented inside dp_peer_find_hash_find().
* Decrement it here.
*/
@@ -3309,7 +3323,7 @@
uint8_t *mac;
mac = peer->mac_addr.raw;
- DP_TRACE(INFO, "peer %pK mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
+ dp_info("peer %pK mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
peer, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return peer->mac_addr.raw;
}
@@ -3384,7 +3398,7 @@
pdev->local_peer_ids.map[i] = peer;
}
qdf_spin_unlock_bh(&pdev->local_peer_ids.lock);
- DP_TRACE(INFO, "peer %pK, local id %d", peer, peer->local_id);
+ dp_info("peer %pK, local id %d", peer, peer->local_id);
}
/**
diff --git a/dp/wifi3.0/dp_reo.c b/dp/wifi3.0/dp_reo.c
index ff8d337..ba1db7f 100644
--- a/dp/wifi3.0/dp_reo.c
+++ b/dp/wifi3.0/dp_reo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -91,13 +91,12 @@
break;
default:
dp_err_log("Invalid REO command type: %d", type);
- return QDF_STATUS_E_FAILURE;
+ return QDF_STATUS_E_INVAL;
};
dp_reo_cmd_srng_event_record(soc, type, num);
if (num < 0) {
- dp_err_log("Error with sending REO command type: %d", type);
return QDF_STATUS_E_FAILURE;
}
diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c
index 11dfaf6..5af6996 100644
--- a/dp/wifi3.0/dp_rx.c
+++ b/dp/wifi3.0/dp_rx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -891,13 +891,6 @@
if (soc->cdp_soc.ol_ops->rx_invalid_peer)
soc->cdp_soc.ol_ops->rx_invalid_peer(vdev->vdev_id, wh);
free:
- /* reset the head and tail pointers */
- pdev = dp_get_pdev_for_mac_id(soc, mac_id);
- if (pdev) {
- pdev->invalid_peer_head_msdu = NULL;
- pdev->invalid_peer_tail_msdu = NULL;
- }
-
/* Drop and free packet */
curr_nbuf = mpdu;
while (curr_nbuf) {
@@ -906,6 +899,13 @@
curr_nbuf = next_nbuf;
}
+ /* Reset the head and tail pointers */
+ pdev = dp_get_pdev_for_mac_id(soc, mac_id);
+ if (pdev) {
+ pdev->invalid_peer_head_msdu = NULL;
+ pdev->invalid_peer_tail_msdu = NULL;
+ }
+
return 0;
}
diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c
index 6538999..9c2ffe9 100644
--- a/dp/wifi3.0/dp_rx_defrag.c
+++ b/dp/wifi3.0/dp_rx_defrag.c
@@ -1026,13 +1026,23 @@
peer->rx_tid[tid].dst_ring_desc;
hal_ring_handle_t hal_srng = soc->reo_reinject_ring.hal_srng;
struct dp_rx_desc *rx_desc = peer->rx_tid[tid].head_frag_desc;
+ struct dp_rx_reorder_array_elem *rx_reorder_array_elem =
+ peer->rx_tid[tid].array;
+ qdf_nbuf_t nbuf_head;
- head = dp_ipa_handle_rx_reo_reinject(soc, head);
- if (qdf_unlikely(!head)) {
+ nbuf_head = dp_ipa_handle_rx_reo_reinject(soc, head);
+ if (qdf_unlikely(!nbuf_head)) {
dp_err_rl("IPA RX REO reinject failed");
return QDF_STATUS_E_FAILURE;
}
+ /* update new allocated skb in case IPA is enabled */
+ if (nbuf_head != head) {
+ head = nbuf_head;
+ rx_desc->nbuf = head;
+ rx_reorder_array_elem->head = head;
+ }
+
ent_ring_desc = hal_srng_src_get_next(soc->hal_soc, hal_srng);
if (!ent_ring_desc) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c
index 29fd9ac..4e5e4a5 100644
--- a/dp/wifi3.0/dp_rx_err.c
+++ b/dp/wifi3.0/dp_rx_err.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -427,8 +427,8 @@
* Return: bool: true for last msdu of mpdu
*/
static bool
-dp_rx_chain_msdus(struct dp_soc *soc, qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr,
- uint8_t mac_id)
+dp_rx_chain_msdus(struct dp_soc *soc, qdf_nbuf_t nbuf,
+ uint8_t *rx_tlv_hdr, uint8_t mac_id)
{
bool mpdu_done = false;
qdf_nbuf_t curr_nbuf = NULL;
@@ -447,8 +447,9 @@
* up
*/
if (!dp_pdev->first_nbuf ||
+ (dp_pdev->invalid_peer_head_msdu &&
QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST
- (dp_pdev->invalid_peer_head_msdu) >= DP_MAX_INVALID_BUFFERS) {
+ (dp_pdev->invalid_peer_head_msdu) >= DP_MAX_INVALID_BUFFERS)) {
qdf_nbuf_set_rx_chfrag_start(nbuf, 1);
dp_pdev->ppdu_id = hal_rx_hw_desc_get_ppduid_get(soc->hal_soc,
rx_tlv_hdr);
@@ -804,6 +805,7 @@
pdev->invalid_peer_head_msdu = NULL;
pdev->invalid_peer_tail_msdu = NULL;
}
+
return QDF_STATUS_E_FAILURE;
}
@@ -1244,7 +1246,8 @@
if (qdf_unlikely((msdu_list.rbm[0] != DP_WBM2SW_RBM) &&
(msdu_list.rbm[0] !=
- HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST))) {
+ HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST) &&
+ (msdu_list.rbm[0] != DP_DEFRAG_RBM))) {
/* TODO */
/* Call appropriate handler */
if (!wlan_cfg_get_dp_soc_nss_cfg(soc->wlan_cfg_ctx)) {
diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c
index 03739c8..1bae203 100644
--- a/dp/wifi3.0/dp_tx.c
+++ b/dp/wifi3.0/dp_tx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -3810,26 +3810,6 @@
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
/**
- * dp_tx_desc_reset_vdev() - reset vdev to NULL in TX Desc
- *
- * @soc: Handle to DP SoC structure
- * @tx_desc: pointer of one TX desc
- * @desc_pool_id: TX Desc pool id
- */
-static inline void
-dp_tx_desc_reset_vdev(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
- uint8_t desc_pool_id)
-{
- struct dp_tx_desc_pool_s *pool = &soc->tx_desc[desc_pool_id];
-
- qdf_spin_lock_bh(&pool->flow_pool_lock);
-
- tx_desc->vdev = NULL;
-
- qdf_spin_unlock_bh(&pool->flow_pool_lock);
-}
-
-/**
* dp_tx_desc_flush() - release resources associated
* to TX Desc
*
@@ -3872,6 +3852,17 @@
!(tx_desc_pool->desc_pages.cacheable_pages))
continue;
+ /*
+ * Add flow pool lock protection in case pool is freed
+ * due to all tx_desc is recycled when handle TX completion.
+ * this is not necessary when do force flush as:
+ * a. double lock will happen if dp_tx_desc_release is
+ * also trying to acquire it.
+ * b. dp interrupt has been disabled before do force TX desc
+ * flush in dp_pdev_deinit().
+ */
+ if (!force_free)
+ qdf_spin_lock_bh(&tx_desc_pool->flow_pool_lock);
num_desc = tx_desc_pool->pool_size;
num_desc_per_page =
tx_desc_pool->desc_pages.num_element_per_page;
@@ -3895,15 +3886,22 @@
dp_tx_comp_free_buf(soc, tx_desc);
dp_tx_desc_release(tx_desc, i);
} else {
- dp_tx_desc_reset_vdev(soc, tx_desc,
- i);
+ tx_desc->vdev = NULL;
}
}
}
+ if (!force_free)
+ qdf_spin_unlock_bh(&tx_desc_pool->flow_pool_lock);
}
}
#else /* QCA_LL_TX_FLOW_CONTROL_V2! */
-
+/**
+ * dp_tx_desc_reset_vdev() - reset vdev to NULL in TX Desc
+ *
+ * @soc: Handle to DP soc structure
+ * @tx_desc: pointer of one TX desc
+ * @desc_pool_id: TX Desc pool id
+ */
static inline void
dp_tx_desc_reset_vdev(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
uint8_t desc_pool_id)
diff --git a/hif/src/ce/ce_internal.h b/hif/src/ce/ce_internal.h
index a5edd14..0de6feb 100644
--- a/hif/src/ce/ce_internal.h
+++ b/hif/src/ce/ce_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -468,6 +468,8 @@
HIF_RX_DESC_PRE_NBUF_ALLOC,
HIF_RX_DESC_PRE_NBUF_MAP,
HIF_RX_DESC_POST_NBUF_MAP,
+
+ HIF_EVENT_TYPE_MAX,
};
void ce_init_ce_desc_event_log(struct hif_softc *scn, int ce_id, int size);
diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c
index 69ca818..7be9a2f 100644
--- a/hif/src/ce/ce_main.c
+++ b/hif/src/ce/ce_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -3194,6 +3194,7 @@
hif_state->target_ce_config_sz =
sizeof(target_ce_config_wlan_qcn9000);
scn->ce_count = QCN_9000_CE_COUNT;
+ scn->disable_wake_irq = 1;
break;
case TARGET_TYPE_QCA6390:
hif_state->host_ce_config = host_ce_config_wlan_qca6390;
diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h
index c943feb..f3feb76 100644
--- a/hif/src/ce/ce_main.h
+++ b/hif/src/ce/ce_main.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -49,6 +49,7 @@
#define CE_USEFUL_SIZE 0x00000058
#define CE_ALL_BITMAP 0xFFFF
+#define HIF_REQUESTED_EVENTS 20
/**
* enum ce_id_type
*
@@ -70,6 +71,30 @@
CE_ID_MAX
};
+/**
+ * enum ce_buckets
+ *
+ * @ce_buckets: CE tasklet time buckets
+ * @CE_BUCKET_500_US: tasklet bucket to store 0-0.5ms
+ * @CE_BUCKET_1_MS: tasklet bucket to store 0.5-1ms
+ * @CE_BUCKET_2_MS: tasklet bucket to store 1-2ms
+ * @CE_BUCKET_5_MS: tasklet bucket to store 2-5ms
+ * @CE_BUCKET_10_MS: tasklet bucket to store 5-10ms
+ * @CE_BUCKET_BEYOND: tasklet bucket to store > 10ms
+ * @CE_BUCKET_MAX: enum max value
+ */
+#ifdef CE_TASKLET_DEBUG_ENABLE
+enum ce_buckets {
+ CE_BUCKET_500_US,
+ CE_BUCKET_1_MS,
+ CE_BUCKET_2_MS,
+ CE_BUCKET_5_MS,
+ CE_BUCKET_10_MS,
+ CE_BUCKET_BEYOND,
+ CE_BUCKET_MAX,
+};
+#endif
+
enum ce_target_type {
CE_SVC_LEGACY,
CE_SVC_SRNG,
@@ -134,8 +159,33 @@
extern struct hif_execution_ops tasklet_sched_ops;
extern struct hif_execution_ops napi_sched_ops;
+/**
+ * struct ce_stats
+ *
+ * @ce_per_cpu: Stats of the CEs running per CPU
+ * @record_index: Current index to store in time record
+ * @tasklet_sched_entry_ts: Timestamp when tasklet is scheduled
+ * @tasklet_exec_entry_ts: Timestamp when tasklet is started execuiton
+ * @tasklet_exec_time_record: Last N number of tasklets execution time
+ * @tasklet_sched_time_record: Last N number of tasklets scheduled time
+ * @ce_tasklet_exec_bucket: Tasklet execution time buckets
+ * @ce_tasklet_sched_bucket: Tasklet time in queue buckets
+ * @ce_tasklet_exec_last_update: Latest timestamp when bucket is updated
+ * @ce_tasklet_sched_last_update: Latest timestamp when bucket is updated
+ */
struct ce_stats {
uint32_t ce_per_cpu[CE_COUNT_MAX][QDF_MAX_AVAILABLE_CPU];
+#ifdef CE_TASKLET_DEBUG_ENABLE
+ uint32_t record_index[CE_COUNT_MAX];
+ uint64_t tasklet_sched_entry_ts[CE_COUNT_MAX];
+ uint64_t tasklet_exec_entry_ts[CE_COUNT_MAX];
+ uint64_t tasklet_exec_time_record[CE_COUNT_MAX][HIF_REQUESTED_EVENTS];
+ uint64_t tasklet_sched_time_record[CE_COUNT_MAX][HIF_REQUESTED_EVENTS];
+ uint64_t ce_tasklet_exec_bucket[CE_COUNT_MAX][CE_BUCKET_MAX];
+ uint64_t ce_tasklet_sched_bucket[CE_COUNT_MAX][CE_BUCKET_MAX];
+ uint64_t ce_tasklet_exec_last_update[CE_COUNT_MAX][CE_BUCKET_MAX];
+ uint64_t ce_tasklet_sched_last_update[CE_COUNT_MAX][CE_BUCKET_MAX];
+#endif
};
struct HIF_CE_state {
diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c
index 9a5b615..ed3030c 100644
--- a/hif/src/ce/ce_tasklet.c
+++ b/hif/src/ce/ce_tasklet.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -35,7 +35,6 @@
#include "hif_debug.h"
#include "hif_napi.h"
-
/**
* struct tasklet_work
*
@@ -139,6 +138,199 @@
tasklet_schedule(&tasklet_entry->intr_tq);
}
+#ifdef CE_TASKLET_DEBUG_ENABLE
+/**
+ * hif_record_tasklet_exec_entry_ts() - Record ce tasklet execution
+ * entry time
+ * @scn: hif_softc
+ * @ce_id: ce_id
+ *
+ * Return: None
+ */
+static inline void
+hif_record_tasklet_exec_entry_ts(struct hif_softc *scn, uint8_t ce_id)
+{
+ struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn);
+
+ hif_ce_state->stats.tasklet_exec_entry_ts[ce_id] =
+ qdf_get_log_timestamp_usecs();
+}
+
+/**
+ * hif_record_tasklet_sched_entry_ts() - Record ce tasklet scheduled
+ * entry time
+ * @scn: hif_softc
+ * @ce_id: ce_id
+ *
+ * Return: None
+ */
+static inline void
+hif_record_tasklet_sched_entry_ts(struct hif_softc *scn, uint8_t ce_id)
+{
+ struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn);
+
+ hif_ce_state->stats.tasklet_sched_entry_ts[ce_id] =
+ qdf_get_log_timestamp_usecs();
+}
+
+/**
+ * hif_ce_latency_stats() - Display ce latency information
+ * @hif_ctx: hif_softc struct
+ *
+ * Return: None
+ */
+static void
+hif_ce_latency_stats(struct hif_softc *hif_ctx)
+{
+ uint8_t i, j;
+ uint32_t index, start_index;
+ static const char * const buck_str[] = {"0 - 0.5", "0.5 - 1", "1 - 2",
+ "2 - 5", "5 - 10", " > 10"};
+ struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(hif_ctx);
+ struct ce_stats *stats = &hif_ce_state->stats;
+
+ for (i = 0; i < CE_COUNT_MAX; i++) {
+ qdf_nofl_info("\n\t\tCE Ring %d Tasklet Execution Bucket", i);
+ for (j = 0; j < CE_BUCKET_MAX; j++) {
+ qdf_nofl_info("\t Bucket %sms :%llu\t last update:%llu",
+ buck_str[j],
+ stats->ce_tasklet_exec_bucket[i][j],
+ stats->ce_tasklet_exec_last_update[i][j]);
+ }
+
+ qdf_nofl_info("\n\t\tCE Ring %d Tasklet Scheduled Bucket", i);
+ for (j = 0; j < CE_BUCKET_MAX; j++) {
+ qdf_nofl_info("\t Bucket %sms :%llu\t last update :%lld",
+ buck_str[j],
+ stats->ce_tasklet_sched_bucket[i][j],
+ stats->
+ ce_tasklet_sched_last_update[i][j]);
+ }
+
+ qdf_nofl_info("\n\t\t CE RING %d Last %d time records",
+ i, HIF_REQUESTED_EVENTS);
+ index = stats->record_index[i];
+ start_index = stats->record_index[i];
+
+ for (j = 0; j < HIF_REQUESTED_EVENTS; j++) {
+ qdf_nofl_info("\t Execuiton time: %luus Total Scheduled time: %luus",
+ stats->tasklet_exec_time_record[i][index],
+ stats->
+ tasklet_sched_time_record[i][index]);
+ index = (index - 1) % HIF_REQUESTED_EVENTS;
+ if (index == start_index)
+ break;
+ }
+ }
+}
+
+/**
+ * ce_tasklet_update_bucket() - update ce execution and scehduled time latency
+ * in corresponding time buckets
+ * @stats: struct ce_stats
+ * @ce_id: ce_id_type
+ * @entry_us: timestamp when tasklet is started to execute
+ * @exit_us: timestamp when tasklet is completed execution
+ *
+ * Return: N/A
+ */
+static void ce_tasklet_update_bucket(struct HIF_CE_state *hif_ce_state,
+ uint8_t ce_id)
+{
+ uint32_t index;
+ uint64_t exec_time, exec_ms;
+ uint64_t sched_time, sched_ms;
+ uint64_t curr_time = qdf_get_log_timestamp_usecs();
+ struct ce_stats *stats = &hif_ce_state->stats;
+
+ exec_time = curr_time - (stats->tasklet_exec_entry_ts[ce_id]);
+ sched_time = (stats->tasklet_exec_entry_ts[ce_id]) -
+ (stats->tasklet_sched_entry_ts[ce_id]);
+
+ index = stats->record_index[ce_id];
+ index = (index + 1) % HIF_REQUESTED_EVENTS;
+
+ stats->tasklet_exec_time_record[ce_id][index] = exec_time;
+ stats->tasklet_sched_time_record[ce_id][index] = sched_time;
+ stats->record_index[ce_id] = index;
+
+ exec_ms = qdf_do_div(exec_time, 1000);
+ sched_ms = qdf_do_div(sched_time, 1000);
+
+ if (exec_ms > 10) {
+ stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_BEYOND]++;
+ stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_BEYOND]
+ = curr_time;
+ } else if (exec_ms > 5) {
+ stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_10_MS]++;
+ stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_10_MS]
+ = curr_time;
+ } else if (exec_ms > 2) {
+ stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_5_MS]++;
+ stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_5_MS]
+ = curr_time;
+ } else if (exec_ms > 1) {
+ stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_2_MS]++;
+ stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_2_MS]
+ = curr_time;
+ } else if (exec_time > 500) {
+ stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_1_MS]++;
+ stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_1_MS]
+ = curr_time;
+ } else {
+ stats->ce_tasklet_exec_bucket[ce_id][CE_BUCKET_500_US]++;
+ stats->ce_tasklet_exec_last_update[ce_id][CE_BUCKET_500_US]
+ = curr_time;
+ }
+
+ if (sched_ms > 10) {
+ stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_BEYOND]++;
+ stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_BEYOND]
+ = curr_time;
+ } else if (sched_ms > 5) {
+ stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_10_MS]++;
+ stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_10_MS]
+ = curr_time;
+ } else if (sched_ms > 2) {
+ stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_5_MS]++;
+ stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_5_MS]
+ = curr_time;
+ } else if (sched_ms > 1) {
+ stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_2_MS]++;
+ stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_2_MS]
+ = curr_time;
+ } else if (sched_time > 500) {
+ stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_1_MS]++;
+ stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_1_MS]
+ = curr_time;
+ } else {
+ stats->ce_tasklet_sched_bucket[ce_id][CE_BUCKET_500_US]++;
+ stats->ce_tasklet_sched_last_update[ce_id][CE_BUCKET_500_US]
+ = curr_time;
+ }
+}
+#else
+static inline void
+hif_record_tasklet_exec_entry_ts(struct hif_softc *scn, uint8_t ce_id)
+{
+}
+
+static void ce_tasklet_update_bucket(struct HIF_CE_state *hif_ce_state,
+ uint8_t ce_id)
+{
+}
+
+static inline void
+hif_record_tasklet_sched_entry_ts(struct hif_softc *scn, uint8_t ce_id)
+{
+}
+
+static void
+hif_ce_latency_stats(struct hif_softc *hif_ctx)
+{
+}
+#endif /*CE_TASKLET_DEBUG_ENABLE*/
+
/**
* ce_tasklet() - ce_tasklet
* @data: data
@@ -153,8 +345,9 @@
struct hif_softc *scn = HIF_GET_SOFTC(hif_ce_state);
struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id];
+ hif_record_tasklet_exec_entry_ts(scn, tasklet_entry->ce_id);
hif_record_ce_desc_event(scn, tasklet_entry->ce_id,
- HIF_CE_TASKLET_ENTRY, NULL, NULL, -1, 0);
+ HIF_CE_TASKLET_ENTRY, NULL, NULL, -1, 0);
if (qdf_atomic_read(&scn->link_suspended)) {
HIF_ERROR("%s: ce %d tasklet fired after link suspend.",
@@ -182,7 +375,7 @@
hif_record_ce_desc_event(scn, tasklet_entry->ce_id, HIF_CE_TASKLET_EXIT,
NULL, NULL, -1, 0);
-
+ ce_tasklet_update_bucket(hif_ce_state, tasklet_entry->ce_id);
qdf_atomic_dec(&scn->active_tasklet_cnt);
}
@@ -339,12 +532,13 @@
*
* Return: none
*/
-void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state)
+void hif_display_ce_stats(struct hif_softc *hif_ctx)
{
#define STR_SIZE 128
uint8_t i, j, pos;
char str_buffer[STR_SIZE];
int size, ret;
+ struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(hif_ctx);
qdf_debug("CE interrupt statistics:");
for (i = 0; i < CE_COUNT_MAX; i++) {
@@ -352,7 +546,7 @@
pos = 0;
for (j = 0; j < QDF_MAX_AVAILABLE_CPU; j++) {
ret = snprintf(str_buffer + pos, size, "[%d]:%d ",
- j, hif_ce_state->stats.ce_per_cpu[i][j]);
+ j, hif_ce_state->stats.ce_per_cpu[i][j]);
if (ret <= 0 || ret >= size)
break;
size -= ret;
@@ -360,6 +554,8 @@
}
qdf_debug("CE id[%2d] - %s", i, str_buffer);
}
+
+ hif_ce_latency_stats(hif_ctx);
#undef STR_SIZE
}
@@ -393,6 +589,7 @@
}
tasklet_schedule(&tasklet_entry->intr_tq);
+ hif_record_tasklet_sched_entry_ts(scn, tasklet_entry->ce_id);
return true;
}
diff --git a/hif/src/ce/ce_tasklet.h b/hif/src/ce/ce_tasklet.h
index 05da168..d5ab58c 100644
--- a/hif/src/ce/ce_tasklet.h
+++ b/hif/src/ce/ce_tasklet.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016,2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016,2018,2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -28,6 +28,6 @@
QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask);
irqreturn_t ce_dispatch_interrupt(int irq,
struct ce_tasklet_entry *tasklet_entry);
-void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state);
+void hif_display_ce_stats(struct hif_softc *hif_ctx);
void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state);
#endif /* __CE_TASKLET_H__ */
diff --git a/hif/src/dispatcher/ahb_api.h b/hif/src/dispatcher/ahb_api.h
index 103114b..1657cbc 100644
--- a/hif/src/dispatcher/ahb_api.h
+++ b/hif/src/dispatcher/ahb_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018,2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -50,4 +50,6 @@
int hif_ahb_configure_grp_irq(struct hif_softc *scn,
struct hif_exec_context *hif_ext_grp);
bool hif_ahb_needs_bmi(struct hif_softc *scn);
+void hif_ahb_display_stats(struct hif_softc *scn);
+void hif_ahb_clear_stats(struct hif_softc *scn);
#endif
diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c
index 04bf46d..fe46d5b 100644
--- a/hif/src/dispatcher/multibus_ahb.c
+++ b/hif/src/dispatcher/multibus_ahb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -69,7 +69,8 @@
bus_ops->hif_grp_irq_configure = &hif_ahb_configure_grp_irq;
bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary;
bus_ops->hif_needs_bmi = &hif_ahb_needs_bmi;
-
+ bus_ops->hif_display_stats = &hif_ahb_display_stats;
+ bus_ops->hif_clear_stats = &hif_ahb_clear_stats;
return QDF_STATUS_SUCCESS;
}
diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h
index 8c1d48e..7875593 100644
--- a/hif/src/hif_main.h
+++ b/hif/src/hif_main.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -203,6 +203,7 @@
struct hif_ut_suspend_context ut_suspend_ctx;
uint32_t hif_attribute;
int wake_irq;
+ int disable_wake_irq;
void (*initial_wakeup_cb)(void *);
void *initial_wakeup_priv;
#ifdef REMOVE_PKT_LOG
diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c
index 36471e4..3cc2c70 100644
--- a/hif/src/pcie/if_pci.c
+++ b/hif/src/pcie/if_pci.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -618,7 +618,7 @@
struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
/* Check device ID from PCIe configuration space for link status */
- pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &device_id);
+ pfrm_read_config_word(sc->pdev, PCI_DEVICE_ID, &device_id);
if (device_id != sc->devid) {
HIF_ERROR("%s: device ID does match (read 0x%x, expect 0x%x)",
__func__, device_id, sc->devid);
@@ -1302,8 +1302,8 @@
}
/* Disable ASPM when pkt log is enabled */
- pci_read_config_dword(sc->pdev, 0x80, &sc->lcr_val);
- pci_write_config_dword(sc->pdev, 0x80, (sc->lcr_val & 0xffffff00));
+ pfrm_read_config_dword(sc->pdev, 0x80, &sc->lcr_val);
+ pfrm_write_config_dword(sc->pdev, 0x80, (sc->lcr_val & 0xffffff00));
}
/**
@@ -1321,7 +1321,7 @@
}
/* Re-enable ASPM after firmware/OTP download is complete */
- pci_write_config_dword(sc->pdev, 0x80, sc->lcr_val);
+ pfrm_write_config_dword(sc->pdev, 0x80, sc->lcr_val);
}
/**
@@ -1395,7 +1395,7 @@
HIF_ERROR("%s, hif_ctx null", __func__);
return;
}
- hif_display_ce_stats(&pci_ctx->ce_sc);
+ hif_display_ce_stats(hif_ctx);
hif_print_pci_stats(pci_ctx);
}
@@ -2370,7 +2370,7 @@
hif_debug("%s: (ce_id %d, msi_data %d, irq %d)", __func__,
ce_id, msi_data, irq);
- free_irq(irq, &ce_sc->tasklets[ce_id]);
+ pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
}
return ret;
@@ -2388,7 +2388,8 @@
hif_ext_group->irq_requested = false;
for (j = 0; j < hif_ext_group->numirq; j++) {
irq = hif_ext_group->os_irq[j];
- free_irq(irq, hif_ext_group);
+ pfrm_free_irq(scn->qdf_dev->dev,
+ irq, hif_ext_group);
}
hif_ext_group->numirq = 0;
}
@@ -2422,7 +2423,7 @@
/* ce irqs freed in hif_ce_srng_msi_free_irq */
if (scn->wake_irq)
- free_irq(scn->wake_irq, scn);
+ pfrm_free_irq(scn->qdf_dev->dev, scn->wake_irq, scn);
scn->wake_irq = 0;
} else if (sc->num_msi_intrs > 0) {
/* MSI interrupt(s) */
@@ -2591,7 +2592,7 @@
return -EINVAL;
}
- pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &dev_id);
+ pfrm_read_config_word(sc->pdev, PCI_DEVICE_ID, &dev_id);
if (dev_id == sc->devid)
return 0;
@@ -3020,23 +3021,23 @@
HIF_ERROR("%s: keep_awake_count = %d",
__func__, hif_state->keep_awake_count);
- pci_read_config_word(sc->pdev, PCI_VENDOR_ID, &val);
+ pfrm_read_config_word(sc->pdev, PCI_VENDOR_ID, &val);
HIF_ERROR("%s: PCI Vendor ID = 0x%04x", __func__, val);
- pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &val);
+ pfrm_read_config_word(sc->pdev, PCI_DEVICE_ID, &val);
HIF_ERROR("%s: PCI Device ID = 0x%04x", __func__, val);
- pci_read_config_word(sc->pdev, PCI_COMMAND, &val);
+ pfrm_read_config_word(sc->pdev, PCI_COMMAND, &val);
HIF_ERROR("%s: PCI Command = 0x%04x", __func__, val);
- pci_read_config_word(sc->pdev, PCI_STATUS, &val);
+ pfrm_read_config_word(sc->pdev, PCI_STATUS, &val);
HIF_ERROR("%s: PCI Status = 0x%04x", __func__, val);
- pci_read_config_dword(sc->pdev, PCI_BASE_ADDRESS_0, &bar);
+ pfrm_read_config_dword(sc->pdev, PCI_BASE_ADDRESS_0, &bar);
HIF_ERROR("%s: PCI BAR 0 = 0x%08x", __func__, bar);
@@ -3331,12 +3332,14 @@
*/
static void hif_ce_srng_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
{
- disable_irq_nosync(hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
+ pfrm_disable_irq_nosync(hif_sc->qdf_dev->dev,
+ hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
}
static void hif_ce_srng_msi_irq_enable(struct hif_softc *hif_sc, int ce_id)
{
- enable_irq(hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
+ pfrm_enable_irq(hif_sc->qdf_dev->dev,
+ hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
}
static void hif_ce_legacy_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
@@ -3360,18 +3363,25 @@
struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(scn);
struct CE_attr *host_ce_conf = ce_sc->host_ce_config;
- /* do wake irq assignment */
- ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "WAKE",
- &msi_data_count, &msi_data_start,
- &msi_irq_start);
- if (ret)
- return ret;
+ if (!scn->disable_wake_irq) {
+ /* do wake irq assignment */
+ ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "WAKE",
+ &msi_data_count,
+ &msi_data_start,
+ &msi_irq_start);
+ if (ret)
+ return ret;
- scn->wake_irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_irq_start);
- ret = request_irq(scn->wake_irq, hif_wake_interrupt_handler,
- IRQF_NO_SUSPEND, "wlan_wake_irq", scn);
- if (ret)
- return ret;
+ scn->wake_irq = pld_get_msi_irq(scn->qdf_dev->dev,
+ msi_irq_start);
+
+ ret = pfrm_request_irq(scn->qdf_dev->dev, scn->wake_irq,
+ hif_wake_interrupt_handler,
+ IRQF_NO_SUSPEND, "wlan_wake_irq", scn);
+
+ if (ret)
+ return ret;
+ }
/* do ce irq assignments */
ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
@@ -3408,10 +3418,11 @@
continue;
pci_sc->ce_msi_irq_num[ce_id] = irq;
- ret = request_irq(irq, hif_ce_interrupt_handler,
- IRQF_SHARED,
- ce_name[ce_id],
- &ce_sc->tasklets[ce_id]);
+ ret = pfrm_request_irq(scn->qdf_dev->dev,
+ irq, hif_ce_interrupt_handler,
+ IRQF_SHARED,
+ ce_name[ce_id],
+ &ce_sc->tasklets[ce_id]);
if (ret)
goto free_irq;
}
@@ -3426,12 +3437,16 @@
ce_id--;
msi_data = (ce_id % msi_data_count) + msi_irq_start;
irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
- free_irq(irq, &ce_sc->tasklets[ce_id]);
+ pfrm_free_irq(scn->qdf_dev->dev,
+ irq, &ce_sc->tasklets[ce_id]);
}
free_wake_irq:
- free_irq(scn->wake_irq, scn->qdf_dev->dev);
- scn->wake_irq = 0;
+ if (!scn->disable_wake_irq) {
+ pfrm_free_irq(scn->qdf_dev->dev,
+ scn->wake_irq, scn->qdf_dev->dev);
+ scn->wake_irq = 0;
+ }
return ret;
}
@@ -3439,17 +3454,20 @@
static void hif_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group)
{
int i;
+ struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
for (i = 0; i < hif_ext_group->numirq; i++)
- disable_irq_nosync(hif_ext_group->os_irq[i]);
+ pfrm_disable_irq_nosync(scn->qdf_dev->dev,
+ hif_ext_group->os_irq[i]);
}
static void hif_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group)
{
int i;
+ struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
for (i = 0; i < hif_ext_group->numirq; i++)
- enable_irq(hif_ext_group->os_irq[i]);
+ pfrm_enable_irq(scn->qdf_dev->dev, hif_ext_group->os_irq[i]);
}
/**
@@ -3483,11 +3501,12 @@
hif_info("request_irq = %d for grp %d",
irq, hif_ext_group->grp_id);
- ret = request_irq(irq,
- hif_ext_group_interrupt_handler,
- IRQF_SHARED | IRQF_NO_SUSPEND,
- "wlan_EXT_GRP",
- hif_ext_group);
+ ret = pfrm_request_irq(
+ scn->qdf_dev->dev, irq,
+ hif_ext_group_interrupt_handler,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "wlan_EXT_GRP",
+ hif_ext_group);
if (ret) {
HIF_ERROR("%s: request_irq failed ret = %d",
__func__, ret);
@@ -3770,7 +3789,7 @@
hif_disable_power_gating(hif_hdl);
device_disable_async_suspend(&pdev->dev);
- pci_read_config_word(pdev, 0x08, &revision_id);
+ pfrm_read_config_word(pdev, 0x08, &revision_id);
ret = hif_get_device_type(id->device, revision_id,
&hif_type, &target_type);
diff --git a/hif/src/pcie/if_pci_internal.h b/hif/src/pcie/if_pci_internal.h
index 16aea4a..c334862 100644
--- a/hif/src/pcie/if_pci_internal.h
+++ b/hif/src/pcie/if_pci_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, 2018-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -23,8 +23,8 @@
#define PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, addr) \
{ \
uint32_t lcr_val; \
- pci_read_config_dword(pdev, addr, &lcr_val); \
- pci_write_config_dword(pdev, addr, (lcr_val & ~0x0000000f)); \
+ pfrm_read_config_dword(pdev, addr, &lcr_val); \
+ pfrm_write_config_dword(pdev, addr, (lcr_val & ~0x0000000f)); \
}
#else
#define PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, addr)
diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c
index 3ec81c9..568f61e 100644
--- a/hif/src/snoc/if_ahb.c
+++ b/hif/src/snoc/if_ahb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -271,13 +271,21 @@
for (i = 0; i < scn->ce_count; i++) {
if (host_ce_conf[i].flags & CE_ATTR_DISABLE_INTR)
continue;
- qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev,
- ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], &irq);
+ ret = pfrm_get_irq(&pdev->dev, (struct qdf_pfm_hndl *)pdev,
+ ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i],
+ HIF_IC_CE0_IRQ_OFFSET + i, &irq);
+ if (ret) {
+ dev_err(&pdev->dev, "get irq failed\n");
+ ret = -1;
+ goto end;
+ }
+
ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i] = irq;
- ret = request_irq(irq ,
- hif_ahb_interrupt_handler,
- IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i],
- &hif_state->tasklets[i]);
+ ret = pfrm_request_irq(&pdev->dev, irq,
+ hif_ahb_interrupt_handler,
+ IRQF_TRIGGER_RISING,
+ ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i],
+ &hif_state->tasklets[i]);
if (ret) {
dev_err(&pdev->dev, "ath_request_irq failed\n");
ret = -1;
@@ -308,18 +316,23 @@
qdf_spin_lock_irqsave(&hif_ext_group->irq_lock);
for (j = 0; j < hif_ext_group->numirq; j++) {
- qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev,
- ic_irqname[hif_ext_group->irq[j]], &irq);
-
+ ret = pfrm_get_irq(&pdev->dev, (struct qdf_pfm_hndl *)pdev,
+ ic_irqname[hif_ext_group->irq[j]],
+ hif_ext_group->irq[j], &irq);
+ if (ret) {
+ dev_err(&pdev->dev, "get irq failed\n");
+ ret = -1;
+ goto end;
+ }
ic_irqnum[hif_ext_group->irq[j]] = irq;
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
- ret = request_irq(irq, hif_ext_group_interrupt_handler,
- IRQF_TRIGGER_RISING,
- ic_irqname[hif_ext_group->irq[j]],
- hif_ext_group);
+ ret = pfrm_request_irq(scn->qdf_dev->dev,
+ irq, hif_ext_group_interrupt_handler,
+ IRQF_TRIGGER_RISING,
+ ic_irqname[hif_ext_group->irq[j]],
+ hif_ext_group);
if (ret) {
- dev_err(&pdev->dev,
- "ath_request_irq failed\n");
+ dev_err(&pdev->dev, "ath_request_irq failed\n");
ret = -1;
goto end;
}
@@ -363,7 +376,8 @@
*/
for (j = 0; j < hif_ext_group->numirq; j++) {
irq = hif_ext_group->os_irq[j];
- free_irq(irq, hif_ext_group);
+ pfrm_free_irq(scn->qdf_dev->dev,
+ irq, hif_ext_group);
}
}
}
@@ -450,19 +464,23 @@
int mem_pa_size = 0;
struct hif_target_info *tgt_info = NULL;
struct qdf_vbus_resource *vmres = NULL;
+ QDF_STATUS status;
tgt_info = &scn->target_info;
/*Disable WIFI clock input*/
if (sc->mem) {
- qal_vbus_get_resource((struct qdf_pfm_hndl *)pdev, &vmres,
- IORESOURCE_MEM, 0);
- memres = (struct resource *)vmres;
- if (!memres) {
+ status = pfrm_platform_get_resource(
+ scn->qdf_dev->dev,
+ (struct qdf_pfm_hndl *)pdev, &vmres,
+ IORESOURCE_MEM, 0);
+ if (QDF_IS_STATUS_ERROR(status)) {
HIF_INFO("%s: Failed to get IORESOURCE_MEM\n",
- __func__);
+ __func__);
return;
}
- mem_pa_size = memres->end - memres->start + 1;
+ memres = (struct resource *)vmres;
+ if (memres)
+ mem_pa_size = memres->end - memres->start + 1;
/* Should not be executed on 8074 platform */
if ((tgt_info->target_type != TARGET_TYPE_QCA8074) &&
@@ -474,9 +492,9 @@
}
mem = (void __iomem *)sc->mem;
if (mem) {
- devm_iounmap(&pdev->dev, mem);
- devm_release_mem_region(&pdev->dev, scn->mem_pa,
- mem_pa_size);
+ pfrm_devm_iounmap(&pdev->dev, mem);
+ pfrm_devm_release_mem_region(&pdev->dev, scn->mem_pa,
+ mem_pa_size);
sc->mem = NULL;
}
}
@@ -510,6 +528,8 @@
void __iomem *mem = NULL;
uint32_t revision_id = 0;
struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc);
+ QDF_STATUS status;
+ struct qdf_vbus_resource *vmres = NULL;
sc->pdev = (struct pci_dev *)pdev;
sc->dev = &pdev->dev;
@@ -523,22 +543,30 @@
return QDF_STATUS_E_FAILURE;
}
- memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ status = pfrm_platform_get_resource(&pdev->dev,
+ (struct qdf_pfm_hndl *)pdev,
+ &vmres,
+ IORESOURCE_MEM, 0);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__);
+ return -EIO;
+ }
+ memres = (struct resource *)vmres;
if (!memres) {
HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__);
return -EIO;
}
- ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+ ret = pfrm_dma_set_mask(dev, 32);
if (ret) {
HIF_INFO("ath: 32-bit DMA not available\n");
goto err_cleanup1;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ ret = pfrm_dma_set_mask_and_coherent(dev, 32);
#else
- ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ ret = pfrm_dma_set_coherent_mask(dev, 32);
#endif
if (ret) {
HIF_ERROR("%s: failed to set dma mask error = %d",
@@ -548,11 +576,16 @@
/* Arrange for access to Target SoC registers. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
- mem = devm_ioremap_resource(&pdev->dev, memres);
+ status = pfrm_devm_ioremap_resource(dev,
+ (struct qdf_vbus_resource *)memres,
+ &mem);
#else
- mem = devm_request_and_ioremap(&pdev->dev, memres);
+ status = pfrm_devm_request_and_ioremap(
+ dev,
+ (struct qdf_vbus_resource *)memres,
+ &mem);
#endif
- if (IS_ERR(mem)) {
+ if (QDF_IS_STATUS_ERROR(status)) {
HIF_INFO("ath: ioremap error\n");
ret = PTR_ERR(mem);
goto err_cleanup1;
@@ -640,20 +673,22 @@
if (sc->num_msi_intrs > 0) {
/* MSI interrupt(s) */
for (i = 0; i < sc->num_msi_intrs; i++) {
- free_irq(sc->irq + i, sc);
+ pfrm_free_irq(scn->qdf_dev->dev, sc->irq + i, sc);
}
sc->num_msi_intrs = 0;
} else {
if (!scn->per_ce_irq) {
- free_irq(sc->irq, sc);
+ pfrm_free_irq(scn->qdf_dev->dev, sc->irq, sc);
} else {
for (i = 0; i < scn->ce_count; i++) {
if (host_ce_conf[i].flags
& CE_ATTR_DISABLE_INTR)
continue;
- free_irq(ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i],
- &hif_state->tasklets[i]);
+ pfrm_free_irq(
+ scn->qdf_dev->dev,
+ ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i],
+ &hif_state->tasklets[i]);
}
hif_ahb_deconfigure_grp_irq(scn);
}
@@ -800,3 +835,23 @@
{
return !ce_srng_based(scn);
}
+
+void hif_ahb_display_stats(struct hif_softc *scn)
+{
+ if (!scn) {
+ HIF_ERROR("%s, hif_scn null", __func__);
+ return;
+ }
+ hif_display_ce_stats(scn);
+}
+
+void hif_ahb_clear_stats(struct hif_softc *scn)
+{
+ struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
+
+ if (!hif_state) {
+ HIF_ERROR("%s, hif_state null", __func__);
+ return;
+ }
+ hif_clear_ce_stats(hif_state);
+}
diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c
index 119db8a..5135088 100644
--- a/hif/src/snoc/if_snoc.c
+++ b/hif/src/snoc/if_snoc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -78,13 +78,11 @@
void hif_snoc_display_stats(struct hif_softc *hif_ctx)
{
- struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
-
- if (!hif_state) {
+ if (!hif_ctx) {
HIF_ERROR("%s, hif_ctx null", __func__);
return;
}
- hif_display_ce_stats(hif_state);
+ hif_display_ce_stats(hif_ctx);
}
void hif_snoc_clear_stats(struct hif_softc *hif_ctx)
diff --git a/htc/htc.c b/htc/htc.c
index 2a40fea..06c1ea4 100644
--- a/htc/htc.c
+++ b/htc/htc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -134,6 +134,16 @@
hif_dump(target->hif_dev, CmdId, start);
}
+void htc_ce_tasklet_debug_dump(HTC_HANDLE htc_handle)
+{
+ HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
+
+ if (!target->hif_dev)
+ return;
+
+ hif_display_stats(target->hif_dev);
+}
+
/* cleanup the HTC instance */
static void htc_cleanup(HTC_TARGET *target)
{
diff --git a/htc/htc_api.h b/htc/htc_api.h
index 9c06ac4..8adabc6 100644
--- a/htc/htc_api.h
+++ b/htc/htc_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -482,6 +482,15 @@
void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start);
/**
+ * htc_ce_taklet_debug_dump - Dump ce tasklet rings debug data
+ * @HTCHandle - HTC handle
+ *
+ * Debug logs will be printed.
+ * Return: None
+ */
+void htc_ce_tasklet_debug_dump(HTC_HANDLE htc_handle);
+
+/**
* htc_send_pkt - Send an HTC packet
* @HTCHandle - HTC handle
* @pPacket - packet to send
diff --git a/init_deinit/dispatcher/src/dispatcher_init_deinit.c b/init_deinit/dispatcher/src/dispatcher_init_deinit.c
index df71a65..0781988 100644
--- a/init_deinit/dispatcher/src/dispatcher_init_deinit.c
+++ b/init_deinit/dispatcher/src/dispatcher_init_deinit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -72,6 +72,10 @@
#include <wlan_cfr_utils_api.h>
#endif
+#ifdef FEATURE_COEX
+#include <wlan_coex_utils_api.h>
+#endif
+
/**
* DOC: This file provides various init/deinit trigger point for new
* components.
@@ -707,6 +711,50 @@
}
#endif /* WLAN_SUPPORT_FILS */
+#ifdef FEATURE_COEX
+static QDF_STATUS dispatcher_coex_init(void)
+{
+ return wlan_coex_init();
+}
+
+static QDF_STATUS dispatcher_coex_deinit(void)
+{
+ return wlan_coex_deinit();
+}
+
+static QDF_STATUS dispatcher_coex_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+ return wlan_coex_psoc_open(psoc);
+}
+
+static QDF_STATUS dispatcher_coex_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+ return wlan_coex_psoc_close(psoc);
+}
+#else
+static inline QDF_STATUS dispatcher_coex_init(void)
+{
+ return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS dispatcher_coex_deinit(void)
+{
+ return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+dispatcher_coex_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+ return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+dispatcher_coex_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+ return QDF_STATUS_SUCCESS;
+}
+#endif /* FEATURE_COEX */
+
QDF_STATUS dispatcher_init(void)
{
if (QDF_STATUS_SUCCESS != wlan_objmgr_global_obj_init())
@@ -772,6 +820,9 @@
if (QDF_STATUS_SUCCESS != dispatcher_init_cfr())
goto cfr_init_fail;
+ if (QDF_STATUS_SUCCESS != dispatcher_coex_init())
+ goto coex_init_fail;
+
/*
* scheduler INIT has to be the last as each component's
* initialization has to happen first and then at the end
@@ -783,6 +834,8 @@
return QDF_STATUS_SUCCESS;
scheduler_init_fail:
+ dispatcher_coex_deinit();
+coex_init_fail:
dispatcher_deinit_cfr();
cfr_init_fail:
wlan_cmn_mlme_deinit();
@@ -836,6 +889,8 @@
QDF_BUG(QDF_STATUS_SUCCESS == scheduler_deinit());
+ QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_coex_deinit());
+
QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_deinit_cfr());
QDF_BUG(QDF_STATUS_SUCCESS == wlan_cmn_mlme_deinit());
@@ -924,8 +979,13 @@
if (QDF_STATUS_SUCCESS != dispatcher_ftm_psoc_open(psoc))
goto ftm_psoc_open_fail;
+ if (QDF_STATUS_SUCCESS != dispatcher_coex_psoc_open(psoc))
+ goto coex_psoc_open_fail;
+
return QDF_STATUS_SUCCESS;
+coex_psoc_open_fail:
+ dispatcher_ftm_psoc_close(psoc);
ftm_psoc_open_fail:
son_psoc_close(psoc);
psoc_son_fail:
@@ -946,6 +1006,8 @@
QDF_STATUS dispatcher_psoc_close(struct wlan_objmgr_psoc *psoc)
{
+ QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_coex_psoc_close(psoc));
+
QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_ftm_psoc_close(psoc));
QDF_BUG(QDF_STATUS_SUCCESS == son_psoc_close(psoc));
diff --git a/os_if/linux/coex/inc/wlan_cfg80211_coex.h b/os_if/linux/coex/inc/wlan_cfg80211_coex.h
new file mode 100644
index 0000000..cd3e6bd
--- /dev/null
+++ b/os_if/linux/coex/inc/wlan_cfg80211_coex.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declares driver functions interfacing with linux kernel
+ */
+
+#ifndef _WLAN_CFG80211_COEX_H_
+#define _WLAN_CFG80211_COEX_H_
+#include <wlan_cfg80211.h>
+#include <wlan_objmgr_cmn.h>
+
+#ifdef FEATURE_COEX
+int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
+ const void *data, int data_len);
+#else
+static inline int
+wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
+ const void *data, int data_len)
+{
+ return -ENOTSUPP;
+}
+#endif
+#endif
diff --git a/os_if/linux/coex/src/wlan_cfg80211_coex.c b/os_if/linux/coex/src/wlan_cfg80211_coex.c
new file mode 100644
index 0000000..754b167
--- /dev/null
+++ b/os_if/linux/coex/src/wlan_cfg80211_coex.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: defines driver functions interfacing with linux kernel
+ */
+#include <wmi_unified_param.h>
+#include <wlan_osif_request_manager.h>
+#include <osif_sync.h>
+#include <wlan_objmgr_psoc_obj_i.h>
+#include <wlan_coex_main.h>
+#include <wlan_coex_ucfg_api.h>
+#include <wlan_cfg80211_coex.h>
+
+static const struct nla_policy
+btc_chain_mode_policy[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1] = {
+ [QCA_VENDOR_ATTR_BTC_CHAIN_MODE] = {.type = NLA_U32},
+ [QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART] = {.type = NLA_FLAG},
+};
+
+static int
+__wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
+ uint8_t mode, bool do_restart)
+{
+ QDF_STATUS status;
+ uint8_t cur_mode;
+ int err;
+ struct wlan_objmgr_psoc *psoc;
+ struct wlan_objmgr_vdev *vdev_tmp;
+ int vdev_id;
+ struct coex_psoc_obj *coex_obj;
+
+ if (!vdev) {
+ coex_err("Null vdev");
+ return -EINVAL;
+ }
+
+ psoc = wlan_vdev_get_psoc(vdev);
+ if (!psoc) {
+ coex_err("NULL psoc");
+ return -EINVAL;
+ }
+
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!coex_obj)
+ return -EINVAL;
+
+ status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &cur_mode);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ coex_err("failed to get cur BTC chain mode, status %d", status);
+ return -EFAULT;
+ }
+
+ if (cur_mode == mode)
+ return -EALREADY;
+
+ status = ucfg_coex_psoc_set_btc_chain_mode(psoc, mode);
+ if (!QDF_IS_STATUS_SUCCESS(status)) {
+ coex_err("unable to set BTC chain mode to %d", mode);
+ return -EFAULT;
+ }
+
+ wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev_tmp) {
+ status = ucfg_coex_send_btc_chain_mode(vdev, mode);
+ err = qdf_status_to_os_return(status);
+ if (err) {
+ coex_err("Failed to set btc chain mode to %d for vdev %d",
+ mode, vdev_id);
+ return err;
+ }
+ coex_debug("Set btc chain mode to %d for vdev %d",
+ mode, vdev_id);
+
+ if (!do_restart)
+ continue;
+
+ wlan_coex_config_updated(vdev, COEX_CONFIG_BTC_CHAIN_MODE);
+ }
+
+ return 0;
+}
+
+/**
+ * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to btc chain mode command parameters.
+ * @data_len: the length in byte of btc chain mode command parameters.
+ *
+ * Return: An error code or 0 on success.
+ */
+int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
+ const void *data, int data_len)
+{
+ struct nlattr *tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1];
+ uint32_t mode;
+ bool restart;
+
+ if (wlan_cfg80211_nla_parse(tb, QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX,
+ data, data_len, btc_chain_mode_policy)) {
+ coex_err("Invalid btc chain mode ATTR");
+ return -EINVAL;
+ }
+
+ if (!tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]) {
+ coex_err("btc chain mode - no attr mode");
+ return -EINVAL;
+ }
+
+ mode = nla_get_u32(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]);
+ if (mode < QCA_BTC_CHAIN_SHARED || mode > QCA_BTC_CHAIN_SEPARATED) {
+ coex_err("Invalid btc chain mode %d", mode);
+ return -EINVAL;
+ }
+
+ restart = nla_get_flag(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART]);
+
+ coex_debug("vdev_id %u mode %u restart %u",
+ wlan_vdev_get_id(vdev), mode, restart);
+
+ return __wlan_cfg80211_coex_set_btc_chain_mode(vdev, mode, restart);
+}
diff --git a/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c b/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c
index 818689f..228c471 100644
--- a/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c
+++ b/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -98,7 +98,7 @@
nl_buf_len += QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX *
(NLMSG_HDRLEN + sizeof(uint32_t));
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
if (!skb) {
osif_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
@@ -202,11 +202,11 @@
goto nla_put_failure;
}
- cfg80211_vendor_cmd_reply(skb);
+ wlan_cfg80211_vendor_cmd_reply(skb);
return 0;
nla_put_failure:
- kfree_skb(skb);
+ wlan_cfg80211_vendor_free_skb(skb);
return -EINVAL;
}
diff --git a/os_if/linux/scan/inc/wlan_cfg80211_scan.h b/os_if/linux/scan/inc/wlan_cfg80211_scan.h
index aee2d3b..a43e057 100644
--- a/os_if/linux/scan/inc/wlan_cfg80211_scan.h
+++ b/os_if/linux/scan/inc/wlan_cfg80211_scan.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -128,6 +128,14 @@
* @half_rate: Half rate flag
* @quarter_rate: Quarter rate flag
* @strict_pscan: strict passive scan flag
+ * @dwell_time_active: Active dwell time. Ignored if zero or inapplicable.
+ * @dwell_time_active_2g: 2.4 GHz specific active dwell time. Ignored if zero or
+ * inapplicable.
+ * @dwell_time_passive: Passive dwell time. Ignored if zero or inapplicable.
+ * @dwell_time_active_6g: 6 GHz specific active dwell time. Ignored if zero or
+ * inapplicable.
+ * @dwell_time_passive_6g: 6 GHz specific passive dwell time. Ignored if zero or
+ * inapplicable.
*/
struct scan_params {
uint8_t source;
@@ -137,6 +145,11 @@
bool half_rate;
bool quarter_rate;
bool strict_pscan;
+ uint32_t dwell_time_active;
+ uint32_t dwell_time_active_2g;
+ uint32_t dwell_time_passive;
+ uint32_t dwell_time_active_6g;
+ uint32_t dwell_time_passive_6g;
};
/**
diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c
index de69efe..a7f6616 100644
--- a/os_if/linux/scan/src/wlan_cfg80211_scan.c
+++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -839,11 +839,13 @@
int i;
uint8_t scan_status;
uint64_t cookie;
+ int index = QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX;
- skb = cfg80211_vendor_event_alloc(req->wdev->wiphy, req->wdev,
- SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN,
- QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX,
- GFP_ATOMIC);
+ skb = wlan_cfg80211_vendor_event_alloc(req->wdev->wiphy, req->wdev,
+ SCAN_DONE_EVENT_BUF_SIZE + 4 +
+ NLMSG_HDRLEN,
+ index,
+ GFP_ATOMIC);
if (!skb) {
osif_err("skb alloc failed");
@@ -889,13 +891,13 @@
if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status))
goto nla_put_failure;
- cfg80211_vendor_event(skb, GFP_ATOMIC);
+ wlan_cfg80211_vendor_event(skb, GFP_ATOMIC);
qdf_mem_free(req);
return;
nla_put_failure:
- kfree_skb(skb);
+ wlan_cfg80211_vendor_free_skb(skb);
qdf_mem_free(req);
}
@@ -1405,6 +1407,24 @@
if (is_p2p_scan && request->no_cck)
req->scan_req.scan_type = SCAN_TYPE_P2P_SEARCH;
+ if (params->dwell_time_active)
+ req->scan_req.dwell_time_active = params->dwell_time_active;
+
+ if (params->dwell_time_active_2g)
+ req->scan_req.dwell_time_active_2g =
+ params->dwell_time_active_2g;
+
+ if (params->dwell_time_passive)
+ req->scan_req.dwell_time_passive = params->dwell_time_passive;
+
+ if (params->dwell_time_active_6g)
+ req->scan_req.dwell_time_active_6g =
+ params->dwell_time_active_6g;
+
+ if (params->dwell_time_passive_6g)
+ req->scan_req.dwell_time_passive_6g =
+ params->dwell_time_passive_6g;
+
/* Set dwell time mode according to scan policy type flags */
if (ucfg_scan_cfg_honour_nl_scan_policy_flags(psoc)) {
if (req->scan_req.scan_policy_high_accuracy)
diff --git a/os_if/linux/spectral/src/wlan_cfg80211_spectral.c b/os_if/linux/spectral/src/wlan_cfg80211_spectral.c
index 8173cee..b45efef 100644
--- a/os_if/linux/spectral/src/wlan_cfg80211_spectral.c
+++ b/os_if/linux/spectral/src/wlan_cfg80211_spectral.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -31,7 +31,6 @@
#include <wlan_spectral_ucfg_api.h>
#include <wlan_cfg80211_spectral.h>
#include <spectral_ioctl.h>
-#include "qal_devcfg.h"
static const struct nla_policy spectral_scan_policy[
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1] = {
@@ -377,7 +376,8 @@
skb_len += NLA_HDRLEN + sizeof(u32);
/* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE */
skb_len += NLA_HDRLEN + sizeof(u64);
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
+
if (!skb) {
osif_err(" reply skb alloc failed");
return -ENOMEM;
@@ -385,8 +385,10 @@
status = wlan_cfg80211_spectral_scan_dma_debug_config(
pdev, tb, sscan_mode);
- if (QDF_IS_STATUS_ERROR(status))
- return -EINVAL;
+ if (QDF_IS_STATUS_ERROR(status)) {
+ status = QDF_STATUS_E_INVAL;
+ goto free_skb_return_os_status;
+ }
if (CONFIG_REQUESTED(scan_req_type)) {
sscan_req.ss_mode = sscan_mode;
@@ -401,25 +403,23 @@
/* No error reasons populated, just return error */
if (sscan_req.config_req.sscan_err_code ==
- SPECTRAL_SCAN_ERR_INVALID) {
- kfree_skb(skb);
- return qdf_status_to_os_return(status);
- }
+ SPECTRAL_SCAN_ERR_INVALID)
+ goto free_skb_return_os_status;
status = convert_spectral_err_code_internal_to_nl
(sscan_req.config_req.sscan_err_code,
&spectral_nl_err_code);
if (QDF_IS_STATUS_ERROR(status)) {
- kfree_skb(skb);
- return -EINVAL;
+ status = QDF_STATUS_E_INVAL;
+ goto free_skb_return_os_status;
}
if (nla_put_u32
(skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE,
spectral_nl_err_code)) {
- kfree_skb(skb);
- return -EINVAL;
+ status = QDF_STATUS_E_INVAL;
+ goto free_skb_return_os_status;
}
}
}
@@ -434,25 +434,23 @@
/* No error reasons populated, just return error */
if (sscan_req.action_req.sscan_err_code ==
- SPECTRAL_SCAN_ERR_INVALID) {
- kfree_skb(skb);
- return qdf_status_to_os_return(status);
- }
+ SPECTRAL_SCAN_ERR_INVALID)
+ goto free_skb_return_os_status;
status = convert_spectral_err_code_internal_to_nl
(sscan_req.action_req.sscan_err_code,
&spectral_nl_err_code);
if (QDF_IS_STATUS_ERROR(status)) {
- kfree_skb(skb);
- return -EINVAL;
+ status = QDF_STATUS_E_INVAL;
+ goto free_skb_return_os_status;
}
if (nla_put_u32
(skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE,
spectral_nl_err_code)) {
- kfree_skb(skb);
- return -EINVAL;
+ status = QDF_STATUS_E_INVAL;
+ goto free_skb_return_os_status;
}
}
}
@@ -461,13 +459,15 @@
if (wlan_cfg80211_nla_put_u64(skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE,
cookie)) {
- kfree_skb(skb);
- return -EINVAL;
+ status = QDF_STATUS_E_INVAL;
+ goto free_skb_return_os_status;
}
- qal_devcfg_send_response((qdf_nbuf_t)skb);
-
+ wlan_cfg80211_qal_devcfg_send_response((qdf_nbuf_t)skb);
return 0;
+free_skb_return_os_status:
+ wlan_cfg80211_vendor_free_skb(skb);
+ return qdf_status_to_os_return(status);
}
int wlan_cfg80211_spectral_scan_stop(struct wiphy *wiphy,
@@ -517,8 +517,9 @@
if (QDF_IS_STATUS_ERROR(status))
return -EINVAL;
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, NLMSG_HDRLEN +
- sizeof(u32) + NLA_HDRLEN);
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ NLMSG_HDRLEN + sizeof(u32) + NLA_HDRLEN);
+
if (!skb) {
osif_err(" reply skb alloc failed");
return -ENOMEM;
@@ -528,10 +529,10 @@
(skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE,
spectral_nl_err_code)) {
- kfree_skb(skb);
+ wlan_cfg80211_vendor_free_skb(skb);
return -EINVAL;
}
- qal_devcfg_send_response((qdf_nbuf_t)skb);
+ wlan_cfg80211_qal_devcfg_send_response((qdf_nbuf_t)skb);
}
return 0;
@@ -568,7 +569,8 @@
return -EINVAL;
}
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (sizeof(u32) +
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ (sizeof(u32) +
NLA_HDRLEN) * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX +
NLMSG_HDRLEN);
if (!skb) {
@@ -643,10 +645,8 @@
sconfig->ss_short_report) ||
nla_put_u32(skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY,
- sconfig->ss_frequency)) {
- kfree_skb(skb);
- return -EINVAL;
- }
+ sconfig->ss_frequency))
+ goto fail;
sscan_req.ss_mode = sscan_mode;
sscan_req.req_id = SPECTRAL_GET_DEBUG_LEVEL;
@@ -654,13 +654,14 @@
spectral_dbg_level = sscan_req.debug_req.spectral_dbg_level;
if (nla_put_u32(skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL,
- spectral_dbg_level)) {
- kfree_skb(skb);
- return -EINVAL;
- }
- qal_devcfg_send_response((qdf_nbuf_t)skb);
+ spectral_dbg_level))
+ goto fail;
+ wlan_cfg80211_qal_devcfg_send_response((qdf_nbuf_t)skb);
return 0;
+fail:
+ wlan_cfg80211_vendor_free_skb(skb);
+ return -EINVAL;
}
int wlan_cfg80211_spectral_scan_get_cap(struct wiphy *wiphy,
@@ -677,7 +678,8 @@
status = ucfg_spectral_control(pdev, &sscan_req);
scaps = &sscan_req.caps_req.sscan_caps;
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (sizeof(u32) +
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ (sizeof(u32) +
NLA_HDRLEN) * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX +
NLMSG_HDRLEN);
if (!skb) {
@@ -773,12 +775,12 @@
if (ret)
goto fail;
}
- qal_devcfg_send_response((qdf_nbuf_t)skb);
+ wlan_cfg80211_qal_devcfg_send_response((qdf_nbuf_t)skb);
return 0;
fail:
- kfree_skb(skb);
+ wlan_cfg80211_vendor_free_skb(skb);
return -EINVAL;
}
@@ -796,8 +798,9 @@
status = ucfg_spectral_control(pdev, &sscan_req);
spetcral_diag = &sscan_req.diag_req.sscan_diag;
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (sizeof(u64) +
- NLA_HDRLEN) * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX +
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ (sizeof(u64) + NLA_HDRLEN) *
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX +
NLMSG_HDRLEN);
if (!skb) {
osif_err(" reply skb alloc failed");
@@ -824,10 +827,10 @@
skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH,
spetcral_diag->spectral_vhtseg2id_mismatch)) {
- kfree_skb(skb);
+ wlan_cfg80211_vendor_free_skb(skb);
return -EINVAL;
}
- qal_devcfg_send_response((qdf_nbuf_t)skb);
+ wlan_cfg80211_qal_devcfg_send_response((qdf_nbuf_t)skb);
return 0;
}
@@ -873,8 +876,8 @@
status = ucfg_spectral_control(pdev, &sscan_req);
sscan_state.is_enabled = sscan_req.status_req.is_enabled;
- skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 2 * (sizeof(u32) +
- NLA_HDRLEN) + NLMSG_HDRLEN);
+ skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ 2 * (sizeof(u32) + NLA_HDRLEN) + NLMSG_HDRLEN);
if (!skb) {
osif_err(" reply skb alloc failed");
return -ENOMEM;
@@ -891,10 +894,10 @@
skb,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE))
goto fail;
- qal_devcfg_send_response((qdf_nbuf_t)skb);
+ wlan_cfg80211_qal_devcfg_send_response((qdf_nbuf_t)skb);
return 0;
fail:
- kfree_skb(skb);
+ wlan_cfg80211_vendor_free_skb(skb);
return -EINVAL;
}
diff --git a/os_if/linux/wlan_cfg80211.h b/os_if/linux/wlan_cfg80211.h
index 8dee454..dd23408 100644
--- a/os_if/linux/wlan_cfg80211.h
+++ b/os_if/linux/wlan_cfg80211.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -29,6 +29,8 @@
#include <net/netlink.h>
#include <net/cfg80211.h>
#include <qca_vendor.h>
+#include <qdf_nbuf.h>
+#include "qal_devcfg.h"
#define osif_alert(params...) \
QDF_TRACE_FATAL(QDF_MODULE_ID_OS_IF, params)
@@ -56,6 +58,94 @@
#define osif_nofl_debug(params...) \
QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_OS_IF, params)
+#if defined(NBUF_MEMORY_DEBUG) && defined(NETLINK_BUF_TRACK)
+#define wlan_cfg80211_vendor_free_skb(skb) \
+ qdf_nbuf_free(skb)
+
+#define wlan_cfg80211_vendor_event(skb, gfp) \
+{ \
+ qdf_nbuf_count_dec(skb); \
+ qdf_net_buf_debug_release_skb(skb); \
+ cfg80211_vendor_event(skb, gfp); \
+}
+
+#define wlan_cfg80211_vendor_cmd_reply(skb) \
+{ \
+ qdf_nbuf_count_dec(skb); \
+ qdf_net_buf_debug_release_skb(skb); \
+ cfg80211_vendor_cmd_reply(skb); \
+}
+
+static inline QDF_STATUS wlan_cfg80211_qal_devcfg_send_response(qdf_nbuf_t skb)
+{
+ qdf_nbuf_count_dec(skb);
+ qdf_net_buf_debug_release_skb(skb);
+ return qal_devcfg_send_response(skb);
+}
+
+static inline struct sk_buff *
+__cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int len,
+ const char *func, uint32_t line)
+{
+ struct sk_buff *skb;
+
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+ if (skb) {
+ qdf_nbuf_count_inc(skb);
+ qdf_net_buf_debug_acquire_skb(skb, func, line);
+ }
+ return skb;
+}
+#define wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len) \
+ __cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len, __func__, __LINE__)
+
+static inline struct sk_buff *
+__cfg80211_vendor_event_alloc(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ int approxlen,
+ int event_idx,
+ gfp_t gfp,
+ const char *func,
+ uint32_t line)
+{
+ struct sk_buff *skb;
+
+ skb = cfg80211_vendor_event_alloc(wiphy, wdev,
+ approxlen,
+ event_idx,
+ gfp);
+ if (skb) {
+ qdf_nbuf_count_inc(skb);
+ qdf_net_buf_debug_acquire_skb(skb, func, line);
+ }
+ return skb;
+}
+#define wlan_cfg80211_vendor_event_alloc(wiphy, wdev, len, idx, gfp) \
+ __cfg80211_vendor_event_alloc(wiphy, wdev, len, \
+ idx, gfp, \
+ __func__, __LINE__)
+#else /* NBUF_MEMORY_DEBUG && NETLINK_BUF_TRACK */
+#define wlan_cfg80211_vendor_free_skb(skb) \
+ kfree_skb(skb)
+
+#define wlan_cfg80211_vendor_event(skb, gfp) \
+ cfg80211_vendor_event(skb, gfp)
+
+#define wlan_cfg80211_vendor_cmd_reply(skb) \
+ cfg80211_vendor_cmd_reply(skb)
+
+#define wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len) \
+ cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len)
+
+#define wlan_cfg80211_vendor_event_alloc(wiphy, wdev, len, idx, gfp) \
+ cfg80211_vendor_event_alloc(wiphy, wdev, len, idx, gfp)
+
+static inline QDF_STATUS wlan_cfg80211_qal_devcfg_send_response( qdf_nbuf_t skb)
+{
+ return qal_devcfg_send_response(skb);
+}
+#endif /* NBUF_MEMORY_DEBUG && NETLINK_BUF_TRACK */
+
#undef nla_parse
#undef nla_parse_nested
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
@@ -111,5 +201,4 @@
return nla_put_u64_64bit(skb, attrtype, value, NL80211_ATTR_PAD);
}
#endif
-
#endif
diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h
index 3f59b8f..63eba71 100644
--- a/qdf/inc/qdf_mem.h
+++ b/qdf/inc/qdf_mem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -91,6 +91,13 @@
#ifdef MEMORY_DEBUG
/**
+ * qdf_mem_debug_config_get() - Get the user configuration of mem_debug_disabled
+ *
+ * Return: value of mem_debug_disabled qdf module argument
+ */
+bool qdf_mem_debug_config_get(void);
+
+/**
* qdf_mem_malloc_debug() - debug version of QDF memory allocation API
* @size: Number of bytes of memory to allocate.
* @func: Function name of the call site
@@ -226,6 +233,10 @@
qdf_mem_free_consistent_debug(osdev, dev, size, vaddr, paddr, memctx, \
__func__, __LINE__)
#else
+static inline bool qdf_mem_debug_config_get(void)
+{
+ return false;
+}
/**
* qdf_mem_malloc() - allocation QDF memory
@@ -240,9 +251,10 @@
* specified (for any reason) it returns NULL.
*/
#define qdf_mem_malloc(size) \
- qdf_mem_malloc_fl(size, __func__, __LINE__)
+ __qdf_mem_malloc(size, __func__, __LINE__)
-void *qdf_mem_malloc_fl(qdf_size_t size, const char *func, uint32_t line);
+#define qdf_mem_malloc_fl(size, func, line) \
+ __qdf_mem_malloc(size, func, line)
/**
* qdf_mem_malloc_atomic() - allocation QDF memory atomically
@@ -263,22 +275,16 @@
const char *func,
uint32_t line);
-/**
- * qdf_mem_free() - free QDF memory
- * @ptr: Pointer to the starting address of the memory to be freed.
- *
- * Return: None
- */
-void qdf_mem_free(void *ptr);
+#define qdf_mem_free(ptr) \
+ __qdf_mem_free(ptr)
static inline void qdf_mem_check_for_leaks(void) { }
-void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev,
- qdf_size_t size, qdf_dma_addr_t *paddr);
+#define qdf_mem_alloc_consistent(osdev, dev, size, paddr) \
+ __qdf_mem_alloc_consistent(osdev, dev, size, paddr, __func__, __LINE__)
-void qdf_mem_free_consistent(qdf_device_t osdev, void *dev,
- qdf_size_t size, void *vaddr,
- qdf_dma_addr_t paddr, qdf_dma_context_t memctx);
+#define qdf_mem_free_consistent(osdev, dev, size, vaddr, paddr, memctx) \
+ __qdf_mem_free_consistent(osdev, dev, size, vaddr, paddr, memctx)
void qdf_mem_multi_pages_alloc(qdf_device_t osdev,
struct qdf_mem_multi_page_t *pages,
diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h
index d160847..2e159fc 100644
--- a/qdf/inc/qdf_types.h
+++ b/qdf/inc/qdf_types.h
@@ -377,6 +377,7 @@
* @QDF_MODULE_ID_BLACKLIST_MGR: Blacklist Manager module
* @QDF_MODULE_ID_QLD: QCA Live Debug module ID
* @QDF_MODULE_ID_DYNAMIC_MODE_CHG: Dynamic mode change module ID
+ * @QDF_MODULE_ID_COEX: Coex related config module ID
* @QDF_MODULE_ID_ANY: anything
* @QDF_MODULE_ID_MAX: Max place holder module ID
*/
@@ -495,6 +496,7 @@
QDF_MODULE_ID_BLACKLIST_MGR,
QDF_MODULE_ID_QLD,
QDF_MODULE_ID_DYNAMIC_MODE_CHG,
+ QDF_MODULE_ID_COEX,
QDF_MODULE_ID_ANY,
QDF_MODULE_ID_MAX,
} QDF_MODULE_ID;
diff --git a/qdf/linux/src/i_qdf_mem.h b/qdf/linux/src/i_qdf_mem.h
index c7ffdca..7843f07 100644
--- a/qdf/linux/src/i_qdf_mem.h
+++ b/qdf/linux/src/i_qdf_mem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -100,6 +100,16 @@
#define __qdf_align(a, mask) ALIGN(a, mask)
+#ifdef DISABLE_MEMDEBUG_PANIC
+#define QDF_MEMDEBUG_PANIC(reason_fmt, args...) \
+ do { \
+ /* no-op */ \
+ } while (false)
+#else
+#define QDF_MEMDEBUG_PANIC(reason_fmt, args...) \
+ QDF_DEBUG_PANIC(reason_fmt, ## args)
+#endif
+
/* typedef for dma_data_direction */
typedef enum dma_data_direction __dma_data_direction;
@@ -440,4 +450,61 @@
{
mem_info->pa = dma_pa;
}
+
+/**
+ * __qdf_mem_alloc_consistent() - allocates consistent qdf memory
+ * @osdev: OS device handle
+ * @dev: Pointer to device handle
+ * @size: Size to be allocated
+ * @paddr: Physical address
+ * @func: Function name of the call site
+ * @line: line numbe rof the call site
+ *
+ * Return: pointer of allocated memory or null if memory alloc fails
+ */
+void *__qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev,
+ qdf_size_t size, qdf_dma_addr_t *paddr,
+ const char *func, uint32_t line);
+
+/**
+ * __qdf_mem_malloc() - allocates QDF memory
+ * @size: Number of bytes of memory to allocate.
+ *
+ * @func: Function name of the call site
+ * @line: line numbe rof the call site
+ *
+ * This function will dynamicallly allocate the specified number of bytes of
+ * memory.
+ *
+ * Return:
+ * Upon successful allocate, returns a non-NULL pointer to the allocated
+ * memory. If this function is unable to allocate the amount of memory
+ * specified (for any reason) it returns NULL.
+ */
+void *__qdf_mem_malloc(qdf_size_t size, const char *func, uint32_t line);
+
+/**
+ * __qdf_mem_free() - free QDF memory
+ * @ptr: Pointer to the starting address of the memory to be freed.
+ *
+ * This function will free the memory pointed to by 'ptr'.
+ * Return: None
+ */
+void __qdf_mem_free(void *ptr);
+
+/**
+ * __qdf_mem_free_consistent() - free consistent qdf memory
+ * @osdev: OS device handle
+ * @dev: Pointer to device handle
+ * @size: Size to be allocated
+ * @vaddr: virtual address
+ * @paddr: Physical address
+ * @memctx: Pointer to DMA context
+ *
+ * Return: none
+ */
+void __qdf_mem_free_consistent(qdf_device_t osdev, void *dev,
+ qdf_size_t size, void *vaddr,
+ qdf_dma_addr_t paddr, qdf_dma_context_t memctx);
+
#endif /* __I_QDF_MEM_H */
diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c
index 33ec0fa..ea14a27 100644
--- a/qdf/linux/src/qdf_mem.c
+++ b/qdf/linux/src/qdf_mem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -43,6 +43,13 @@
#include <net/cnss_prealloc.h>
#endif
+#if defined(MEMORY_DEBUG) || defined(NBUF_MEMORY_DEBUG)
+static bool mem_debug_disabled;
+qdf_declare_param(mem_debug_disabled, bool);
+qdf_export_symbol(mem_debug_disabled);
+static bool is_initial_mem_debug_disabled;
+#endif
+
/* Preprocessor Definitions and Constants */
#define QDF_MEM_MAX_MALLOC (4096 * 1024) /* 4 Mega Bytes */
#define QDF_MEM_WARN_THRESHOLD 300 /* ms */
@@ -52,6 +59,39 @@
#include "qdf_debug_domain.h"
#include <qdf_list.h>
+enum list_type {
+ LIST_TYPE_MEM = 0,
+ LIST_TYPE_DMA = 1,
+ LIST_TYPE_MAX,
+};
+
+/**
+ * major_alloc_priv: private data registered to debugfs entry created to list
+ * the list major allocations
+ * @type: type of the list to be parsed
+ * @threshold: configured by user by overwriting the respective debugfs
+ * sys entry. This is to list the functions which requested
+ * memory/dma allocations more than threshold nubmer of times.
+ */
+struct major_alloc_priv {
+ enum list_type type;
+ uint32_t threshold;
+};
+
+static struct major_alloc_priv mem_priv = {
+ /* List type set to mem */
+ LIST_TYPE_MEM,
+ /* initial threshold to list APIs which allocates mem >= 50 times */
+ 50
+};
+
+static struct major_alloc_priv dma_priv = {
+ /* List type set to DMA */
+ LIST_TYPE_DMA,
+ /* initial threshold to list APIs which allocates dma >= 50 times */
+ 50
+};
+
static qdf_list_t qdf_mem_domains[QDF_DEBUG_DOMAIN_COUNT];
static qdf_spinlock_t qdf_mem_list_lock;
@@ -241,7 +281,7 @@
qdf_debug_domain_name(header->domain), header->domain,
qdf_debug_domain_name(current_domain), current_domain);
- QDF_DEBUG_PANIC("Fatal memory error detected @ %s:%d", func, line);
+ QDF_MEMDEBUG_PANIC("Fatal memory error detected @ %s:%d", func, line);
}
#endif /* MEMORY_DEBUG */
@@ -346,15 +386,20 @@
#define QDF_MEM_STAT_TABLE_SIZE 8
/**
- * qdf_mem_domain_print_header() - memory domain header print logic
+ * qdf_mem_debug_print_header() - memory debug header print logic
* @print: the print adapter function
* @print_priv: the private data to be consumed by @print
+ * @threshold: the threshold value set by user to list top allocations
*
* Return: None
*/
-static void qdf_mem_domain_print_header(qdf_abstract_print print,
- void *print_priv)
+static void qdf_mem_debug_print_header(qdf_abstract_print print,
+ void *print_priv,
+ uint32_t threshold)
{
+ if (threshold)
+ print(print_priv, "APIs requested allocations >= %u no of time",
+ threshold);
print(print_priv,
"--------------------------------------------------------------");
print(print_priv,
@@ -368,12 +413,14 @@
* @table: the memory metadata table to print
* @print: the print adapter function
* @print_priv: the private data to be consumed by @print
+ * @threshold: the threshold value set by user to list top allocations
*
* Return: None
*/
static void qdf_mem_meta_table_print(struct __qdf_mem_info *table,
qdf_abstract_print print,
- void *print_priv)
+ void *print_priv,
+ uint32_t threshold)
{
int i;
char debug_str[QDF_DEBUG_STRING_SIZE];
@@ -406,6 +453,37 @@
}
/**
+ * qdf_print_major_alloc() - memory metadata table print logic
+ * @table: the memory metadata table to print
+ * @print: the print adapter function
+ * @print_priv: the private data to be consumed by @print
+ * @threshold: the threshold value set by uset to list top allocations
+ *
+ * Return: None
+ */
+static void qdf_print_major_alloc(struct __qdf_mem_info *table,
+ qdf_abstract_print print,
+ void *print_priv,
+ uint32_t threshold)
+{
+ int i;
+
+ for (i = 0; i < QDF_MEM_STAT_TABLE_SIZE; i++) {
+ if (!table[i].count)
+ break;
+ if (table[i].count >= threshold)
+ print(print_priv,
+ "%6u x %5u = %7uB @ %s:%u %pS %llu",
+ table[i].count,
+ table[i].size,
+ table[i].count * table[i].size,
+ table[i].func,
+ table[i].line, table[i].caller,
+ table[i].time);
+ }
+}
+
+/**
* qdf_mem_meta_table_insert() - insert memory metadata into the given table
* @table: the memory metadata table to insert into
* @meta: the memory metadata to insert
@@ -447,19 +525,25 @@
* @domain: the memory domain to print
* @print: the print adapter function
* @print_priv: the private data to be consumed by @print
+ * @threshold: the threshold value set by uset to list top allocations
+ * @mem_print: pointer to function which prints the memory allocation data
*
* Return: None
*/
static void qdf_mem_domain_print(qdf_list_t *domain,
qdf_abstract_print print,
- void *print_priv)
+ void *print_priv,
+ uint32_t threshold,
+ void (*mem_print)(struct __qdf_mem_info *,
+ qdf_abstract_print,
+ void *, uint32_t))
{
QDF_STATUS status;
struct __qdf_mem_info table[QDF_MEM_STAT_TABLE_SIZE];
qdf_list_node_t *node;
qdf_mem_zero(table, sizeof(table));
- qdf_mem_domain_print_header(print, print_priv);
+ qdf_mem_debug_print_header(print, print_priv, threshold);
/* hold lock while inserting to avoid use-after free of the metadata */
qdf_spin_lock(&qdf_mem_list_lock);
@@ -471,7 +555,7 @@
qdf_spin_unlock(&qdf_mem_list_lock);
if (is_full) {
- qdf_mem_meta_table_print(table, print, print_priv);
+ (*mem_print)(table, print, print_priv, threshold);
qdf_mem_zero(table, sizeof(table));
}
@@ -480,7 +564,7 @@
}
qdf_spin_unlock(&qdf_mem_list_lock);
- qdf_mem_meta_table_print(table, print, print_priv);
+ (*mem_print)(table, print, print_priv, threshold);
}
/**
@@ -541,7 +625,10 @@
seq_printf(seq, "\n%s Memory Domain (Id %d)\n",
qdf_debug_domain_name(domain_id), domain_id);
qdf_mem_domain_print(qdf_mem_list_get(domain_id),
- seq_printf_printer, seq);
+ seq_printf_printer,
+ seq,
+ 0,
+ qdf_mem_meta_table_print);
return 0;
}
@@ -560,6 +647,99 @@
return seq_open(file, &qdf_mem_seq_ops);
}
+/**
+ * qdf_major_alloc_show() - print sequential callback
+ * @seq: seq_file handle
+ * @v: current iterator
+ *
+ * Return: 0 - success
+ */
+static int qdf_major_alloc_show(struct seq_file *seq, void *v)
+{
+ enum qdf_debug_domain domain_id = *(enum qdf_debug_domain *)v;
+ struct major_alloc_priv *priv;
+ qdf_list_t *list;
+
+ priv = (struct major_alloc_priv *)seq->private;
+ seq_printf(seq, "\n%s Memory Domain (Id %d)\n",
+ qdf_debug_domain_name(domain_id), domain_id);
+
+ switch (priv->type) {
+ case LIST_TYPE_MEM:
+ list = qdf_mem_list_get(domain_id);
+ break;
+ case LIST_TYPE_DMA:
+ list = qdf_mem_dma_list(domain_id);
+ break;
+ default:
+ list = NULL;
+ break;
+ }
+
+ if (list)
+ qdf_mem_domain_print(list,
+ seq_printf_printer,
+ seq,
+ priv->threshold,
+ qdf_print_major_alloc);
+
+ return 0;
+}
+
+/* sequential file operation table created to track major allocs */
+static const struct seq_operations qdf_major_allocs_seq_ops = {
+ .start = qdf_mem_seq_start,
+ .next = qdf_mem_seq_next,
+ .stop = qdf_mem_seq_stop,
+ .show = qdf_major_alloc_show,
+};
+
+static int qdf_major_allocs_open(struct inode *inode, struct file *file)
+{
+ void *private = inode->i_private;
+ struct seq_file *seq;
+ int rc;
+
+ rc = seq_open(file, &qdf_major_allocs_seq_ops);
+ if (rc == 0) {
+ seq = file->private_data;
+ seq->private = private;
+ }
+ return rc;
+}
+
+static ssize_t qdf_major_alloc_set_threshold(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *pos)
+{
+ char buf[32];
+ ssize_t buf_size;
+ uint32_t threshold;
+ struct seq_file *seq = file->private_data;
+ struct major_alloc_priv *priv = (struct major_alloc_priv *)seq->private;
+
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (buf_size <= 0)
+ return 0;
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = '\0';
+ if (!kstrtou32(buf, 10, &threshold))
+ priv->threshold = threshold;
+ return buf_size;
+}
+
+/* file operation table for listing major allocs */
+static const struct file_operations fops_qdf_major_allocs = {
+ .owner = THIS_MODULE,
+ .open = qdf_major_allocs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = qdf_major_alloc_set_threshold,
+};
+
/* debugfs file operation table */
static const struct file_operations fops_qdf_mem_debugfs = {
.owner = THIS_MODULE,
@@ -571,6 +751,9 @@
static QDF_STATUS qdf_mem_debug_debugfs_init(void)
{
+ if (is_initial_mem_debug_disabled)
+ return QDF_STATUS_SUCCESS;
+
if (!qdf_mem_debugfs_root)
return QDF_STATUS_E_FAILURE;
@@ -580,6 +763,18 @@
NULL,
&fops_qdf_mem_debugfs);
+ debugfs_create_file("major_mem_allocs",
+ 0600,
+ qdf_mem_debugfs_root,
+ &mem_priv,
+ &fops_qdf_major_allocs);
+
+ debugfs_create_file("major_dma_allocs",
+ 0600,
+ qdf_mem_debugfs_root,
+ &dma_priv,
+ &fops_qdf_major_allocs);
+
return QDF_STATUS_SUCCESS;
}
@@ -893,6 +1088,15 @@
/* External Function implementation */
#ifdef MEMORY_DEBUG
+/**
+ * qdf_mem_debug_config_get() - Get the user configuration of mem_debug_disabled
+ *
+ * Return: value of mem_debug_disabled qdf module argument
+ */
+bool qdf_mem_debug_config_get(void)
+{
+ return mem_debug_disabled;
+}
/**
* qdf_mem_debug_init() - initialize qdf memory debug functionality
@@ -903,6 +1107,11 @@
{
int i;
+ is_initial_mem_debug_disabled = qdf_mem_debug_config_get();
+
+ if (is_initial_mem_debug_disabled)
+ return;
+
/* Initalizing the list with maximum size of 60000 */
for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
qdf_list_create(&qdf_mem_domains[i], 60000);
@@ -918,12 +1127,19 @@
qdf_mem_domain_check_for_leaks(enum qdf_debug_domain domain,
qdf_list_t *mem_list)
{
+ if (is_initial_mem_debug_disabled)
+ return 0;
+
if (qdf_list_empty(mem_list))
return 0;
qdf_err("Memory leaks detected in %s domain!",
qdf_debug_domain_name(domain));
- qdf_mem_domain_print(mem_list, qdf_err_printer, NULL);
+ qdf_mem_domain_print(mem_list,
+ qdf_err_printer,
+ NULL,
+ 0,
+ qdf_mem_meta_table_print);
return mem_list->count;
}
@@ -933,13 +1149,16 @@
uint32_t leak_count = 0;
int i;
+ if (is_initial_mem_debug_disabled)
+ return;
+
/* detect and print leaks */
for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
leak_count += qdf_mem_domain_check_for_leaks(i, domains + i);
if (leak_count)
- QDF_DEBUG_PANIC("%u fatal memory leaks detected!",
- leak_count);
+ QDF_MEMDEBUG_PANIC("%u fatal memory leaks detected!",
+ leak_count);
}
/**
@@ -951,6 +1170,9 @@
{
int i;
+ if (is_initial_mem_debug_disabled)
+ return;
+
/* mem */
qdf_mem_domain_set_check_for_leaks(qdf_mem_domains);
for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i)
@@ -975,6 +1197,9 @@
void *ptr;
unsigned long start, duration;
+ if (is_initial_mem_debug_disabled)
+ return __qdf_mem_malloc(size, func, line);
+
if (!size || size > QDF_MEM_MAX_MALLOC) {
qdf_err("Cannot malloc %zu bytes @ %s:%d", size, func, line);
return NULL;
@@ -1022,6 +1247,11 @@
struct qdf_mem_header *header;
enum qdf_mem_validation_bitmap error_bitmap;
+ if (is_initial_mem_debug_disabled) {
+ __qdf_mem_free(ptr);
+ return;
+ }
+
/* freeing a null pointer is valid */
if (qdf_unlikely(!ptr))
return;
@@ -1030,8 +1260,8 @@
return;
if (qdf_unlikely((qdf_size_t)ptr <= sizeof(*header)))
- QDF_DEBUG_PANIC("Failed to free invalid memory location %pK",
- ptr);
+ QDF_MEMDEBUG_PANIC("Failed to free invalid memory location %pK",
+ ptr);
qdf_talloc_assert_no_children_fl(ptr, func, line);
@@ -1062,12 +1292,15 @@
qdf_list_t *dma_list = qdf_mem_dma_list(current_domain);
uint32_t leaks_count = 0;
+ if (is_initial_mem_debug_disabled)
+ return;
+
leaks_count += qdf_mem_domain_check_for_leaks(current_domain, mem_list);
leaks_count += qdf_mem_domain_check_for_leaks(current_domain, dma_list);
if (leaks_count)
- QDF_DEBUG_PANIC("%u fatal memory leaks detected!",
- leaks_count);
+ QDF_MEMDEBUG_PANIC("%u fatal memory leaks detected!",
+ leaks_count);
}
/**
@@ -1232,33 +1465,6 @@
static void qdf_mem_debug_exit(void) {}
-void *qdf_mem_malloc_fl(size_t size, const char *func, uint32_t line)
-{
- void *ptr;
-
- if (!size || size > QDF_MEM_MAX_MALLOC) {
- qdf_nofl_err("Cannot malloc %zu bytes @ %s:%d", size, func,
- line);
- return NULL;
- }
-
- ptr = qdf_mem_prealloc_get(size);
- if (ptr)
- return ptr;
-
- ptr = kzalloc(size, qdf_mem_malloc_flags());
- if (!ptr) {
- qdf_nofl_err("Failed to malloc %zuB @ %s:%d",
- size, func, line);
- return NULL;
- }
-
- qdf_mem_kmalloc_inc(ksize(ptr));
-
- return ptr;
-}
-qdf_export_symbol(qdf_mem_malloc_fl);
-
void *qdf_mem_malloc_atomic_fl(size_t size, const char *func, uint32_t line)
{
void *ptr;
@@ -1281,29 +1487,6 @@
qdf_export_symbol(qdf_mem_malloc_atomic_fl);
/**
- * qdf_mem_free() - free QDF memory
- * @ptr: Pointer to the starting address of the memory to be free'd.
- *
- * This function will free the memory pointed to by 'ptr'.
- *
- * Return: None
- */
-void qdf_mem_free(void *ptr)
-{
- if (!ptr)
- return;
-
- if (qdf_mem_prealloc_put(ptr))
- return;
-
- qdf_mem_kmalloc_dec(ksize(ptr));
-
- kfree(ptr);
-}
-
-qdf_export_symbol(qdf_mem_free);
-
-/**
* qdf_mem_multi_pages_alloc() - allocate large size of kernel memory
* @osdev: OS device handle pointer
* @pages: Multi page information storage
@@ -1444,6 +1627,46 @@
qdf_export_symbol(qdf_mem_multi_pages_free);
#endif
+void __qdf_mem_free(void *ptr)
+{
+ if (!ptr)
+ return;
+
+ if (qdf_mem_prealloc_put(ptr))
+ return;
+
+ qdf_mem_kmalloc_dec(ksize(ptr));
+
+ kfree(ptr);
+}
+
+qdf_export_symbol(__qdf_mem_free);
+
+void *__qdf_mem_malloc(size_t size, const char *func, uint32_t line)
+{
+ void *ptr;
+
+ if (!size || size > QDF_MEM_MAX_MALLOC) {
+ qdf_nofl_err("Cannot malloc %zu bytes @ %s:%d", size, func,
+ line);
+ return NULL;
+ }
+
+ ptr = qdf_mem_prealloc_get(size);
+ if (ptr)
+ return ptr;
+
+ ptr = kzalloc(size, qdf_mem_malloc_flags());
+ if (!ptr)
+ return NULL;
+
+ qdf_mem_kmalloc_inc(ksize(ptr));
+
+ return ptr;
+}
+
+qdf_export_symbol(__qdf_mem_malloc);
+
void *qdf_aligned_malloc_fl(uint32_t *size,
void **vaddr_unaligned,
qdf_dma_addr_t *paddr_unaligned,
@@ -1797,6 +2020,11 @@
struct qdf_mem_header *header;
void *vaddr;
+ if (is_initial_mem_debug_disabled)
+ return __qdf_mem_alloc_consistent(osdev, dev,
+ size, paddr,
+ func, line);
+
if (!size || size > QDF_MEM_MAX_MALLOC) {
qdf_err("Cannot malloc %zu bytes @ %s:%d", size, func, line);
return NULL;
@@ -1840,6 +2068,14 @@
struct qdf_mem_header *header;
enum qdf_mem_validation_bitmap error_bitmap;
+ if (is_initial_mem_debug_disabled) {
+ __qdf_mem_free_consistent(
+ osdev, dev,
+ size, vaddr,
+ paddr, memctx);
+ return;
+ }
+
/* freeing a null pointer is valid */
if (qdf_unlikely(!vaddr))
return;
@@ -1867,31 +2103,39 @@
qdf_mem_dma_free(dev, size + QDF_DMA_MEM_DEBUG_SIZE, vaddr, paddr);
}
qdf_export_symbol(qdf_mem_free_consistent_debug);
+#endif /* MEMORY_DEBUG */
-#else
-
-void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev,
- qdf_size_t size, qdf_dma_addr_t *paddr)
+void __qdf_mem_free_consistent(qdf_device_t osdev, void *dev,
+ qdf_size_t size, void *vaddr,
+ qdf_dma_addr_t paddr, qdf_dma_context_t memctx)
{
- void *vaddr = qdf_mem_dma_alloc(osdev, dev, size, paddr);
+ qdf_mem_dma_dec(size);
+ qdf_mem_dma_free(dev, size, vaddr, paddr);
+}
+
+qdf_export_symbol(__qdf_mem_free_consistent);
+
+void *__qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev,
+ qdf_size_t size, qdf_dma_addr_t *paddr,
+ const char *func, uint32_t line)
+{
+ void *vaddr;
+
+ if (!size || size > QDF_MEM_MAX_MALLOC) {
+ qdf_nofl_err("Cannot malloc %zu bytes @ %s:%d",
+ size, func, line);
+ return NULL;
+ }
+
+ vaddr = qdf_mem_dma_alloc(osdev, dev, size, paddr);
if (vaddr)
qdf_mem_dma_inc(size);
return vaddr;
}
-qdf_export_symbol(qdf_mem_alloc_consistent);
-void qdf_mem_free_consistent(qdf_device_t osdev, void *dev,
- qdf_size_t size, void *vaddr,
- qdf_dma_addr_t paddr, qdf_dma_context_t memctx)
-{
- qdf_mem_dma_dec(size);
- qdf_mem_dma_free(dev, size, vaddr, paddr);
-}
-qdf_export_symbol(qdf_mem_free_consistent);
-
-#endif /* MEMORY_DEBUG */
+qdf_export_symbol(__qdf_mem_alloc_consistent);
void *qdf_aligned_mem_alloc_consistent_fl(
qdf_device_t osdev, uint32_t *size,
diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c
index 91f4586..923654a 100644
--- a/qdf/linux/src/qdf_nbuf.c
+++ b/qdf/linux/src/qdf_nbuf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -113,6 +113,10 @@
static qdf_atomic_t nbuf_count;
#endif
+#if defined(NBUF_MEMORY_DEBUG)
+static bool is_initial_mem_debug_disabled;
+#endif
+
/**
* qdf_nbuf_tx_desc_count_display() - Displays the packet counter
*
@@ -616,6 +620,9 @@
{
QDF_STATUS status;
+ if (is_initial_mem_debug_disabled)
+ return QDF_STATUS_SUCCESS;
+
status = qdf_tracker_track(&qdf_nbuf_map_tracker, nbuf, func, line);
if (QDF_IS_STATUS_ERROR(status))
return status;
@@ -628,6 +635,9 @@
static void
qdf_nbuf_untrack_map(qdf_nbuf_t nbuf, const char *func, uint32_t line)
{
+ if (is_initial_mem_debug_disabled)
+ return;
+
qdf_nbuf_history_add(nbuf, func, line, QDF_NBUF_UNMAP);
qdf_tracker_untrack(&qdf_nbuf_map_tracker, nbuf, func, line);
}
@@ -784,8 +794,8 @@
&map_func, &map_line))
return;
- QDF_DEBUG_PANIC("Nbuf freed @ %s:%u while mapped from %s:%u",
- func, line, map_func, map_line);
+ QDF_MEMDEBUG_PANIC("Nbuf freed @ %s:%u while mapped from %s:%u",
+ func, line, map_func, map_line);
}
#else
static inline void qdf_nbuf_map_tracking_init(void)
@@ -2325,6 +2335,11 @@
{
uint32_t i;
+ is_initial_mem_debug_disabled = qdf_mem_debug_config_get();
+
+ if (is_initial_mem_debug_disabled)
+ return;
+
qdf_atomic_set(&qdf_nbuf_history_index, -1);
qdf_nbuf_map_tracking_init();
@@ -2354,6 +2369,9 @@
QDF_NBUF_TRACK *p_node;
QDF_NBUF_TRACK *p_prev;
+ if (is_initial_mem_debug_disabled)
+ return;
+
for (i = 0; i < QDF_NET_BUF_TRACK_MAX_SIZE; i++) {
spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag);
p_node = gp_qdf_net_buf_track_tbl[i];
@@ -2433,6 +2451,9 @@
QDF_NBUF_TRACK *p_node;
QDF_NBUF_TRACK *new_node;
+ if (is_initial_mem_debug_disabled)
+ return;
+
new_node = qdf_nbuf_track_alloc();
i = qdf_net_buf_debug_hash(net_buf);
@@ -2473,6 +2494,9 @@
unsigned long irq_flag;
QDF_NBUF_TRACK *p_node;
+ if (is_initial_mem_debug_disabled)
+ return;
+
i = qdf_net_buf_debug_hash(net_buf);
spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag);
@@ -2502,6 +2526,9 @@
unsigned long irq_flag;
QDF_NBUF_TRACK *p_prev;
+ if (is_initial_mem_debug_disabled)
+ return;
+
i = qdf_net_buf_debug_hash(net_buf);
spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag);
@@ -2547,6 +2574,9 @@
{
qdf_nbuf_t ext_list = qdf_nbuf_get_ext_list(net_buf);
+ if (is_initial_mem_debug_disabled)
+ return;
+
while (ext_list) {
/*
* Take care to add if it is Jumbo packet connected using
@@ -2576,6 +2606,9 @@
{
qdf_nbuf_t ext_list = qdf_nbuf_get_ext_list(net_buf);
+ if (is_initial_mem_debug_disabled)
+ return;
+
while (ext_list) {
/*
* Take care to free if it is Jumbo packet connected using
@@ -2607,6 +2640,11 @@
{
qdf_nbuf_t nbuf;
+ if (is_initial_mem_debug_disabled)
+ return __qdf_nbuf_alloc(osdev, size,
+ reserve, align,
+ prio, func, line);
+
nbuf = __qdf_nbuf_alloc(osdev, size, reserve, align, prio, func, line);
/* Store SKB in internal QDF tracking table */
@@ -2628,6 +2666,9 @@
if (qdf_unlikely(!nbuf))
return;
+ if (is_initial_mem_debug_disabled)
+ goto free_buf;
+
if (qdf_nbuf_get_users(nbuf) > 1)
goto free_buf;
@@ -2656,6 +2697,9 @@
{
qdf_nbuf_t cloned_buf = __qdf_nbuf_clone(buf);
+ if (is_initial_mem_debug_disabled)
+ return cloned_buf;
+
if (qdf_unlikely(!cloned_buf))
return NULL;
@@ -2671,6 +2715,9 @@
{
qdf_nbuf_t copied_buf = __qdf_nbuf_copy(buf);
+ if (is_initial_mem_debug_disabled)
+ return copied_buf;
+
if (qdf_unlikely(!copied_buf))
return NULL;
@@ -2691,6 +2738,9 @@
if (qdf_unlikely(!copied_buf))
return NULL;
+ if (is_initial_mem_debug_disabled)
+ return copied_buf;
+
/* Store SKB in internal QDF tracking table */
qdf_net_buf_debug_add_node(copied_buf, 0, func, line);
qdf_nbuf_history_add(copied_buf, func, line,
diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c
index 332976d..b0252a9 100644
--- a/qdf/linux/src/qdf_trace.c
+++ b/qdf/linux/src/qdf_trace.c
@@ -2819,6 +2819,7 @@
[QDF_MODULE_ID_BLACKLIST_MGR] = {"blm"},
[QDF_MODULE_ID_QLD] = {"QLD"},
[QDF_MODULE_ID_DYNAMIC_MODE_CHG] = {"Dynamic Mode Change"},
+ [QDF_MODULE_ID_COEX] = {"COEX"},
[QDF_MODULE_ID_ANY] = {"ANY"},
};
qdf_export_symbol(g_qdf_category_name);
@@ -3279,6 +3280,7 @@
[QDF_MODULE_ID_BLACKLIST_MGR] = QDF_TRACE_LEVEL_NONE,
[QDF_MODULE_ID_QLD] = QDF_TRACE_LEVEL_ERROR,
[QDF_MODULE_ID_DYNAMIC_MODE_CHG] = QDF_TRACE_LEVEL_INFO,
+ [QDF_MODULE_ID_COEX] = QDF_TRACE_LEVEL_ERROR,
[QDF_MODULE_ID_ANY] = QDF_TRACE_LEVEL_INFO,
};
diff --git a/scheduler/inc/scheduler_core.h b/scheduler/inc/scheduler_core.h
index 680ac20..0fe8d48 100644
--- a/scheduler/inc/scheduler_core.h
+++ b/scheduler/inc/scheduler_core.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -95,11 +95,11 @@
* @resume_sch_event: scheduler resume wait event
* @sch_thread_lock: scheduler thread lock
* @sch_last_qidx: scheduler last qidx allocation
+ * @watchdog_msg_type: 'type' of the current msg being processed
* @hdd_callback: os if suspend callback
* @legacy_wma_handler: legacy wma message handler
* @legacy_sys_handler: legacy sys message handler
* @watchdog_timer: timer for triggering a scheduler watchdog bite
- * @watchdog_msg_type: 'type' of the current msg being processed
* @watchdog_callback: the callback of the current msg being processed
*/
struct scheduler_ctx {
@@ -112,11 +112,11 @@
qdf_event_t resume_sch_event;
qdf_spinlock_t sch_thread_lock;
uint8_t sch_last_qidx;
+ uint16_t watchdog_msg_type;
hdd_suspend_callback hdd_callback;
scheduler_msg_process_fn_t legacy_wma_handler;
scheduler_msg_process_fn_t legacy_sys_handler;
qdf_timer_t watchdog_timer;
- uint16_t watchdog_msg_type;
void *watchdog_callback;
};
diff --git a/target_if/coex/inc/target_if_coex.h b/target_if/coex/inc/target_if_coex.h
new file mode 100644
index 0000000..d496efa
--- /dev/null
+++ b/target_if/coex/inc/target_if_coex.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: contains coex target if declarations
+ */
+#ifndef __TARGET_IF_COEX_H__
+#define __TARGET_IF_COEX_H__
+
+#include <target_if.h>
+
+/**
+ * target_if_coex_register_tx_ops() - Register coex target_if tx ops
+ * @tx_ops: pointer to target if tx ops
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS
+target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops);
+#endif
diff --git a/target_if/coex/src/target_if_coex.c b/target_if/coex/src/target_if_coex.c
new file mode 100644
index 0000000..6dd3c70
--- /dev/null
+++ b/target_if/coex/src/target_if_coex.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: contains coex target if functions
+ */
+#include <wlan_coex_main.h>
+#include <target_if_coex.h>
+
+static QDF_STATUS
+target_if_coex_config_send(struct wlan_objmgr_pdev *pdev,
+ struct coex_config_params *param)
+{
+ wmi_unified_t pdev_wmi_handle;
+
+ pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
+ if (!pdev_wmi_handle) {
+ coex_err("Invalid PDEV WMI handle");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return wmi_unified_send_coex_config_cmd(pdev_wmi_handle, param);
+}
+
+QDF_STATUS
+target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+ struct wlan_lmac_if_coex_tx_ops *coex_ops;
+
+ if (!tx_ops) {
+ coex_err("target if tx ops is NULL!");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ coex_ops = &tx_ops->coex_ops;
+ coex_ops->coex_config_send = target_if_coex_config_send;
+
+ return QDF_STATUS_SUCCESS;
+}
diff --git a/target_if/core/src/target_if_main.c b/target_if/core/src/target_if_main.c
index f860f59..a37f721 100644
--- a/target_if/core/src/target_if_main.c
+++ b/target_if/core/src/target_if_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -80,6 +80,10 @@
#endif
#include <target_if_vdev_mgr_tx_ops.h>
+#ifdef FEATURE_COEX
+#include <target_if_coex.h>
+#endif
+
static struct target_if_ctx *g_target_if_ctx;
struct target_if_ctx *target_if_get_ctx()
@@ -338,6 +342,20 @@
}
#endif
+#ifdef FEATURE_COEX
+static QDF_STATUS
+target_if_coex_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+ return target_if_coex_register_tx_ops(tx_ops);
+}
+#else
+static inline QDF_STATUS
+target_if_coex_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+ return QDF_STATUS_SUCCESS;
+}
+#endif
+
static void target_if_target_tx_ops_register(
struct wlan_lmac_if_tx_ops *tx_ops)
{
@@ -441,6 +459,8 @@
target_if_vdev_mgr_tx_ops_register(tx_ops);
+ target_if_coex_tx_ops_register(tx_ops);
+
/* Converged UMAC components to register their TX-ops here */
return QDF_STATUS_SUCCESS;
}
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
index 47f9e0f..c266a74 100644
--- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
@@ -354,6 +354,7 @@
struct wlan_objmgr_pdev *pdev, void *data)
{
struct direct_buf_rx_pdev_obj *dbr_pdev_obj;
+ struct direct_buf_rx_psoc_obj *dbr_psoc_obj;
struct wlan_objmgr_psoc *psoc;
uint8_t num_modules;
QDF_STATUS status;
@@ -372,13 +373,20 @@
return QDF_STATUS_E_INVAL;
}
+ dbr_psoc_obj =
+ wlan_objmgr_psoc_get_comp_private_obj(psoc,
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX);
+
+ if (!dbr_psoc_obj) {
+ direct_buf_rx_err("dir buf rx psoc object is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+
dbr_pdev_obj = qdf_mem_malloc(sizeof(*dbr_pdev_obj));
if (!dbr_pdev_obj)
return QDF_STATUS_E_NOMEM;
- direct_buf_rx_info("Dbr pdev obj %pK", dbr_pdev_obj);
-
status = wlan_objmgr_pdev_component_obj_attach(pdev,
WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
dbr_pdev_obj, QDF_STATUS_SUCCESS);
@@ -390,9 +398,13 @@
return status;
}
+ dbr_psoc_obj->dbr_pdev_obj[wlan_objmgr_pdev_get_pdev_id(pdev)] =
+ dbr_pdev_obj;
+
num_modules = get_num_dbr_modules_per_pdev(pdev);
- direct_buf_rx_info("Number of modules = %d pdev %d", num_modules,
- wlan_objmgr_pdev_get_pdev_id(pdev));
+ direct_buf_rx_info("Number of modules = %d pdev %d DBR pdev obj %pK",
+ num_modules, wlan_objmgr_pdev_get_pdev_id(pdev),
+ dbr_pdev_obj);
dbr_pdev_obj->num_modules = num_modules;
if (!dbr_pdev_obj->num_modules) {
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
index 2828b97..a06375f 100644
--- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
@@ -210,10 +210,12 @@
* struct direct_buf_rx_psoc_obj - Direct Buf RX psoc object struct
* @hal_soc: Opaque HAL SOC handle
* @osdev: QDF os device handle
+ * @dbr_pdev_objs: array of DBR pdev objects
*/
struct direct_buf_rx_psoc_obj {
void *hal_soc;
qdf_device_t osdev;
+ struct direct_buf_rx_pdev_obj *dbr_pdev_obj[WLAN_UMAC_MAX_PDEVS];
};
/**
diff --git a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c
index 22793fd..ce97b1c 100644
--- a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c
+++ b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -3193,7 +3193,7 @@
if (opmode == QDF_STA_MODE) {
peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CRYPTO_ID);
if (!peer) {
- crypto_err("peer NULL");
+ crypto_debug("peer NULL");
return QDF_STATUS_E_INVAL;
}
}
diff --git a/umac/cmn_services/inc/wlan_cmn.h b/umac/cmn_services/inc/wlan_cmn.h
index 42e516d..494a0c0 100644
--- a/umac/cmn_services/inc/wlan_cmn.h
+++ b/umac/cmn_services/inc/wlan_cmn.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -272,6 +272,7 @@
* @WLAN_UMAC_COMP_FWOL FW Offload
* @WLAN_UMAC_COMP_INTEROP_ISSUES_AP interop issues ap component
* @WLAN_UMAC_COMP_BLACKLIST_MGR: Blacklist mgr component
+ * @WLAN_UMAC_COMP_COEX: Coex config component
* @WLAN_UMAC_COMP_ID_MAX: Maximum components in UMAC
*
* This id is static.
@@ -311,6 +312,7 @@
WLAN_UMAC_COMP_CFR = 30,
WLAN_UMAC_COMP_INTEROP_ISSUES_AP = 31,
WLAN_UMAC_COMP_BLACKLIST_MGR = 32,
+ WLAN_UMAC_COMP_COEX = 33,
WLAN_UMAC_COMP_ID_MAX,
};
diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h
index 7c7cd8d..3ea38ae 100644
--- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h
+++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -166,6 +166,8 @@
#define WLAN_VDEV_FEXT_MAT 0x20000000
/* VDEV is wired PSTA*/
#define WLAN_VDEV_FEXT_WIRED_PSTA 0x40000000
+ /* Fils discovery on 6G SAP*/
+#define WLAN_VDEV_FEXT_FILS_DISC_6G_SAP 0x80000000
/* VDEV OP flags */
/* if the vap destroyed by user */
@@ -253,11 +255,11 @@
* struct wlan_channel - channel structure
* @ch_freq: Channel in Mhz.
* @ch_ieee: IEEE channel number.
- * @ch_flags: Channel flags.
- * @ch_flagext: Channel extension flags.
- * @ch_maxpower: Maximum tx power in dBm.
* @ch_freq_seg1: Channel Center frequeny for VHT80/160 and HE80/160.
* @ch_freq_seg2: Second channel Center frequency applicable for 80+80MHz mode.
+ * @ch_maxpower: Maximum tx power in dBm.
+ * @ch_flagext: Channel extension flags.
+ * @ch_flags: Channel flags.
* @ch_cfreq1: channel center frequency for primary
* @ch_cfreq2: channel center frequency for secondary
* @ch_width: Channel width.
@@ -266,11 +268,11 @@
struct wlan_channel {
uint16_t ch_freq;
uint8_t ch_ieee;
- uint64_t ch_flags;
- uint16_t ch_flagext;
- int8_t ch_maxpower;
uint8_t ch_freq_seg1;
uint8_t ch_freq_seg2;
+ int8_t ch_maxpower;
+ uint16_t ch_flagext;
+ uint64_t ch_flags;
uint32_t ch_cfreq1;
uint32_t ch_cfreq2;
enum phy_ch_width ch_width;
diff --git a/umac/coex/core/inc/wlan_coex_main.h b/umac/coex/core/inc/wlan_coex_main.h
new file mode 100644
index 0000000..22cde21
--- /dev/null
+++ b/umac/coex/core/inc/wlan_coex_main.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains declarations for coex core functions
+ */
+
+#ifndef _WLAN_COEX_MAIN_API_H_
+#define _WLAN_COEX_MAIN_API_H_
+
+#ifdef FEATURE_COEX
+#include "wlan_coex_ucfg_api.h"
+#include "wmi_unified_param.h"
+#include "wlan_objmgr_psoc_obj.h"
+#include "wlan_objmgr_vdev_obj.h"
+
+#define coex_err(params...) \
+ QDF_TRACE_ERROR(QDF_MODULE_ID_COEX, params)
+#define coex_info(params...) \
+ QDF_TRACE_INFO(QDF_MODULE_ID_COEX, params)
+#define coex_debug(params...) \
+ QDF_TRACE_DEBUG(QDF_MODULE_ID_COEX, params)
+
+/**
+ * struct coex_psoc_obj - coex object definition
+ * @btc_chain_mode: BT Coex chain mode.
+ * @coex_config_updated: callback functions for each config type, which will
+ * be called when config is updated.
+ */
+struct coex_psoc_obj {
+ uint8_t btc_chain_mode;
+ update_coex_cb coex_config_updated[COEX_CONFIG_TYPE_MAX];
+};
+
+/**
+ * wlan_psoc_get_coex_obj() - private API to get coex object from psoc
+ * @psoc: psoc object
+ *
+ * Return: coex object
+ */
+#define wlan_psoc_get_coex_obj(psoc) \
+ wlan_psoc_get_coex_obj_fl(psoc, __func__, __LINE__)
+
+static inline struct coex_psoc_obj *
+wlan_psoc_get_coex_obj_fl(struct wlan_objmgr_psoc *psoc,
+ const char *func, uint32_t line)
+{
+ struct coex_psoc_obj *psoc_obj;
+
+ psoc_obj = (struct coex_psoc_obj *)
+ wlan_objmgr_psoc_get_comp_private_obj(psoc,
+ WLAN_UMAC_COMP_COEX);
+ if (!psoc_obj) {
+ coex_err("%s:%u, Failed to get coex psoc object", func, line);
+ return NULL;
+ }
+ return psoc_obj;
+}
+
+/**
+ * wlan_coex_psoc_init() - API to initialize coex component
+ * @psoc: soc context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_coex_psoc_init(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_coex_psoc_deinit() - API to deinitialize coex component
+ * @psoc: soc context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_coex_psoc_deinit(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_coex_config_send() - private API to send coex config
+ * @vdev: pointer to vdev object
+ * @param: parameters of coex config
+ *
+ * Return: status of operation
+ */
+QDF_STATUS wlan_coex_config_send(struct wlan_objmgr_vdev *vdev,
+ struct coex_config_params *param);
+
+/**
+ * wlan_coex_config_updated() - private API to notify that coex config
+ * is updated.
+ * @vdev: pointer to vdev object
+ * @type: type of coex config
+ *
+ * Return: status of operation
+ */
+QDF_STATUS
+wlan_coex_config_updated(struct wlan_objmgr_vdev *vdev, uint8_t type);
+
+/**
+ * wlan_coex_psoc_created_notification() - PSOC obj create callback
+ * @psoc: PSOC object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization to
+ * get notified when the object is created.
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS wlan_coex_psoc_created_notification(struct wlan_objmgr_psoc *psoc,
+ void *arg_list);
+
+/**
+ * wlan_coex_psoc_destroyed_notification() - PSOC obj delete callback
+ * @psoc: PSOC object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization to
+ * get notified when the object is deleted.
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS wlan_coex_psoc_destroyed_notification(struct wlan_objmgr_psoc *psoc,
+ void *arg_list);
+
+/**
+ * wlan_coex_psoc_set_btc_chain_mode() - private API to set BT coex chain mode
+ * for psoc
+ * @psoc: pointer to psoc object
+ * @val: BT coex chain mode
+ *
+ * Return : status of operation
+ */
+QDF_STATUS
+wlan_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val);
+
+/**
+ * wlan_coex_psoc_get_btc_chain_mode() - private API to get BT coex chain mode
+ * from psoc
+ * @psoc: pointer to psoc object
+ * @val: pointer to BT coex chain mode
+ *
+ * Return : status of operation
+ */
+QDF_STATUS
+wlan_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val);
+#endif
+#endif
diff --git a/umac/coex/core/src/wlan_coex_main.c b/umac/coex/core/src/wlan_coex_main.c
new file mode 100644
index 0000000..d48b6e5
--- /dev/null
+++ b/umac/coex/core/src/wlan_coex_main.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains definitions for coex core functions
+ */
+
+#include <wlan_coex_ucfg_api.h>
+#include <wlan_coex_tgt_api.h>
+#include <wlan_coex_main.h>
+
+QDF_STATUS wlan_coex_psoc_created_notification(struct wlan_objmgr_psoc *psoc,
+ void *arg_list)
+{
+ struct coex_psoc_obj *psoc_obj;
+ QDF_STATUS status;
+
+ psoc_obj = qdf_mem_malloc(sizeof(*psoc_obj));
+ if (!psoc_obj)
+ return QDF_STATUS_E_NOMEM;
+
+ /* Attach scan private date to psoc */
+ status = wlan_objmgr_psoc_component_obj_attach(psoc,
+ WLAN_UMAC_COMP_COEX,
+ psoc_obj,
+ QDF_STATUS_SUCCESS);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ coex_err("Failed to attach psoc coex component");
+ qdf_mem_free(psoc_obj);
+ } else {
+ coex_debug("Coex object attach to psoc successful");
+ }
+
+ return status;
+}
+
+QDF_STATUS wlan_coex_psoc_destroyed_notification(struct wlan_objmgr_psoc *psoc,
+ void *arg_list)
+{
+ void *psoc_obj;
+ QDF_STATUS status;
+
+ psoc_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!psoc_obj)
+ return QDF_STATUS_E_FAILURE;
+
+ status = wlan_objmgr_psoc_component_obj_detach(psoc,
+ WLAN_UMAC_COMP_COEX,
+ psoc_obj);
+ if (QDF_IS_STATUS_ERROR(status))
+ coex_err("Failed to detach psoc coex component");
+
+ qdf_mem_free(psoc_obj);
+
+ return status;
+}
+
+QDF_STATUS
+wlan_coex_psoc_init(struct wlan_objmgr_psoc *psoc)
+{
+ struct coex_psoc_obj *coex_obj;
+
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!coex_obj)
+ return QDF_STATUS_E_INVAL;
+
+ coex_obj->btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED;
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_coex_psoc_deinit(struct wlan_objmgr_psoc *psoc)
+{
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_coex_config_send(struct wlan_objmgr_vdev *vdev,
+ struct coex_config_params *param)
+{
+ QDF_STATUS status;
+
+ status = tgt_send_coex_config(vdev, param);
+ if (QDF_IS_STATUS_ERROR(status))
+ coex_err("failed to send coex config");
+
+ return status;
+}
+
+QDF_STATUS
+wlan_coex_config_updated(struct wlan_objmgr_vdev *vdev, uint8_t type)
+{
+ struct wlan_objmgr_psoc *psoc;
+ struct coex_psoc_obj *coex_obj;
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+ if (!vdev) {
+ coex_err("NULL vdev");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (type >= COEX_CONFIG_TYPE_MAX) {
+ coex_err("config type out of range: %d", type);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ psoc = wlan_vdev_get_psoc(vdev);
+ if (!psoc) {
+ coex_err("NULL psoc");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!coex_obj)
+ return QDF_STATUS_E_INVAL;
+
+ if (coex_obj->coex_config_updated[type])
+ status = coex_obj->coex_config_updated[type](vdev);
+
+ return status;
+}
+
+QDF_STATUS
+wlan_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val)
+{
+ struct coex_psoc_obj *coex_obj;
+
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!coex_obj)
+ return QDF_STATUS_E_INVAL;
+
+ coex_obj->btc_chain_mode = val;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val)
+{
+ struct coex_psoc_obj *coex_obj;
+
+ if (!val) {
+ coex_err("invalid param for getting btc chain mode");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!coex_obj)
+ return QDF_STATUS_E_INVAL;
+
+ *val = coex_obj->btc_chain_mode;
+ return QDF_STATUS_SUCCESS;
+}
diff --git a/umac/coex/dispatcher/inc/wlan_coex_tgt_api.h b/umac/coex/dispatcher/inc/wlan_coex_tgt_api.h
new file mode 100644
index 0000000..452ce1b
--- /dev/null
+++ b/umac/coex/dispatcher/inc/wlan_coex_tgt_api.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains coex south bound interface definitions
+ */
+
+#ifndef _WLAN_COEX_TGT_API_H_
+#define _WLAN_COEX_TGT_API_H_
+
+#ifdef FEATURE_COEX
+struct coex_config_params;
+
+/**
+ * tgt_send_coex_config() - invoke target_if send coex config
+ * @vdev: vdev object
+ * @param: coex config parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+tgt_send_coex_config(struct wlan_objmgr_vdev *vdev,
+ struct coex_config_params *param);
+#endif
+#endif
diff --git a/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h b/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h
new file mode 100644
index 0000000..2fd5a24
--- /dev/null
+++ b/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains coex north bound interface declarations
+ */
+
+#ifndef _WLAN_COEX_UCFG_API_H_
+#define _WLAN_COEX_UCFG_API_H_
+
+#include "qdf_status.h"
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include "qca_vendor.h"
+
+#define WLAN_COEX_BTC_CHAIN_MODE_SHARED QCA_BTC_CHAIN_SHARED
+#define WLAN_COEX_BTC_CHAIN_MODE_SEPARATED QCA_BTC_CHAIN_SEPARATED
+#define WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED 0xFF
+
+/**
+ * enum coex_config_type - coex config type definitions
+ * @COEX_CONFIG_BTC_CHAIN_MODE: config BT coex chain mode
+ * @COEX_CONFIG_TYPE_MAX: max value
+ */
+enum coex_config_type {
+ COEX_CONFIG_BTC_CHAIN_MODE,
+ /* keep last */
+ COEX_CONFIG_TYPE_MAX,
+};
+
+/**
+ * typedef update_coex_cb() - cb to inform coex config
+ * @vdev: vdev pointer
+ *
+ * Return: void
+ */
+typedef QDF_STATUS (*update_coex_cb)(struct wlan_objmgr_vdev *vdev);
+
+#ifdef FEATURE_COEX
+/**
+ * ucfg_coex_register_cfg_updated_handler() - API to register coex config
+ * updated handler.
+ * @psoc: pointer to psoc object
+ * @type: type of coex config
+ * @handler: handler to be registered
+ *
+ * Return: status of operation
+ */
+QDF_STATUS
+ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc,
+ enum coex_config_type type,
+ update_coex_cb handler);
+
+/**
+ * ucfg_coex_psoc_set_btc_chain_mode() - API to set BT coex chain mode for psoc
+ * @psoc: pointer to psoc object
+ * @val: BT coex chain mode
+ *
+ * Return : status of operation
+ */
+QDF_STATUS
+ucfg_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val);
+
+/**
+ * ucfg_coex_psoc_get_btc_chain_mode() - API to get BT coex chain mode from psoc
+ * @psoc: pointer to psoc object
+ * @val: pointer to BT coex chain mode
+ *
+ * Return : status of operation
+ */
+QDF_STATUS
+ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val);
+
+/**
+ * ucfg_coex_send_btc_chain_mode() - API to send BT coex config to target if
+ * @vdev: pointer to vdev object
+ * @mode: BT coex chain mode
+ *
+ * Return: status of operation
+ */
+QDF_STATUS
+ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, uint8_t mode);
+#else
+static inline QDF_STATUS
+ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc,
+ enum coex_config_type type,
+ update_coex_cb handler)
+{
+ return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val)
+{
+ if (val)
+ *val = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, uint8_t mode)
+{
+ return QDF_STATUS_SUCCESS;
+}
+#endif
+#endif
diff --git a/umac/coex/dispatcher/inc/wlan_coex_utils_api.h b/umac/coex/dispatcher/inc/wlan_coex_utils_api.h
new file mode 100644
index 0000000..76bb68d
--- /dev/null
+++ b/umac/coex/dispatcher/inc/wlan_coex_utils_api.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_coex_utils_api.h
+ *
+ * This header file provides declaration of public APIs exposed to other UMAC
+ * components.
+ */
+
+#ifndef _WLAN_COEX_UTILS_API_H_
+#define _WLAN_COEX_UTILS_API_H_
+#include <wlan_objmgr_psoc_obj.h>
+
+/*
+ * wlan_coex_init() - Coex module initialization API
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_coex_init(void);
+
+/*
+ * wlan_coex_deinit() - Coex module deinitialization API
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_coex_deinit(void);
+
+/**
+ * wlan_coex_psoc_open() - Open coex component
+ * @psoc: soc context
+ *
+ * This function gets called when dispatcher opening.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS
+wlan_coex_psoc_open(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_coex_psoc_close() - Close coex component
+ * @psoc: soc context
+ *
+ * This function gets called when dispatcher closing.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS
+wlan_coex_psoc_close(struct wlan_objmgr_psoc *psoc);
+#endif
diff --git a/umac/coex/dispatcher/src/wlan_coex_tgt_api.c b/umac/coex/dispatcher/src/wlan_coex_tgt_api.c
new file mode 100644
index 0000000..4022a7c
--- /dev/null
+++ b/umac/coex/dispatcher/src/wlan_coex_tgt_api.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains coex south bound interface definitions
+ */
+
+#include <wlan_coex_main.h>
+#include <wlan_coex_tgt_api.h>
+#include <wlan_lmac_if_def.h>
+#include "wlan_objmgr_pdev_obj.h"
+
+static inline struct wlan_lmac_if_coex_tx_ops *
+wlan_psoc_get_coex_txops(struct wlan_objmgr_psoc *psoc)
+{
+ return &psoc->soc_cb.tx_ops.coex_ops;
+}
+
+static inline struct wlan_lmac_if_coex_tx_ops *
+wlan_vdev_get_coex_txops(struct wlan_objmgr_vdev *vdev)
+{
+ struct wlan_objmgr_psoc *psoc;
+
+ psoc = wlan_vdev_get_psoc(vdev);
+ if (!psoc) {
+ coex_err("NULL psoc");
+ return NULL;
+ }
+
+ return wlan_psoc_get_coex_txops(psoc);
+}
+
+QDF_STATUS
+tgt_send_coex_config(struct wlan_objmgr_vdev *vdev,
+ struct coex_config_params *param)
+{
+ struct wlan_lmac_if_coex_tx_ops *coex_ops;
+ struct wlan_objmgr_psoc *psoc;
+ struct wlan_objmgr_pdev *pdev;
+
+ if (!vdev) {
+ coex_err("NULL vdev");
+ return QDF_STATUS_E_NULL_VALUE;
+ }
+
+ psoc = wlan_vdev_get_psoc(vdev);
+ if (!psoc) {
+ coex_err("NULL psoc");
+ return QDF_STATUS_E_NULL_VALUE;
+ }
+
+ pdev = wlan_vdev_get_pdev(vdev);
+ if (!pdev) {
+ coex_err("NULL pdev");
+ return QDF_STATUS_E_NULL_VALUE;
+ }
+
+ coex_ops = wlan_psoc_get_coex_txops(psoc);
+ QDF_ASSERT(coex_ops->coex_config_send);
+ if (coex_ops->coex_config_send)
+ return coex_ops->coex_config_send(pdev, param);
+
+ return QDF_STATUS_SUCCESS;
+}
diff --git a/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c b/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c
new file mode 100644
index 0000000..68321ee
--- /dev/null
+++ b/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains coex north bound interface definitions
+ */
+
+#include <wlan_coex_main.h>
+#include <wlan_coex_ucfg_api.h>
+#include "wmi_unified.h"
+
+QDF_STATUS
+ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc,
+ enum coex_config_type type,
+ update_coex_cb handler)
+{
+ struct coex_psoc_obj *coex_obj;
+
+ if (type >= COEX_CONFIG_TYPE_MAX) {
+ coex_err("invalid coex type: %d", type);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
+ if (!coex_obj)
+ return QDF_STATUS_E_INVAL;
+
+ coex_obj->coex_config_updated[type] = handler;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val)
+{
+ return wlan_coex_psoc_set_btc_chain_mode(psoc, val);
+}
+
+QDF_STATUS
+ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val)
+{
+ return wlan_coex_psoc_get_btc_chain_mode(psoc, val);
+}
+
+QDF_STATUS
+ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, uint8_t mode)
+{
+ struct coex_config_params param = {0};
+
+ if (mode != WLAN_COEX_BTC_CHAIN_MODE_SHARED &&
+ mode != WLAN_COEX_BTC_CHAIN_MODE_SEPARATED)
+ return QDF_STATUS_E_INVAL;
+
+ param.vdev_id = wlan_vdev_get_id(vdev);
+ param.config_type = WMI_COEX_CONFIG_BTCOEX_SEPARATE_CHAIN_MODE;
+ param.config_arg1 = mode;
+
+ coex_debug("send btc chain mode %d for vdev %d", mode, param.vdev_id);
+
+ return wlan_coex_config_send(vdev, ¶m);
+}
diff --git a/umac/coex/dispatcher/src/wlan_coex_utils_api.c b/umac/coex/dispatcher/src/wlan_coex_utils_api.c
new file mode 100644
index 0000000..3217878
--- /dev/null
+++ b/umac/coex/dispatcher/src/wlan_coex_utils_api.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_coex_utils_api.c
+ *
+ * This file provides definitions of public APIs exposed to other UMAC
+ * components.
+ */
+
+#include <wlan_coex_main.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_coex_utils_api.h>
+
+QDF_STATUS wlan_coex_init(void)
+{
+ QDF_STATUS status;
+
+ status = wlan_objmgr_register_psoc_create_handler(
+ WLAN_UMAC_COMP_COEX,
+ wlan_coex_psoc_created_notification, NULL);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ coex_err("Failed to register psoc create handler");
+ goto fail_create_psoc;
+ }
+
+ status = wlan_objmgr_register_psoc_destroy_handler(
+ WLAN_UMAC_COMP_COEX,
+ wlan_coex_psoc_destroyed_notification, NULL);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ coex_err("Failed to create psoc delete handler");
+ goto fail_psoc_destroy;
+ }
+
+ coex_debug("coex psoc create and delete handler registered");
+ return status;
+
+fail_psoc_destroy:
+ wlan_objmgr_unregister_psoc_create_handler(
+ WLAN_UMAC_COMP_COEX,
+ wlan_coex_psoc_created_notification, NULL);
+fail_create_psoc:
+ return status;
+}
+
+QDF_STATUS wlan_coex_deinit(void)
+{
+ QDF_STATUS status;
+
+ status = wlan_objmgr_unregister_psoc_destroy_handler(
+ WLAN_UMAC_COMP_COEX,
+ wlan_coex_psoc_destroyed_notification, NULL);
+ if (status != QDF_STATUS_SUCCESS)
+ coex_err("Failed to unregister psoc delete handler");
+
+ status = wlan_objmgr_unregister_psoc_create_handler(
+ WLAN_UMAC_COMP_COEX,
+ wlan_coex_psoc_created_notification, NULL);
+ if (status != QDF_STATUS_SUCCESS)
+ coex_err("Failed to unregister psoc create handler");
+
+ return status;
+}
+
+QDF_STATUS
+wlan_coex_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+ return wlan_coex_psoc_init(psoc);
+}
+
+QDF_STATUS
+wlan_coex_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+ return wlan_coex_psoc_deinit(psoc);
+}
diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
index 2e8c7a8..15cf260 100644
--- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
+++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
*
* Permission to use, copy, modify, and/or distribute this software for
@@ -912,6 +912,19 @@
};
#endif
+#ifdef FEATURE_COEX
+struct coex_config_params;
+
+/**
+ * struct wlan_lmac_if_coex_tx_ops - south bound tx function pointers for coex
+ * @coex_config_send: function pointer to send coex config to fw
+ */
+struct wlan_lmac_if_coex_tx_ops {
+ QDF_STATUS (*coex_config_send)(struct wlan_objmgr_pdev *pdev,
+ struct coex_config_params *param);
+};
+#endif
+
/**
* struct wlan_lmac_if_tx_ops - south bound tx function pointers
* @mgmt_txrx_tx_ops: mgmt txrx tx ops
@@ -919,9 +932,10 @@
* @dfs_tx_ops: dfs tx ops.
* @green_ap_tx_ops: green_ap tx_ops
* @cp_stats_tx_ops: cp stats tx_ops
+ * @coex_ops: coex tx_ops
*
* Callback function tabled to be registered with umac.
- * umac will use the functional table to send events/frames to lmac/wmi
+ * umac will use the functional table to send events/frames to wmi
*/
struct wlan_lmac_if_tx_ops {
@@ -990,6 +1004,10 @@
#endif
struct wlan_lmac_if_ftm_tx_ops ftm_tx_ops;
+
+#ifdef FEATURE_COEX
+ struct wlan_lmac_if_coex_tx_ops coex_ops;
+#endif
};
/**
diff --git a/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c b/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c
index bc5912c..e4bac19 100644
--- a/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c
+++ b/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -344,6 +344,7 @@
enum QDF_OPMODE opmode;
struct wlan_objmgr_vdev *vdev;
struct config_fils_params fils_param = {0};
+ uint8_t is_6g_sap_fd_enabled;
if (!mlme_obj) {
mlme_err("VDEV_MLME is NULL");
@@ -374,7 +375,11 @@
if (QDF_IS_STATUS_ERROR(status))
return status;
+ is_6g_sap_fd_enabled = wlan_vdev_mlme_feat_ext_cap_get(vdev,
+ WLAN_VDEV_FEXT_FILS_DISC_6G_SAP);
+ mlme_debug("SAP FD enabled %d", is_6g_sap_fd_enabled);
if (opmode == QDF_SAP_MODE && mlme_obj->vdev->vdev_mlme.des_chan &&
+ is_6g_sap_fd_enabled &&
WLAN_REG_IS_6GHZ_CHAN_FREQ(
mlme_obj->vdev->vdev_mlme.des_chan->ch_freq)) {
fils_param.vdev_id = wlan_vdev_get_id(mlme_obj->vdev);
diff --git a/umac/regulatory/core/src/reg_opclass.c b/umac/regulatory/core/src/reg_opclass.c
index d856f13..79505ce 100644
--- a/umac/regulatory/core/src/reg_opclass.c
+++ b/umac/regulatory/core/src/reg_opclass.c
@@ -590,8 +590,8 @@
op_class_tbl->channels[i]); i++) {
if (op_class_tbl->channels[i] == chan) {
chan = op_class_tbl->channels[i];
- return (op_class_tbl->start_freq +
- (chan * FREQ_TO_CHAN_SCALE));
+ return op_class_tbl->start_freq +
+ (chan * FREQ_TO_CHAN_SCALE);
}
}
reg_err_rl("Channel not found");
@@ -602,4 +602,122 @@
reg_err_rl("Invalid opclass given as input");
return 0;
}
+
+static void
+reg_get_op_class_tbl_by_chan_map(const struct
+ reg_dmn_op_class_map_t **op_class_tbl)
+{
+ if (channel_map == channel_map_us)
+ *op_class_tbl = us_op_class;
+ else if (channel_map == channel_map_eu)
+ *op_class_tbl = euro_op_class;
+ else if (channel_map == channel_map_china)
+ *op_class_tbl = us_op_class;
+ else if (channel_map == channel_map_jp)
+ *op_class_tbl = japan_op_class;
+ else
+ *op_class_tbl = global_op_class;
+}
+
+/**
+ * reg_get_channels_from_opclassmap()- Get channels from the opclass map
+ * @pdev: Pointer to pdev
+ * @reg_ap_cap: Pointer to reg_ap_cap
+ * @index: Pointer to index of reg_ap_cap
+ * @op_class_tbl: Pointer to op_class_tbl
+ * @is_opclass_operable: Set true if opclass is operable, else set false
+ *
+ * Populate channels from opclass map to reg_ap_cap as supported and
+ * non-supported channels.
+ *
+ * Return: void.
+ */
+static void
+reg_get_channels_from_opclassmap(
+ struct wlan_objmgr_pdev *pdev,
+ struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+ uint8_t index,
+ const struct reg_dmn_op_class_map_t *op_class_tbl,
+ bool *is_opclass_operable)
+{
+ uint8_t op_cls_chan;
+ qdf_freq_t search_freq;
+ bool is_freq_present;
+ uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
+
+ while (op_class_tbl->channels[chan_idx]) {
+ op_cls_chan = op_class_tbl->channels[chan_idx];
+ search_freq = op_class_tbl->start_freq +
+ (FREQ_TO_CHAN_SCALE * op_cls_chan);
+ is_freq_present =
+ reg_is_freq_present_in_cur_chan_list(pdev, search_freq);
+
+ if (!is_freq_present) {
+ reg_ap_cap[index].
+ non_sup_chan_list[n_unsup_chans++] =
+ op_class_tbl->channels[chan_idx];
+ reg_ap_cap[index].num_non_supported_chan++;
+ } else {
+ reg_ap_cap[index].sup_chan_list[n_sup_chans++] =
+ op_class_tbl->channels[chan_idx];
+ reg_ap_cap[index].num_supported_chan++;
+ }
+
+ chan_idx++;
+ }
+
+ if (reg_ap_cap[index].num_supported_chan >= 1)
+ *is_opclass_operable = true;
+}
+
+QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+ struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+ uint8_t *n_opclasses,
+ uint8_t max_supp_op_class,
+ bool global_tbl_lookup)
+{
+ uint8_t max_reg_power = 0;
+ const struct reg_dmn_op_class_map_t *op_class_tbl;
+ uint8_t index = 0;
+
+ if (global_tbl_lookup)
+ op_class_tbl = global_op_class;
+ else
+ reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
+
+ max_reg_power = reg_get_max_tx_power(pdev);
+
+ while (op_class_tbl->op_class && (index < max_supp_op_class)) {
+ bool is_opclass_operable = false;
+
+ qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
+ REG_MAX_CHANNELS_PER_OPERATING_CLASS);
+ reg_ap_cap[index].num_supported_chan = 0;
+ qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
+ REG_MAX_CHANNELS_PER_OPERATING_CLASS);
+ reg_ap_cap[index].num_non_supported_chan = 0;
+ reg_get_channels_from_opclassmap(pdev,
+ reg_ap_cap,
+ index,
+ op_class_tbl,
+ &is_opclass_operable);
+ if (is_opclass_operable) {
+ reg_ap_cap[index].op_class = op_class_tbl->op_class;
+ reg_ap_cap[index].ch_width =
+ op_class_tbl->chan_spacing;
+ reg_ap_cap[index].start_freq =
+ op_class_tbl->start_freq;
+ reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
+ reg_ap_cap[index].behav_limit =
+ op_class_tbl->behav_limit;
+ index++;
+ }
+
+ op_class_tbl++;
+ }
+
+ *n_opclasses = index;
+
+ return QDF_STATUS_SUCCESS;
+}
#endif
diff --git a/umac/regulatory/core/src/reg_opclass.h b/umac/regulatory/core/src/reg_opclass.h
index 834f3d7..3b5c8dc 100644
--- a/umac/regulatory/core/src/reg_opclass.h
+++ b/umac/regulatory/core/src/reg_opclass.h
@@ -89,6 +89,21 @@
*/
uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class);
+/**
+ * reg_get_opclass_details() - Get details about the current opclass table.
+ * @pdev: Pointer to pdev.
+ * @reg_ap_cap: Pointer to reg_ap_cap.
+ * @n_opclasses: Pointer to number of opclasses.
+ * @max_supp_op_class: Maximum number of operating classes supported.
+ * @global_tbl_lookup: Whether to lookup global op class table.
+ *
+ * Return: QDF_STATUS_SUCCESS if success, else return QDF_STATUS_FAILURE.
+ */
+QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+ struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+ uint8_t *n_opclasses,
+ uint8_t max_supp_op_class,
+ bool global_tbl_lookup);
#ifdef CONFIG_CHAN_FREQ_API
/**
@@ -195,6 +210,16 @@
{
}
+static inline
+QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+ struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+ uint8_t *n_opclasses,
+ uint8_t max_supp_op_class,
+ bool global_tbl_lookup)
+{
+ return QDF_STATUS_E_FAILURE;
+}
+
#ifdef CONFIG_CHAN_FREQ_API
static inline void
diff --git a/umac/regulatory/core/src/reg_services_common.c b/umac/regulatory/core/src/reg_services_common.c
index 1b61ab3..b43a54f 100644
--- a/umac/regulatory/core/src/reg_services_common.c
+++ b/umac/regulatory/core/src/reg_services_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -1071,6 +1071,8 @@
reg_channels[i].chan_flags != REGULATORY_CHAN_DISABLED) {
ch_list[count].chan_num =
reg_channels[i].chan_num;
+ ch_list[count].center_freq =
+ reg_channels[i].center_freq;
ch_list[count++].tx_power =
reg_channels[i].tx_power;
}
@@ -2853,6 +2855,36 @@
return INVALID_CHANNEL;
}
+bool
+reg_is_freq_present_in_cur_chan_list(struct wlan_objmgr_pdev *pdev,
+ qdf_freq_t freq)
+{
+ enum channel_enum chan_enum;
+ struct regulatory_channel *cur_chan_list;
+ struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+ pdev_priv_obj = reg_get_pdev_obj(pdev);
+
+ if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+ reg_err_rl("pdev reg obj is NULL");
+ return false;
+ }
+
+ cur_chan_list = pdev_priv_obj->cur_chan_list;
+
+ for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++)
+ if (cur_chan_list[chan_enum].center_freq == freq)
+ if ((cur_chan_list[chan_enum].state !=
+ CHANNEL_STATE_DISABLE) &&
+ !(cur_chan_list[chan_enum].chan_flags &
+ REGULATORY_CHAN_DISABLED))
+ return true;
+
+ reg_debug_rl("Channel center frequency %d not found", freq);
+
+ return false;
+}
+
enum channel_state reg_get_channel_state_for_freq(struct wlan_objmgr_pdev *pdev,
qdf_freq_t freq)
{
@@ -3474,8 +3506,38 @@
return REG_BAND_6G;
return REG_BAND_UNKNOWN;
}
+
#endif /* CONFIG_CHAN_FREQ_API */
+uint8_t reg_get_max_tx_power(struct wlan_objmgr_pdev *pdev)
+{
+ struct regulatory_channel *cur_chan_list;
+ struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+ uint8_t i, max_tx_power = 0;
+
+ pdev_priv_obj = reg_get_pdev_obj(pdev);
+
+ if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+ reg_err("reg pdev private obj is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ cur_chan_list = pdev_priv_obj->cur_chan_list;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (cur_chan_list[i].state != CHANNEL_STATE_DISABLE &&
+ cur_chan_list[i].chan_flags != REGULATORY_CHAN_DISABLED) {
+ if (cur_chan_list[i].tx_power > max_tx_power)
+ max_tx_power = cur_chan_list[i].tx_power;
+ }
+ }
+
+ if (!max_tx_power)
+ reg_err_rl("max_tx_power is zero");
+
+ return max_tx_power;
+}
+
QDF_STATUS reg_set_ignore_fw_reg_offload_ind(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
diff --git a/umac/regulatory/core/src/reg_services_common.h b/umac/regulatory/core/src/reg_services_common.h
index d8e9d99..ffd0091 100644
--- a/umac/regulatory/core/src/reg_services_common.h
+++ b/umac/regulatory/core/src/reg_services_common.h
@@ -742,6 +742,21 @@
#ifdef CONFIG_CHAN_FREQ_API
/**
+ * reg_is_freq_present_in_cur_chan_list() - Check the input frequency
+ * @pdev: Pointer to pdev
+ * @freq: Channel center frequency in MHz
+ *
+ * Check if the input channel center frequency is present in the current
+ * channel list
+ *
+ * Return: Return true if channel center frequency is present in the current
+ * channel list, else return false.
+ */
+bool
+reg_is_freq_present_in_cur_chan_list(struct wlan_objmgr_pdev *pdev,
+ qdf_freq_t freq);
+
+/**
* reg_get_chan_enum_for_freq() - Get channel enum for given channel frequency
* @freq: Channel Frequency
*
@@ -936,6 +951,15 @@
#endif /* CONFIG_CHAN_FREQ_API */
/**
+ * reg_get_max_tx_power() - Get maximum tx power from the current channel list
+ * @pdev: Pointer to pdev
+ *
+ * Return: return the value of the maximum tx power in the current channel list
+ *
+ */
+uint8_t reg_get_max_tx_power(struct wlan_objmgr_pdev *pdev);
+
+/**
* reg_set_ignore_fw_reg_offload_ind() - Set if regdb offload indication
* needs to be ignored
* @psoc: Pointer to psoc
diff --git a/umac/regulatory/core/src/reg_utils.h b/umac/regulatory/core/src/reg_utils.h
index dc714b0..059c1b3 100644
--- a/umac/regulatory/core/src/reg_utils.h
+++ b/umac/regulatory/core/src/reg_utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
*
* Permission to use, copy, modify, and/or distribute this software for
@@ -516,7 +516,7 @@
* Return: true or false
*/
#ifdef CONFIG_CHAN_FREQ_API
-bool reg_is_dsrc_freq(uint16_t freq);
+bool reg_is_dsrc_freq(qdf_freq_t freq);
#endif /* CONFIG_CHAN_FREQ_API*/
#ifdef CONFIG_CHAN_NUM_API
@@ -567,7 +567,7 @@
return false;
}
-static inline bool reg_is_dsrc_freq(uint16_t freq)
+static inline bool reg_is_dsrc_freq(qdf_freq_t freq)
{
return false;
}
@@ -612,7 +612,7 @@
return false;
}
-static inline bool reg_is_dsrc_freq(uint16_t freq)
+static inline bool reg_is_dsrc_freq(qdf_freq_t freq)
{
return false;
}
diff --git a/umac/regulatory/dispatcher/inc/reg_services_public_struct.h b/umac/regulatory/dispatcher/inc/reg_services_public_struct.h
index 2617cd8..2400e69 100644
--- a/umac/regulatory/dispatcher/inc/reg_services_public_struct.h
+++ b/umac/regulatory/dispatcher/inc/reg_services_public_struct.h
@@ -528,8 +528,8 @@
struct ch_params {
enum phy_ch_width ch_width;
uint8_t sec_ch_offset;
- qdf_freq_t center_freq_seg0;
- qdf_freq_t center_freq_seg1;
+ uint8_t center_freq_seg0;
+ uint8_t center_freq_seg1;
qdf_freq_t mhz_freq_seg0;
qdf_freq_t mhz_freq_seg1;
};
@@ -598,6 +598,30 @@
};
/**
+ * struct regdmn_ap_cap_opclass_t: AP Cap operation class table
+ * @op_class: operating class number
+ * @ch_width: channel width in MHz
+ * @start_freq: Starting Frequency in MHz
+ * @behav_limit: OR of bitmaps of enum behav_limit
+ * @max_tx_pwr_dbm: Maximum tx power in dbm
+ * @num_supported_chan: Number of supported channels
+ * @num_non_supported_chan: Number of non-supported channels
+ * @sup_chan_list: Array of supported channel numbers
+ * @non_sup_chan_list: Array of non supported channel numbers
+ */
+struct regdmn_ap_cap_opclass_t {
+ uint8_t op_class;
+ uint8_t ch_width;
+ qdf_freq_t start_freq;
+ uint16_t behav_limit;
+ uint8_t max_tx_pwr_dbm;
+ uint8_t num_supported_chan;
+ uint8_t num_non_supported_chan;
+ uint8_t sup_chan_list[REG_MAX_CHANNELS_PER_OPERATING_CLASS];
+ uint8_t non_sup_chan_list[REG_MAX_CHANNELS_PER_OPERATING_CLASS];
+};
+
+/**
* struct reg_dmn_supp_op_classes: operating classes
* @num_classes: number of classes
* @classes: classes
diff --git a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h
index dc89234..dca8d3b 100644
--- a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h
+++ b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h
@@ -606,6 +606,23 @@
/**
+ * wlan_reg_get_opclass_details() - Get details about the current opclass table.
+ * @pdev: Pointer to pdev.
+ * @reg_ap_cap: Pointer to reg_ap_cap.
+ * @n_opclasses: Pointer to number of opclasses.
+ * @max_supp_op_class: Maximum number of operating classes supported.
+ * @global_tbl_lookup: Whether to lookup global op class tbl.
+ *
+ * Return: QDF_STATUS_SUCCESS if success, else return QDF_STATUS_FAILURE.
+ */
+QDF_STATUS
+wlan_reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+ struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+ uint8_t *n_opclasses,
+ uint8_t max_supp_op_class,
+ bool global_tbl_lookup);
+
+/**
* wlan_regulatory_init() - init regulatory component
*
* Return: Success or Failure
diff --git a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c
index 22f2482..b21ec96 100644
--- a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c
+++ b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c
@@ -302,6 +302,18 @@
return reg_dmn_get_curr_opclasses(num_classes, class);
}
+QDF_STATUS
+wlan_reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+ struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+ uint8_t *n_opclasses,
+ uint8_t max_supp_op_class,
+ bool global_tbl_lookup)
+{
+ return reg_get_opclass_details(pdev, reg_ap_cap, n_opclasses,
+ max_supp_op_class,
+ global_tbl_lookup);
+}
+
QDF_STATUS wlan_regulatory_init(void)
{
QDF_STATUS status;
diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h
index fde2a5a..dba1199 100644
--- a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h
+++ b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h
@@ -1246,7 +1246,7 @@
/* Set PNO */
#define SCAN_PNO_MAX_PLAN_REQUEST 2
-#define SCAN_PNO_MAX_NETW_CHANNELS_EX 60
+#define SCAN_PNO_MAX_NETW_CHANNELS_EX (QDF_MAX_NUM_CHAN)
#define SCAN_PNO_MAX_SUPP_NETWORKS 16
#define SCAN_PNO_DEF_SLOW_SCAN_MULTIPLIER 6
#define SCAN_PNO_DEF_SCAN_TIMER_REPEAT 20
diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c
index f9d23de..bfbe4f3 100644
--- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c
+++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -598,17 +598,15 @@
static QDF_STATUS
util_scan_update_rnr(struct rnr_bss_info *rnr,
struct neighbor_ap_info_field *ap_info,
- uint8_t **data)
+ uint8_t *data)
{
- uint16_t fieldtype;
- uint8_t *tmp = *data;
+ uint8_t tbtt_info_length;
- fieldtype = ap_info->tbtt_header.tbbt_info_fieldtype;
+ tbtt_info_length = ap_info->tbtt_header.tbtt_info_length;
- switch (fieldtype) {
+ switch (tbtt_info_length) {
case TBTT_NEIGHBOR_AP_OFFSET_ONLY:
/* Dont store it skip*/
- *data = tmp + NEIGHBOR_AP_LEN;
break;
case TBTT_NEIGHBOR_AP_BSS_PARAM:
@@ -618,51 +616,42 @@
case TBTT_NEIGHBOR_AP_SHORTSSID:
rnr->channel_number = ap_info->channel_number;
rnr->operating_class = ap_info->operting_class;
- qdf_mem_copy(&rnr->short_ssid, &tmp[1], SHORT_SSID_LEN);
- *data = tmp + NEIGHBOR_AP_LEN + SHORT_SSID_LEN;
+ qdf_mem_copy(&rnr->short_ssid, &data[1], SHORT_SSID_LEN);
break;
case TBTT_NEIGHBOR_AP_S_SSID_BSS_PARAM:
rnr->channel_number = ap_info->channel_number;
rnr->operating_class = ap_info->operting_class;
- qdf_mem_copy(&rnr->short_ssid, &tmp[1], SHORT_SSID_LEN);
- rnr->bss_params = tmp[5];
- *data = tmp + NEIGHBOR_AP_LEN + SHORT_SSID_LEN + BSS_PARAMS_LEN;
+ qdf_mem_copy(&rnr->short_ssid, &data[1], SHORT_SSID_LEN);
+ rnr->bss_params = data[5];
break;
case TBTT_NEIGHBOR_AP_BSSID:
rnr->channel_number = ap_info->channel_number;
rnr->operating_class = ap_info->operting_class;
- qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE);
- *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE;
+ qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
break;
case TBTT_NEIGHBOR_AP_BSSID_BSS_PARAM:
rnr->channel_number = ap_info->channel_number;
rnr->operating_class = ap_info->operting_class;
- qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE);
- rnr->bss_params = tmp[7];
- *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE
- + BSS_PARAMS_LEN;
+ qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
+ rnr->bss_params = data[7];
break;
case TBTT_NEIGHBOR_AP_BSSSID_S_SSID:
rnr->channel_number = ap_info->channel_number;
rnr->operating_class = ap_info->operting_class;
- qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(&rnr->short_ssid, &tmp[7], SHORT_SSID_LEN);
- *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE
- + SHORT_SSID_LEN;
+ qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
+ qdf_mem_copy(&rnr->short_ssid, &data[7], SHORT_SSID_LEN);
break;
case TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM:
rnr->channel_number = ap_info->channel_number;
rnr->operating_class = ap_info->operting_class;
- qdf_mem_copy(&rnr->bssid, &tmp[1], QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(&rnr->short_ssid, &tmp[7], SHORT_SSID_LEN);
- rnr->bss_params = tmp[11];
- *data = tmp + NEIGHBOR_AP_LEN + QDF_MAC_ADDR_SIZE
- + SHORT_SSID_LEN + BSS_PARAMS_LEN;
+ qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
+ qdf_mem_copy(&rnr->short_ssid, &data[7], SHORT_SSID_LEN);
+ rnr->bss_params = data[11];
break;
default:
@@ -684,7 +673,7 @@
rnr_ie_len = ie->ie_len;
data = (uint8_t *)ie + sizeof(struct ie_header);
- while (data < (uint8_t *)ie + rnr_ie_len + 2) {
+ while (data < ((uint8_t *)ie + rnr_ie_len + 2)) {
neighbor_ap_info = (struct neighbor_ap_info_field *)data;
tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count;
tbtt_length = neighbor_ap_info->tbtt_header.tbtt_info_length;
@@ -694,11 +683,14 @@
neighbor_ap_info->operting_class);
scm_debug("tbtt_count %d, tbtt_length %d, fieldtype %d",
tbtt_count, tbtt_length, fieldtype);
- for (i = 0; i < (tbtt_count + 1) && i < MAX_RNR_BSS; i++) {
- data = data + sizeof(struct neighbor_ap_info_field);
- util_scan_update_rnr(&scan_entry->rnr.bss_info[i],
- neighbor_ap_info,
- &data);
+ data += sizeof(struct neighbor_ap_info_field);
+ for (i = 0; i < (tbtt_count + 1) ; i++) {
+ if (i < MAX_RNR_BSS)
+ util_scan_update_rnr(
+ &scan_entry->rnr.bss_info[i],
+ neighbor_ap_info,
+ data);
+ data += tbtt_length;
}
}
diff --git a/umac/wifi_pos/src/wifi_pos_main.c b/umac/wifi_pos/src/wifi_pos_main.c
index a8bba7c..d36c657 100644
--- a/umac/wifi_pos/src/wifi_pos_main.c
+++ b/umac/wifi_pos/src/wifi_pos_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -442,14 +442,66 @@
vdev_idx++;
}
+#ifdef CNSS_GENL
+static uint8_t *
+wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
+ struct app_reg_rsp_vdev_info *vdevs_info)
+{
+ uint32_t *nl_sign;
+ uint8_t *resp_buf;
+ struct wifi_app_reg_rsp *app_reg_rsp;
+
+ /*
+ * allocate ENHNC_FLAGS_LEN i.e. 4bytes extra memory in app_reg_resp
+ * to indicate NLA type resoponse is supported for OEM request
+ * commands.
+ */
+ *rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
+ + sizeof(uint8_t) + ENHNC_FLAGS_LEN;
+ resp_buf = qdf_mem_malloc(*rsp_len);
+ if (!resp_buf)
+ return NULL;
+
+ app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
+ app_reg_rsp->num_inf = vdev_idx;
+ qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
+ sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
+
+ nl_sign = (uint32_t *)&app_reg_rsp->vdevs[vdev_idx];
+ *nl_sign |= NL_ENABLE_OEM_REQ_RSP;
+
+ return resp_buf;
+}
+#else
+static uint8_t *
+wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
+ struct app_reg_rsp_vdev_info *vdevs_info)
+{
+ uint8_t *resp_buf;
+ struct wifi_app_reg_rsp *app_reg_rsp;
+
+ *rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
+ + sizeof(uint8_t);
+ resp_buf = qdf_mem_malloc(*rsp_len);
+ if (!resp_buf)
+ return NULL;
+
+ app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
+ app_reg_rsp->num_inf = vdev_idx;
+ qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
+ sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
+
+ return resp_buf;
+}
+#endif
+
static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
struct wifi_pos_req_msg *req)
{
QDF_STATUS ret = QDF_STATUS_SUCCESS;
- uint8_t err = 0;
+ uint8_t err = 0, *app_reg_rsp;
uint32_t rsp_len;
char *sign_str = NULL;
- struct wifi_app_reg_rsp *app_reg_rsp;
struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS]
= { { 0 } };
struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
@@ -484,18 +536,14 @@
wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
wifi_pos_vdev_iterator,
vdevs_info, true, WLAN_WIFI_POS_CORE_ID);
- rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
- + sizeof(uint8_t);
- app_reg_rsp = qdf_mem_malloc(rsp_len);
+
+ app_reg_rsp = wifi_pos_prepare_reg_resp(&rsp_len, vdevs_info);
if (!app_reg_rsp) {
ret = QDF_STATUS_E_NOMEM;
err = OEM_ERR_NULL_CONTEXT;
goto app_reg_failed;
}
- app_reg_rsp->num_inf = vdev_idx;
- qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
- sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
if (!vdev_idx)
wifi_pos_debug("no active vdev");
diff --git a/umac/wifi_pos/src/wifi_pos_main_i.h b/umac/wifi_pos/src/wifi_pos_main_i.h
index 864f709..227c2ce 100644
--- a/umac/wifi_pos/src/wifi_pos_main_i.h
+++ b/umac/wifi_pos/src/wifi_pos_main_i.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -25,6 +25,11 @@
#ifndef _WIFI_POS_MAIN_H_
#define _WIFI_POS_MAIN_H_
+#ifdef CNSS_GENL
+#define ENHNC_FLAGS_LEN 4
+#define NL_ENABLE_OEM_REQ_RSP 0x00000001
+#endif
+
/* forward reference */
struct wlan_objmgr_psoc;
diff --git a/utils/host_diag_log/inc/host_diag_core_log.h b/utils/host_diag_log/inc/host_diag_core_log.h
index f9b47cb..5e5b363 100644
--- a/utils/host_diag_log/inc/host_diag_core_log.h
+++ b/utils/host_diag_log/inc/host_diag_core_log.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, 2019-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -285,6 +285,272 @@
uint8_t cb_cal_data[HOST_LOG_MAX_COLD_BOOT_CAL_DATA_SIZE];
};
+#define WLAN_MAX_ROAM_CANDIDATE_AP 8
+#define WLAN_MAX_ROAM_SCAN_CHAN 38
+#define WLAN_MAX_SSID_SIZE 32
+#define WLAN_MAC_ADDR_SIZE 6
+
+/**
+ * host_log_wlan_mgmt_tx_rx_info: To capture TX/RX mgmt frames' payload
+ * @hdr: Log header
+ * @version: Version number of the payload
+ * @vdev_id: Vdev id
+ * @is_tx: 1 - TX frame, 0 - RX frame
+ * @mgmt_type: type of frames, value: enum wifi_frm_type
+ * @mgmt_subtype: subtype of mgmt frame, value: enum mgmt_frm_subtype
+ * @mgmt_frame_seq_num: Frame sequence number in 802.11 header
+ * @operating_freq: operating frequency of AP
+ * @ssid_len: length of SSID, max 32 bytes long as per standard
+ * @ssid: SSID of connected AP
+ * @self_mac_addr: mac address of self interface
+ * @bssid: BSSID for which frame is received
+ * @mac_failure_reason: Internal driver failure reason
+ * @mgmt_status_code: 802.11 management frame response status code from
+ * section 9.4.1.9 IEEE 802.11 - 2016
+ * @auth_algo: Authentication algorithm number
+ * @auth_transaction_num: Authentication transaction sequence number
+ * @is_retry: Is retry frame
+ * @rssi: RSSI for the received frame
+ * @origin: 1- Sent by host. 2- sent by firmware
+ */
+struct host_log_wlan_mgmt_tx_rx_info {
+ log_hdr_type hdr;
+ uint8_t version;
+ uint8_t vdev_id;
+ bool is_tx;
+ uint8_t mgmt_type;
+ uint8_t mgmt_subtype;
+ uint16_t mgmt_frame_seq_num;
+ uint8_t operating_freq;
+ uint8_t ssid_len;
+ char ssid[WLAN_MAX_SSID_SIZE];
+ uint8_t self_mac_addr[WLAN_MAC_ADDR_SIZE];
+ uint8_t bssid[WLAN_MAC_ADDR_SIZE];
+ uint16_t mac_failure_reason;
+ uint16_t mgmt_status_code;
+ uint8_t auth_algo;
+ uint8_t auth_transaction_num;
+ uint8_t is_retry;
+ uint32_t rssi;
+ uint8_t origin;
+} qdf_packed;
+
+/**
+ * struct wlan_roam_btm_trigger_data - BTM roam trigger related information
+ * @btm_request_mode: BTM request mode - solicited/unsolicited
+ * @disassoc_timer: Number of TBTT before AP disassociates the STA in ms
+ * @validity_interval: Preferred candidate list validity interval in ms
+ * @candidate_list_count: Number of candidates in BTM request.
+ * @btm_resp_status: Status code of the BTM response.
+ */
+struct wlan_roam_btm_trigger_data {
+ uint8_t btm_request_mode;
+ uint32_t disassoc_timer;
+ uint32_t validity_interval;
+ uint16_t candidate_list_count;
+ uint16_t btm_resp_status;
+} qdf_packed;
+
+/**
+ * struct wlan_roam_cu_trigger_data - BSS Load roam trigger parameters
+ * @cu_load: Connected AP CU load percentage
+ */
+struct wlan_roam_cu_trigger_data {
+ uint16_t cu_load;
+} qdf_packed;
+
+/**
+ * Struct wlan_roam_rssi_trigger_data - RSSI roam trigger related
+ * parameters
+ * @threshold: RSSI threshold value in dBm for LOW rssi roam trigger
+ */
+struct wlan_roam_rssi_trigger_data {
+ uint32_t threshold;
+} qdf_packed;
+
+/**
+ * struct wlan_roam_deauth_trigger_data - Deauth roaming trigger related
+ * parameters
+ * @type: 1- Deauthentication 2- Disassociation
+ * @reason: Status code of the Deauth/Disassoc received
+ */
+struct wlan_roam_deauth_trigger_data {
+ uint8_t type;
+ uint32_t reason;
+} qdf_packed;
+
+/**
+ * struct host_log_wlan_roam_trigger_info - Roam trigger
+ * related info
+ * @hdr: Log header
+ * @version: Version number of the payload
+ * @vdev_id: Vdev id
+ * @trigger_reason: Roaming trigger reason
+ * @trigger_sub_reason: Roaming trigger sub reason
+ * @current_rssi: Current connected AP RSSI
+ * @timestamp: Host driver timestamp in msecs
+ * @btm_trig_data: BTM trigger related data
+ * @cu_load_data: CU load trigger related data
+ * @rssi_trig_data: RSSI roam trigger related data
+ * @deauth_trig_data: Deauth Roam trigger related data
+ */
+struct host_log_wlan_roam_trigger_info {
+ log_hdr_type hdr;
+ uint8_t version;
+ uint8_t vdev_id;
+ uint32_t trigger_reason;
+ uint32_t trigger_sub_reason;
+ uint32_t current_rssi;
+ uint32_t timestamp;
+ union {
+ struct wlan_roam_btm_trigger_data btm_trig_data;
+ struct wlan_roam_cu_trigger_data cu_load_data;
+ struct wlan_roam_rssi_trigger_data rssi_trig_data;
+ struct wlan_roam_deauth_trigger_data deauth_trig_data;
+ };
+} qdf_packed;
+
+/**
+ * struct host_log_wlan_roam_candidate_info - Roam scan candidate APs related
+ * info
+ * @version: Payload structure version
+ * @timestamp: Host timestamp in millisecs
+ * @type: 0 - Candidate AP; 1 - Current connected AP.
+ * @bssid: AP bssid.
+ * @freq: Channel frquency
+ * @cu_load: Channel utilization load of the AP.
+ * @cu_score: Channel Utilization score.
+ * @rssi: Candidate AP rssi
+ * @rssi_score: AP RSSI score
+ * @total_score: Total score of the candidate AP.
+ * @etp: Estimated throughput value of the AP in Mbps
+ */
+struct host_log_wlan_roam_candidate_info {
+ uint8_t version;
+ uint32_t timestamp;
+ uint8_t type;
+ uint8_t bssid[WLAN_MAC_ADDR_SIZE];
+ uint16_t freq;
+ uint32_t cu_load;
+ uint32_t cu_score;
+ uint32_t rssi;
+ uint32_t rssi_score;
+ uint32_t total_score;
+ uint32_t etp;
+} qdf_packed;
+
+/**
+ * struct host_log_wlan_roam_scan_data - Roam scan event details
+ * @hdr: Log header
+ * @version: Version number of the diag log payload
+ * @vdev_id: Vdev ID
+ * @type: 0 - Partial roam scan; 1 - Full roam scan
+ * @num_ap: Number of candidate APs.
+ * @num_chan: Number of channels.
+ * @timestamp: Time of day in milliseconds at which scan was triggered
+ * @trigger_reason: Roam scan trigger reason
+ * @next_rssi_threshold: Next roam can trigger rssi threshold
+ * @chan_freq: List of frequencies scanned as part of roam scan
+ * @ap: List of candidate AP info
+ */
+struct host_log_wlan_roam_scan_data {
+ log_hdr_type hdr;
+ uint8_t version;
+ uint8_t vdev_id;
+ uint16_t type;
+ uint8_t num_ap;
+ uint8_t num_chan;
+ uint32_t timestamp;
+ uint32_t trigger_reason;
+ uint32_t next_rssi_threshold;
+ uint16_t chan_freq[WLAN_MAX_ROAM_SCAN_CHAN];
+ struct host_log_wlan_roam_candidate_info ap[WLAN_MAX_ROAM_CANDIDATE_AP];
+} qdf_packed;
+
+/**
+ * struct host_log_wlan_roam_result_info - Roam result related info.
+ * @hdr: Log header
+ * @version: Payload strcuture version
+ * @vdev_id: Vdev Id
+ * @status: 0 - Roaming is success ; 1 - Roaming failed
+ * @timestamp: Host timestamp in millisecs
+ * @fail_reason: One of WMI_ROAM_FAIL_REASON_ID
+ */
+struct host_log_wlan_roam_result_info {
+ log_hdr_type hdr;
+ uint8_t version;
+ uint8_t vdev_id;
+ bool status;
+ uint32_t timestamp;
+ uint32_t fail_reason;
+} qdf_packed;
+
+/**
+ * struct wlan_rrm_beacon_report - RRM beacon report related
+ * parameters
+ * @req_bssid: beacon report requestor BSSID
+ * @req_ssid: Requested SSID for beacon report
+ * @is_wildcard_bssid: Is the BSSID FF:FF:FF:FF:FF:FF
+ * @req_reg_class: Regulatory class mentioned in the request
+ * @req_measurement_mode: Measurement mode. Active/Passive/Beacon report Table
+ * @req_measurement_duration: Measurement duration requested.
+ * @num_reports_in_frame: Number of BSS scanned
+ * @is_last_frame_in_req: True if this frame is the last frame sent for the
+ * request
+ */
+struct wlan_rrm_beacon_report {
+ uint8_t req_bssid[WLAN_MAC_ADDR_SIZE];
+ uint8_t req_ssid[WLAN_MAX_SSID_SIZE];
+ bool is_wildcard_bssid;
+ uint8_t req_reg_class;
+ uint16_t req_measurement_mode;
+ uint16_t req_measurement_duration;
+ uint8_t num_reports_in_frame;
+ bool is_last_frame_in_req;
+} qdf_packed;
+
+/**
+ * struct host_log_wlan_rrm_tx_rx_info - RRM frame related details
+ * @hdr: Log header
+ * @version: Version of the payload struture
+ * @vdev_id: Vdev id
+ * @orgin: Sent by host or firmware
+ * @is_tx: Is Tx frame or RX frame
+ * @roam_result: Roaming result
+ * @timestamp: Time of the day in milliseconds
+ * @mgmt_frame_seq_num: Frame sequence number
+ * @received_chan_freq: Frame received channel frequency
+ * @action_category: Action frame category
+ * @rrm_action_code: Radio measurement/Noise measurement
+ * @radio_measurement_type: Neighbor report/Beacon report
+ * @bssid: BSSID field in frame
+ * @req_num_freq: Number of frequencies provided in request
+ * @req_freq: Frequencies requested
+ * @fail_reason_code: response TX failure status code
+ * @rssi: Rx frame rssi
+ * @bcn_rpt: Beacon report related parameters
+ */
+struct host_log_wlan_rrm_tx_rx_info {
+ log_hdr_type hdr;
+ uint8_t version;
+ uint8_t vdev_id;
+ uint8_t origin;
+ bool is_tx;
+ bool roam_result;
+ uint32_t timestamp;
+ uint16_t mgmt_frame_seq_num;
+ uint16_t received_chan_freq;
+ uint8_t action_category;
+ uint8_t rrm_action_code;
+ uint8_t radio_measurement_type;
+ uint8_t bssid[WLAN_MAC_ADDR_SIZE];
+ uint8_t req_num_freq;
+ uint16_t req_freq[WLAN_MAX_ROAM_SCAN_CHAN];
+ uint8_t fail_reason_code;
+ uint32_t rssi;
+ struct wlan_rrm_beacon_report bcn_rpt;
+} qdf_packed;
+
/*-------------------------------------------------------------------------
Function declarations and documenation
------------------------------------------------------------------------*/
diff --git a/utils/host_diag_log/inc/log_codes.h b/utils/host_diag_log/inc/log_codes.h
index 9f3fe6c..11dfa6b 100644
--- a/utils/host_diag_log/inc/log_codes.h
+++ b/utils/host_diag_log/inc/log_codes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -2003,6 +2003,12 @@
#define LOG_WLAN_COLD_BOOT_CAL_DATA_C ((0xA18) + LOG_1X_BASE_C)
+#define LOG_WLAN_AUTH_ASSOC_TX_RX_INFO_C ((0x1A19) + LOG_1X_BASE_C)
+#define LOG_WLAN_ROAM_TRIGGER_INFO_C ((0x1A1A) + LOG_1X_BASE_C)
+#define LOG_WLAN_ROAM_SCAN_INFO_C ((0x1A1B) + LOG_1X_BASE_C)
+#define LOG_WLAN_ROAM_RESULT_INFO_C ((0x1A1C) + LOG_1X_BASE_C)
+#define LOG_WLAN_RRM_TX_RX_INFO_C ((0x1A1D) + LOG_1X_BASE_C)
+
/* This is only here for old (pre equipment ID update) logging code */
#define LOG_LAST_C (LOG_1X_LAST_C & 0xFFF)
diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h
index 79f75bc..d2c000e 100644
--- a/wmi/inc/wmi_unified_param.h
+++ b/wmi/inc/wmi_unified_param.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -881,13 +881,13 @@
/**
* struct fd_params - FD cmd parameter
* @vdev_id: vdev id
- * @wbuf: FD buffer
* @frame_ctrl: frame control field
+ * @wbuf: FD buffer
*/
struct fd_params {
uint8_t vdev_id;
- qdf_nbuf_t wbuf;
uint16_t frame_ctrl;
+ qdf_nbuf_t wbuf;
};
/**
@@ -1276,30 +1276,30 @@
* @tx_frame: management tx frame
* @frm_len: frame length
* @vdev_id: vdev id
+ * @tx_type: type of management frame (determines what callback to use)
* @chanfreq: channel frequency
- * @pdata: frame data
* @desc_id: descriptor id relyaed back by target
+ * @pdata: frame data
* @macaddr: macaddr of peer
* @qdf_ctx: qdf context for qdf_nbuf_map
* @tx_param: TX send parameters
* @tx_params_valid: Flag that indicates if TX params are valid
* @use_6mbps: specify whether management frame to transmit should
* use 6 Mbps rather than 1 Mbps min rate(for 5GHz band or P2P)
- * @tx_type: type of management frame (determines what callback to use)
*/
struct wmi_mgmt_params {
void *tx_frame;
uint16_t frm_len;
uint8_t vdev_id;
+ uint8_t tx_type;
uint16_t chanfreq;
- void *pdata;
uint16_t desc_id;
+ void *pdata;
uint8_t *macaddr;
void *qdf_ctx;
struct tx_send_params tx_param;
bool tx_params_valid;
uint8_t use_6mbps;
- uint8_t tx_type;
};
/**
@@ -1307,25 +1307,25 @@
* @tx_frame: management tx frame
* @frm_len: frame length
* @vdev_id: vdev id
+ * @tx_params_valid: Flag that indicates if TX params are valid
* @chanfreq: channel frequency
- * @pdata: frame data
* @desc_id: descriptor id relyaed back by target
+ * @pdata: frame data
* @macaddr: macaddr of peer
* @qdf_ctx: qdf context for qdf_nbuf_map
* @tx_param: TX send parameters
- * @tx_params_valid: Flag that indicates if TX params are valid
*/
struct wmi_offchan_data_tx_params {
void *tx_frame;
uint16_t frm_len;
uint8_t vdev_id;
+ bool tx_params_valid;
uint16_t chanfreq;
- void *pdata;
uint16_t desc_id;
+ void *pdata;
uint8_t *macaddr;
void *qdf_ctx;
struct tx_send_params tx_param;
- bool tx_params_valid;
};
/**
@@ -1348,14 +1348,14 @@
* struct ta_uapsd_trig_params - uapsd trigger parameter
* @vdevid: vdev id
* @peer_addr: peer address
- * @auto_triggerparam: trigger parameters
* @num_ac: no of access category
+ * @auto_triggerparam: trigger parameters
*/
struct sta_uapsd_trig_params {
- uint32_t vdevid;
- uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
- struct sta_uapsd_params *auto_triggerparam;
- uint32_t num_ac;
+ uint32_t vdevid;
+ uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
+ uint32_t num_ac;
+ struct sta_uapsd_params *auto_triggerparam;
};
#define WMI_NUM_AC (4)
@@ -1531,14 +1531,15 @@
* struct wifi_passpoint_network_param - passpoint network block
* @id: identifier of this network block
* @realm: null terminated UTF8 encoded realm, 0 if unspecified
- * @roaming_consortium_ids: roaming consortium ids to match, 0s if unspecified
* @plmn: mcc/mnc combination as per rules, 0s if unspecified
+ * @roaming_consortium_ids: roaming consortium ids to match, 0s if unspecified
*/
struct wifi_passpoint_network_param {
uint32_t id;
uint8_t realm[WMI_PASSPOINT_REALM_LEN];
- int64_t roaming_consortium_ids[WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM];
uint8_t plmn[WMI_PASSPOINT_PLMN_LEN];
+ int64_t roaming_consortium_ids[
+ WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM];
};
/**
@@ -3241,13 +3242,16 @@
* struct ctl_table_params - Ctl table params
* @ctl_array: pointer to ctl array
* @ctl_cmd_len: ctl command length
- * @is_acfg_ctl: is acfg_ctl table
+ * @is_2g: is 2G
+ * @target_type: target type
+ * @ctl_band: ctl band
+ * @pdev_id: pdev id
*/
struct ctl_table_params {
uint8_t *ctl_array;
uint16_t ctl_cmd_len;
- uint32_t target_type;
bool is_2g;
+ uint32_t target_type;
uint32_t ctl_band;
uint32_t pdev_id;
};
@@ -3375,29 +3379,29 @@
* @wildcard: iwldcard table entry?
* @mcast_ip_addr: mcast ip address to be updated
* @mcast_ip_addr_bytes: mcast ip addr bytes
- * @ucast_mac_addr: ucast peer mac subscribed to mcast ip
- * @filter_mode: filter mode
* @nsrcs: number of entries in source list
+ * @filter_mode: filter mode
+ * @is_action_delete: is delete
+ * @is_filter_mode_snoop: is filter mode snoop
+ * @ucast_mac_addr: ucast peer mac subscribed to mcast ip
* @srcs: source mac accpted
* @mask: mask
* @vap_id: vdev id
- * @is_action_delete: is delete
- * @is_filter_mode_snoop:
- * @is_mcast_addr_len:
+ * @is_mcast_addr_len: is mcast address length
*/
struct mcast_group_update_params {
int action;
int wildcard;
uint8_t *mcast_ip_addr;
int mcast_ip_addr_bytes;
- uint8_t *ucast_mac_addr;
- uint8_t filter_mode;
uint8_t nsrcs;
+ uint8_t filter_mode;
+ bool is_action_delete;
+ bool is_filter_mode_snoop;
+ uint8_t *ucast_mac_addr;
uint8_t *srcs;
uint8_t *mask;
uint8_t vap_id;
- bool is_action_delete;
- bool is_filter_mode_snoop;
bool is_mcast_addr_len;
};
@@ -3644,26 +3648,26 @@
* struct rtt_meas_req_params - RTT measurement request params
* @req_id: Request id
* @vdev_id: vdev id
- * @sta_mac_addr: pointer to station mac address
- * @spoof_mac_addr: pointer to spoof mac address
* @is_mode_na: 11NA
* @is_mode_ac: AC
* @is_bw_20: 20
* @is_bw_40: 40
* @is_bw_80: 80
+ * @sta_mac_addr: pointer to station mac address
+ * @spoof_mac_addr: pointer to spoof mac address
* @num_probe_rqst: number of probe request
* @channel_param: channel param
*/
struct rtt_meas_req_params {
uint8_t req_id;
uint8_t vdev_id;
- uint8_t *sta_mac_addr;
- uint8_t *spoof_mac_addr;
bool is_mode_na;
bool is_mode_ac;
bool is_bw_20;
bool is_bw_40;
bool is_bw_80;
+ uint8_t *sta_mac_addr;
+ uint8_t *spoof_mac_addr;
uint32_t num_probe_rqst;
struct channel_param channel;
};
@@ -3841,14 +3845,14 @@
* struct wmi_host_peer_adv_stats - peer adv stats event structure
* @peer_macaddr: mac address
* @fcs_count: fcs count
- * @rx_bytes: rx bytes
* @rx_count: rx count
+ * @rx_bytes: rx bytes
*/
struct wmi_host_peer_adv_stats {
uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE];
uint32_t fcs_count;
- uint64_t rx_bytes;
uint32_t rx_count;
+ uint64_t rx_bytes;
};
/**
@@ -6874,13 +6878,13 @@
/**
* struct wmi_host_rf_characterization_event_param - rf characterization table
* @freq: center frequency of primary channel (in MHz)
- * @bw: bandwidth of primary channel (in MHz)
* @chan_metric: primary channel-specific metric
+ * @bw: bandwidth of primary channel (in MHz)
*/
struct wmi_host_rf_characterization_event_param {
uint16_t freq;
- wmi_host_channel_width bw;
uint8_t chan_metric;
+ wmi_host_channel_width bw;
};
/*
@@ -7680,6 +7684,38 @@
uint32_t vdev_id;
uint32_t map_precedence;
};
+
+/**
+ * struct peer_vlan_config_param - peer vlan config command
+ * @tx_cmd: Tx command
+ * @rx_cmd: Rx command
+ * @tx_strip_insert: Strip or Insert vlan in Tx[0:Strip, 1: Insert]
+ * @tx_strip_insert_inner: Enable tx_strip_insert operation for inner vlan tag.
+ * @tx_strip_insert_outer: Enable tx_strip_insert operation for outer vlan tag.
+ * @rx_strip_c_tag: Strip c_tag
+ * @rx_strip_s_tag: Strip s_tag
+ * @rx_insert_c_tag: Insert c_tag
+ * @rx_insert_s_tag: Insert s_tag
+ *
+ * @insert_vlan_inner_tci: Vlan inner tci
+ * @insert_vlan_inner_tci: Vlan outer tci
+ *
+ * @vdev_id: vdev id corresponding to peer.
+ */
+struct peer_vlan_config_param {
+ uint16_t tx_cmd:1,
+ rx_cmd:1,
+ tx_strip_insert:1,
+ tx_strip_insert_inner:1,
+ tx_strip_insert_outer:1,
+ rx_strip_c_tag:1,
+ rx_strip_s_tag:1,
+ rx_insert_c_tag:1,
+ rx_insert_s_tag:1;
+ uint16_t insert_vlan_inner_tci;
+ uint16_t insert_vlan_outer_tci;
+ uint8_t vdev_id;
+};
#endif
/**
@@ -7747,27 +7783,27 @@
/**
* struct wmi_host_oem_indirect_data - Indirect OEM data
* @pdev_id: pdev id
- * @addr: 36 bit address
* @len: length of data in bytes
+ * @addr: 36 bit address
*/
struct wmi_host_oem_indirect_data {
uint32_t pdev_id;
- uint64_t addr;
uint32_t len;
+ uint64_t addr;
};
/**
* struct wmi_oem_response_param - OEM response info
* @num_data1: First data response length
- * @data_1: First data
* @num_data2: Second data response length
+ * @data_1: First data
* @data_2: Second data
* @indirect_data: Indirect data
*/
struct wmi_oem_response_param {
uint32_t num_data1;
- uint8_t *data_1;
uint32_t num_data2;
+ uint8_t *data_1;
uint8_t *data_2;
struct wmi_host_oem_indirect_data indirect_data;
};
diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h
index 4713a5e..2b47c44 100644
--- a/wmi/inc/wmi_unified_priv.h
+++ b/wmi/inc/wmi_unified_priv.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -2067,6 +2067,10 @@
QDF_STATUS (*send_peer_ft_roam_cmd)(wmi_unified_t wmi_handle,
uint8_t peer_addr[QDF_MAC_ADDR_SIZE],
uint8_t vdev_id);
+QDF_STATUS (*send_peer_vlan_config_cmd)(wmi_unified_t wmi,
+ uint8_t peer_addr[QDF_MAC_ADDR_SIZE],
+ struct peer_vlan_config_param *param);
+
#endif
QDF_STATUS (*send_mws_coex_status_req_cmd)(wmi_unified_t wmi_handle,
uint32_t vdev_id, uint32_t cmd_id);
diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c
index f509dfa..f875249 100644
--- a/wmi/src/wmi_unified.c
+++ b/wmi/src/wmi_unified.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -27,6 +27,7 @@
#include "qdf_platform.h"
#ifdef WMI_EXT_DBG
#include "qdf_list.h"
+#include "qdf_atomic.h"
#endif
#ifndef WMI_NON_TLV_SUPPORT
@@ -35,271 +36,6 @@
#include <linux/debugfs.h>
#include <target_if.h>
-#ifdef WMI_EXT_DBG
-#include "qdf_atomic.h"
-
-/**
- * wmi_ext_dbg_msg_enqueue() - enqueue wmi message
- *
- * @wmi_handle: wmi handler
- *
- * Return: size of wmi message queue after enqueue
- */
-static uint32_t wmi_ext_dbg_msg_enqueue(struct wmi_unified *wmi_handle,
- struct wmi_ext_dbg_msg *msg)
-{
- uint32_t list_size;
-
- qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
- qdf_list_insert_back_size(&wmi_handle->wmi_ext_dbg_msg_queue,
- &msg->node, &list_size);
- qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
-
- return list_size;
-}
-
-/**
- * wmi_ext_dbg_msg_dequeue() - dequeue wmi message
- *
- * @wmi_handle: wmi handler
- *
- * Return: wmi msg on success else NULL
- */
-static struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_dequeue(struct wmi_unified
- *wmi_handle)
-{
- qdf_list_node_t *list_node = NULL;
-
- qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
- qdf_list_remove_front(&wmi_handle->wmi_ext_dbg_msg_queue, &list_node);
- qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
-
- if (!list_node)
- return NULL;
-
- return qdf_container_of(list_node, struct wmi_ext_dbg_msg, node);
-}
-
-/**
- * wmi_ext_dbg_msg_record() - record wmi messages
- *
- * @wmi_handle: wmi handler
- * @buf: wmi message buffer
- * @len: wmi message length
- * @type: wmi message type
- *
- * Return: QDF_STATUS_SUCCESS on successful recording else failure.
- */
-static QDF_STATUS wmi_ext_dbg_msg_record(struct wmi_unified *wmi_handle,
- uint8_t *buf, uint32_t len,
- enum WMI_MSG_TYPE type)
-{
- struct wmi_ext_dbg_msg *msg;
- uint32_t list_size;
-
- msg = wmi_ext_dbg_msg_get(len);
- if (!msg)
- return QDF_STATUS_E_NOMEM;
-
- msg->len = len;
- msg->type = type;
- qdf_mem_copy(msg->buf, buf, len);
- msg->ts = qdf_get_log_timestamp();
- list_size = wmi_ext_dbg_msg_enqueue(wmi_handle, msg);
-
- if (list_size >= wmi_handle->wmi_ext_dbg_msg_queue_size) {
- msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
- wmi_ext_dbg_msg_put(msg);
- }
-
- return QDF_STATUS_SUCCESS;
-}
-
-/**
- * wmi_ext_dbg_msg_cmd_record() - record wmi command messages
- *
- * @wmi_handle: wmi handler
- * @buf: wmi command buffer
- * @len: wmi command message length
- *
- * Return: QDF_STATUS_SUCCESS on successful recording else failure.
- */
-static QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified *wmi_handle,
- uint8_t *buf, uint32_t len)
-{
- return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
- WMI_MSG_TYPE_CMD);
-}
-
-/**
- * wmi_ext_dbg_msg_event_record() - record wmi event messages
- *
- * @wmi_handle: wmi handler
- * @buf: wmi event buffer
- * @len: wmi event message length
- *
- * Return: QDF_STATUS_SUCCESS on successful recording else failure.
- */
-static QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified *wmi_handle,
- uint8_t *buf, uint32_t len)
-{
- uint32_t id;
-
- id = WMI_GET_FIELD(buf, WMI_CMD_HDR, COMMANDID);
- if (id != wmi_handle->wmi_events[wmi_diag_event_id])
- return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
- WMI_MSG_TYPE_EVENT);
-
- return QDF_STATUS_SUCCESS;
-}
-
-/**
- * wmi_ext_dbg_msg_queue_init() - create debugfs queue and associated lock
- *
- * @wmi_handle: wmi handler
- *
- * Return: none
- */
-static void wmi_ext_dbg_msg_queue_init(struct wmi_unified *wmi_handle)
-{
- qdf_list_create(&wmi_handle->wmi_ext_dbg_msg_queue,
- wmi_handle->wmi_ext_dbg_msg_queue_size);
- qdf_spinlock_create(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
-}
-
-/**
- * wmi_ext_dbg_msg_queue_deinit() - destroy debugfs queue and associated lock
- *
- * @wmi_handle: wmi handler
- *
- * Return: none
- */
-static void wmi_ext_dbg_msg_queue_deinit(struct wmi_unified *wmi_handle)
-{
- qdf_list_destroy(&wmi_handle->wmi_ext_dbg_msg_queue);
- qdf_spinlock_destroy(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
-}
-
-/**
- * wmi_ext_dbg_msg_show() - debugfs function to display whole content of
- * wmi command/event messages including headers.
- *
- * @file: qdf debugfs file handler
- * @arg: pointer to wmi handler
- *
- * Return: QDF_STATUS_SUCCESS if all the messages are shown successfully,
- * else QDF_STATUS_E_AGAIN if more data to show.
- */
-static QDF_STATUS wmi_ext_dbg_msg_show(qdf_debugfs_file_t file, void *arg)
-{
- struct wmi_unified *wmi_handle = (struct wmi_unified *)arg;
- struct wmi_ext_dbg_msg *msg;
- uint64_t secs, usecs;
-
- msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
- if (!msg)
- return QDF_STATUS_SUCCESS;
-
- qdf_debugfs_printf(file, "%s: 0x%x\n",
- msg->type == WMI_MSG_TYPE_CMD ? "COMMAND" :
- "EVENT", WMI_GET_FIELD(msg->buf, WMI_CMD_HDR,
- COMMANDID));
- qdf_log_timestamp_to_secs(msg->ts, &secs, &usecs);
- qdf_debugfs_printf(file, "Time: %llu.%llu\n", secs, usecs);
- qdf_debugfs_printf(file, "Length:%d\n", msg->len);
- qdf_debugfs_hexdump(file, msg->buf, msg->len,
- WMI_EXT_DBG_DUMP_ROW_SIZE,
- WMI_EXT_DBG_DUMP_GROUP_SIZE);
- qdf_debugfs_printf(file, "\n");
-
- if (qdf_debugfs_overflow(file)) {
- qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
- qdf_list_insert_front(&wmi_handle->wmi_ext_dbg_msg_queue,
- &msg->node);
- qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
-
- } else {
- wmi_ext_dbg_msg_put(msg);
- }
-
- return QDF_STATUS_E_AGAIN;
-}
-
-/**
- * wmi_ext_dbg_msg_write() - debugfs write not supported
- *
- * @priv: private data
- * @buf: received data buffer
- * @len: length of received buffer
- *
- * Return: QDF_STATUS_E_NOSUPPORT.
- */
-static QDF_STATUS wmi_ext_dbg_msg_write(void *priv, const char *buf,
- qdf_size_t len)
-{
- return QDF_STATUS_E_NOSUPPORT;
-}
-
-static struct qdf_debugfs_fops wmi_ext_dbgfs_ops = {
- .show = wmi_ext_dbg_msg_show,
- .write = wmi_ext_dbg_msg_write,
- .priv = NULL,
-};
-
-/**
- * wmi_ext_debugfs_init() - init debugfs items for extended wmi dump.
- *
- * @wmi_handle: wmi handler
- *
- * Return: QDF_STATUS_SUCCESS if debugfs is initialized else
- * QDF_STATUS_E_FAILURE
- */
-static QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle)
-{
- qdf_dentry_t dentry;
-
- dentry = qdf_debugfs_create_dir(WMI_EXT_DBG_DIR, NULL);
- if (!dentry) {
- WMI_LOGE("error while creating extended wmi debugfs dir");
- return QDF_STATUS_E_FAILURE;
- }
-
- wmi_ext_dbgfs_ops.priv = wmi_handle;
- if (!qdf_debugfs_create_file(WMI_EXT_DBG_FILE, WMI_EXT_DBG_FILE_PERM,
- dentry, &wmi_ext_dbgfs_ops)) {
- qdf_debugfs_remove_dir(dentry);
- WMI_LOGE("error while creating extended wmi debugfs file");
- return QDF_STATUS_E_FAILURE;
- }
-
- wmi_handle->wmi_ext_dbg_dentry = dentry;
- wmi_handle->wmi_ext_dbg_msg_queue_size = WMI_EXT_DBG_QUEUE_SIZE;
- wmi_ext_dbg_msg_queue_init(wmi_handle);
-
- return QDF_STATUS_SUCCESS;
-}
-
-/**
- * wmi_ext_debugfs_deinit() - cleanup/deinit debugfs items of extended wmi dump.
- *
- * @wmi_handle: wmi handler
- *
- * Return: QDF_STATUS_SUCCESS if cleanup is successful
- */
-static QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle)
-{
- struct wmi_ext_dbg_msg *msg;
-
- while ((msg = wmi_ext_dbg_msg_dequeue(wmi_handle)))
- wmi_ext_dbg_msg_put(msg);
-
- wmi_ext_dbg_msg_queue_deinit(wmi_handle);
- qdf_debugfs_remove_dir_recursive(wmi_handle->wmi_ext_dbg_dentry);
-
- return QDF_STATUS_SUCCESS;
-}
-
-#endif /*WMI_EXT_DBG */
/* This check for CONFIG_WIN temporary added due to redeclaration compilation
error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h
@@ -591,6 +327,271 @@
uint32_t wmi_record_max_length = WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH;
uint32_t wmi_display_size = 100;
+#ifdef WMI_EXT_DBG
+
+/**
+ * wmi_ext_dbg_msg_enqueue() - enqueue wmi message
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: size of wmi message queue after enqueue
+ */
+static uint32_t wmi_ext_dbg_msg_enqueue(struct wmi_unified *wmi_handle,
+ struct wmi_ext_dbg_msg *msg)
+{
+ uint32_t list_size;
+
+ qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+ qdf_list_insert_back_size(&wmi_handle->wmi_ext_dbg_msg_queue,
+ &msg->node, &list_size);
+ qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+
+ return list_size;
+}
+
+/**
+ * wmi_ext_dbg_msg_dequeue() - dequeue wmi message
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: wmi msg on success else NULL
+ */
+static struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_dequeue(struct wmi_unified
+ *wmi_handle)
+{
+ qdf_list_node_t *list_node = NULL;
+
+ qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+ qdf_list_remove_front(&wmi_handle->wmi_ext_dbg_msg_queue, &list_node);
+ qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+
+ if (!list_node)
+ return NULL;
+
+ return qdf_container_of(list_node, struct wmi_ext_dbg_msg, node);
+}
+
+/**
+ * wmi_ext_dbg_msg_record() - record wmi messages
+ *
+ * @wmi_handle: wmi handler
+ * @buf: wmi message buffer
+ * @len: wmi message length
+ * @type: wmi message type
+ *
+ * Return: QDF_STATUS_SUCCESS on successful recording else failure.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_record(struct wmi_unified *wmi_handle,
+ uint8_t *buf, uint32_t len,
+ enum WMI_MSG_TYPE type)
+{
+ struct wmi_ext_dbg_msg *msg;
+ uint32_t list_size;
+
+ msg = wmi_ext_dbg_msg_get(len);
+ if (!msg)
+ return QDF_STATUS_E_NOMEM;
+
+ msg->len = len;
+ msg->type = type;
+ qdf_mem_copy(msg->buf, buf, len);
+ msg->ts = qdf_get_log_timestamp();
+ list_size = wmi_ext_dbg_msg_enqueue(wmi_handle, msg);
+
+ if (list_size >= wmi_handle->wmi_ext_dbg_msg_queue_size) {
+ msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
+ wmi_ext_dbg_msg_put(msg);
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wmi_ext_dbg_msg_cmd_record() - record wmi command messages
+ *
+ * @wmi_handle: wmi handler
+ * @buf: wmi command buffer
+ * @len: wmi command message length
+ *
+ * Return: QDF_STATUS_SUCCESS on successful recording else failure.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified *wmi_handle,
+ uint8_t *buf, uint32_t len)
+{
+ return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
+ WMI_MSG_TYPE_CMD);
+}
+
+/**
+ * wmi_ext_dbg_msg_event_record() - record wmi event messages
+ *
+ * @wmi_handle: wmi handler
+ * @buf: wmi event buffer
+ * @len: wmi event message length
+ *
+ * Return: QDF_STATUS_SUCCESS on successful recording else failure.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified *wmi_handle,
+ uint8_t *buf, uint32_t len)
+{
+ uint32_t id;
+
+ id = WMI_GET_FIELD(buf, WMI_CMD_HDR, COMMANDID);
+ if (id != wmi_handle->wmi_events[wmi_diag_event_id])
+ return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
+ WMI_MSG_TYPE_EVENT);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wmi_ext_dbg_msg_queue_init() - create debugfs queue and associated lock
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: none
+ */
+static void wmi_ext_dbg_msg_queue_init(struct wmi_unified *wmi_handle)
+{
+ qdf_list_create(&wmi_handle->wmi_ext_dbg_msg_queue,
+ wmi_handle->wmi_ext_dbg_msg_queue_size);
+ qdf_spinlock_create(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+}
+
+/**
+ * wmi_ext_dbg_msg_queue_deinit() - destroy debugfs queue and associated lock
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: none
+ */
+static void wmi_ext_dbg_msg_queue_deinit(struct wmi_unified *wmi_handle)
+{
+ qdf_list_destroy(&wmi_handle->wmi_ext_dbg_msg_queue);
+ qdf_spinlock_destroy(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+}
+
+/**
+ * wmi_ext_dbg_msg_show() - debugfs function to display whole content of
+ * wmi command/event messages including headers.
+ *
+ * @file: qdf debugfs file handler
+ * @arg: pointer to wmi handler
+ *
+ * Return: QDF_STATUS_SUCCESS if all the messages are shown successfully,
+ * else QDF_STATUS_E_AGAIN if more data to show.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_show(qdf_debugfs_file_t file, void *arg)
+{
+ struct wmi_unified *wmi_handle = (struct wmi_unified *)arg;
+ struct wmi_ext_dbg_msg *msg;
+ uint64_t secs, usecs;
+
+ msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
+ if (!msg)
+ return QDF_STATUS_SUCCESS;
+
+ qdf_debugfs_printf(file, "%s: 0x%x\n",
+ msg->type == WMI_MSG_TYPE_CMD ? "COMMAND" :
+ "EVENT", WMI_GET_FIELD(msg->buf, WMI_CMD_HDR,
+ COMMANDID));
+ qdf_log_timestamp_to_secs(msg->ts, &secs, &usecs);
+ qdf_debugfs_printf(file, "Time: %llu.%llu\n", secs, usecs);
+ qdf_debugfs_printf(file, "Length:%d\n", msg->len);
+ qdf_debugfs_hexdump(file, msg->buf, msg->len,
+ WMI_EXT_DBG_DUMP_ROW_SIZE,
+ WMI_EXT_DBG_DUMP_GROUP_SIZE);
+ qdf_debugfs_printf(file, "\n");
+
+ if (qdf_debugfs_overflow(file)) {
+ qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+ qdf_list_insert_front(&wmi_handle->wmi_ext_dbg_msg_queue,
+ &msg->node);
+ qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+
+ } else {
+ wmi_ext_dbg_msg_put(msg);
+ }
+
+ return QDF_STATUS_E_AGAIN;
+}
+
+/**
+ * wmi_ext_dbg_msg_write() - debugfs write not supported
+ *
+ * @priv: private data
+ * @buf: received data buffer
+ * @len: length of received buffer
+ *
+ * Return: QDF_STATUS_E_NOSUPPORT.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_write(void *priv, const char *buf,
+ qdf_size_t len)
+{
+ return QDF_STATUS_E_NOSUPPORT;
+}
+
+static struct qdf_debugfs_fops wmi_ext_dbgfs_ops = {
+ .show = wmi_ext_dbg_msg_show,
+ .write = wmi_ext_dbg_msg_write,
+ .priv = NULL,
+};
+
+/**
+ * wmi_ext_debugfs_init() - init debugfs items for extended wmi dump.
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: QDF_STATUS_SUCCESS if debugfs is initialized else
+ * QDF_STATUS_E_FAILURE
+ */
+static QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle)
+{
+ qdf_dentry_t dentry;
+
+ dentry = qdf_debugfs_create_dir(WMI_EXT_DBG_DIR, NULL);
+ if (!dentry) {
+ WMI_LOGE("error while creating extended wmi debugfs dir");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ wmi_ext_dbgfs_ops.priv = wmi_handle;
+ if (!qdf_debugfs_create_file(WMI_EXT_DBG_FILE, WMI_EXT_DBG_FILE_PERM,
+ dentry, &wmi_ext_dbgfs_ops)) {
+ qdf_debugfs_remove_dir(dentry);
+ WMI_LOGE("error while creating extended wmi debugfs file");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ wmi_handle->wmi_ext_dbg_dentry = dentry;
+ wmi_handle->wmi_ext_dbg_msg_queue_size = WMI_EXT_DBG_QUEUE_SIZE;
+ wmi_ext_dbg_msg_queue_init(wmi_handle);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wmi_ext_debugfs_deinit() - cleanup/deinit debugfs items of extended wmi dump.
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: QDF_STATUS_SUCCESS if cleanup is successful
+ */
+static QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle)
+{
+ struct wmi_ext_dbg_msg *msg;
+
+ while ((msg = wmi_ext_dbg_msg_dequeue(wmi_handle)))
+ wmi_ext_dbg_msg_put(msg);
+
+ wmi_ext_dbg_msg_queue_deinit(wmi_handle);
+ qdf_debugfs_remove_dir_recursive(wmi_handle->wmi_ext_dbg_dentry);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+#endif /*WMI_EXT_DBG */
+
/**
* wmi_log_init() - Initialize WMI event logging
* @wmi_handle: WMI handle.
@@ -1808,6 +1809,7 @@
wmi_nofl_err("%s:%d, MAX %d WMI Pending cmds reached",
func, line, wmi_handle->wmi_max_cmds);
wmi_unified_debug_dump(wmi_handle);
+ htc_ce_tasklet_debug_dump(wmi_handle->htc_handle);
qdf_trigger_self_recovery(QDF_WMI_EXCEED_MAX_PENDING_CMDS);
return QDF_STATUS_E_BUSY;
}