summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFerry Zhou <tianguiz@codeaurora.org>2017-05-11 16:10:46 +0800
committerFerry Zhou <tianguiz@codeaurora.org>2017-09-07 09:55:40 +0800
commitb36205ccf799deb4bbfeff8f30a708afef3733bf (patch)
tree003a5a5d8317e3937f283c47e8baff7281fc6095
parent8515c142e7ba7fbba6b28dfc486e25f40c9ad333 (diff)
qcacld-2.0: Fix wrong tx power when DCC enabled
When DSRC DCC (Decentralized Congestion Control) enabled, the tx power used by FW to send packet into air is up to DCC setting, then the tx power in ocb_tx_ctrl_hdr_t sent down from host to FW might be different from the actual tx power used by FW. Fix it by getting tx power of each packet from FW. Since need to use MSDU_ID to match each packet's two parts of tx statistics tx power and others like data rate, bandwidth etc., so we need to make sure MSDU_IDs used in order. So, change the ol_tx_desc_free() to recycle the tx_desc to the end of free list to make sure that the MSDU_ID of each packet will be used in order. Change-Id: I2f167f773348d935d7748ce37fa09ef547725145 CRs-Fixed: 2024157
-rw-r--r--CORE/CLD_TXRX/HTT/htt.h38
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx.c253
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx.h51
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx_desc.c31
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx_send.c119
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_txrx.c7
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_txrx_types.h1
-rw-r--r--CORE/HDD/src/wlan_hdd_debugfs_ocb.c32
-rw-r--r--CORE/SERVICES/BMI/ol_fw.c3
-rw-r--r--CORE/SERVICES/COMMON/adf/adf_os_time.h12
-rw-r--r--CORE/SERVICES/COMMON/adf/linux/adf_os_time_pvt.h8
-rw-r--r--CORE/SERVICES/WMA/wma.c1
-rw-r--r--CORE/VOSS/inc/vos_api.h12
13 files changed, 459 insertions, 109 deletions
diff --git a/CORE/CLD_TXRX/HTT/htt.h b/CORE/CLD_TXRX/HTT/htt.h
index 454603e09c50..03b75ffd129b 100644
--- a/CORE/CLD_TXRX/HTT/htt.h
+++ b/CORE/CLD_TXRX/HTT/htt.h
@@ -6237,17 +6237,19 @@ PREPACK struct htt_txq_group {
* The following diagram shows the format of the TX completion indication sent
* from the target to the host
*
- * |31 26| 25 | 24 |23 16| 15 |14 11|10 8|7 0|
+ * |31 27|26|25|24|23 16| 15 |14 11|10 8|7 0|
* |-------------------------------------------------------------|
- * header: | reserved |append1|append|num | t_i| tid |status| msg_type |
+ * header: | reserved |a2|a1|a0| num | t_i| tid |status | msg_type |
* |-------------------------------------------------------------|
* payload: | MSDU1 ID | MSDU0 ID |
* |-------------------------------------------------------------|
* : MSDU3 ID : MSDU2 ID :
* |-------------------------------------------------------------|
* | struct htt_tx_compl_ind_append_retries |
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * | struct htt_tx_compl_ind_append_txtstamp |
+ * |-------------------------------------------------------------|
+ * | struct htt_tx_compl_ind_append_txtstamp |
+ * |-------------------------------------------------------------|
+ * | struct htt_tx_compl_ind_append_txpower |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* The following field definitions describe the format of the TX completion
@@ -6274,15 +6276,21 @@ PREPACK struct htt_txq_group {
* Bits 23:16
* Purpose: the number of payload in this indication
* Value: 1 to 255
- * - append
+ * - a0 - append0
* Bits 24:24
* Purpose: append the struct htt_tx_compl_ind_append_retries which contains
- * the number of tx retries for one MSDU at the end of this message
+ * the number of tx retries for one MSDU after MSDU ID.
* Value: 0 indicates no appending; 1 indicates appending
- * - append1
+ * - a1 - append1
* Bits 25:25
* Purpose: append the struct htt_tx_compl_ind_append_txtstamp which contains
- * the timestamp info for each TX msdu id in payload
+ * the timestamp info for each TX msdu id in payload after append0.
+ * Value: 0 indicates no appending; 1 indicates appending
+ * - a2 - append2
+ * Bits 26:26
+ * Purpose: append the struct htt_tx_compl_ind_append_txpower which contains
+ * one or more tx power of each MSDUs after append1.
+ * The start of tx power(s) must be 4-bytes-word aligned.
* Value: 0 indicates no appending; 1 indicates appending
* Payload fields:
* - hmsdu_id
@@ -6303,6 +6311,8 @@ PREPACK struct htt_txq_group {
#define HTT_TX_COMPL_IND_APPEND_M 0x01000000
#define HTT_TX_COMPL_IND_APPEND1_S 25
#define HTT_TX_COMPL_IND_APPEND1_M 0x02000000
+#define HTT_TX_COMPL_IND_APPEND2_S 26
+#define HTT_TX_COMPL_IND_APPEND2_M 0x04000000
#define HTT_TX_COMPL_IND_STATUS_SET(_info, _val) \
do { \
@@ -6347,7 +6357,13 @@ PREPACK struct htt_txq_group {
} while (0)
#define HTT_TX_COMPL_IND_APPEND1_GET(_info) \
(((_info) & HTT_TX_COMPL_IND_APPEND1_M) >> HTT_TX_COMPL_IND_APPEND1_S)
-
+#define HTT_TX_COMPL_IND_APPEND2_SET(_info, _val) \
+ do { \
+ HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_APPEND2, _val); \
+ ((_info) |= ((_val) << HTT_TX_COMPL_IND_APPEND2_S)); \
+ } while (0)
+#define HTT_TX_COMPL_IND_APPEND2_GET(_info) \
+ (((_info) & HTT_TX_COMPL_IND_APPEND2_M) >> HTT_TX_COMPL_IND_APPEND2_S)
#define HTT_TX_COMPL_CTXT_SZ sizeof(A_UINT16)
#define HTT_TX_COMPL_CTXT_NUM(_bytes) ((_bytes) >> 1)
@@ -6390,6 +6406,10 @@ PREPACK struct htt_tx_compl_ind_append_txtstamp {
A_UINT32 timestamp[1/*or more*/];
} POSTPACK;
+PREPACK struct htt_tx_compl_ind_append_txpower {
+ A_UINT16 tx_power[1/*or more*/];
+} POSTPACK;
+
/**
* @brief target -> host rate-control update indication message
*
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx.c b/CORE/CLD_TXRX/TXRX/ol_tx.c
index 00e2e06769e6..0521c0a4510a 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx.c
+++ b/CORE/CLD_TXRX/TXRX/ol_tx.c
@@ -56,25 +56,52 @@
#ifdef WLAN_FEATURE_DSRC
#include "ol_tx.h"
#include "adf_os_lock.h"
+#include "adf_os_util.h"
+#include "queue.h"
-struct ol_tx_stats_ring_head {
- adf_os_spinlock_t mutex;
- uint8_t head;
- uint8_t tail;
-};
-
+/**
+ * struct ol_tx_stats_ring_item - the item of a packet tx stats in the ring
+ * @list: list for all tx stats item in the ring
+ * @stats: a packet tx stats including fields from host and FW respectively
+ * @msdu_id: msdu ID used to match stats fields respectively from host and FW
+ * into a complete tx stats item
+ * @reserved: reserved to align to 4 bytes
+ */
struct ol_tx_stats_ring_item {
+ TAILQ_ENTRY(ol_tx_stats_ring_item) list;
struct ol_tx_per_pkt_stats stats;
uint16_t msdu_id;
uint8_t reserved[2];
};
+/**
+ * struct ol_tx_stats_ring_head - the ring head of all tx stats
+ * @mutex: mutex to access it exclusively
+ * @free_list: list of free tx stats ring items
+ * @host_list: list of tx stats items only containing tx stats fields from host
+ * @comp_list: list of tx stats items containing complete tx stats fields
+ * from host and FW, items in this list can be dequeued to user
+ * @num_free: number of free tx stats items
+ * @num_host_stat: number of tx stats items only containing tx stats fields
+ * from host
+ * @num_comp_stat: number of tx stats items containing complete tx stats fields
+ */
+struct ol_tx_stats_ring_head {
+ adf_os_spinlock_t mutex;
+ TAILQ_HEAD(free_list, ol_tx_stats_ring_item) free_list;
+ TAILQ_HEAD(host_list, ol_tx_stats_ring_item) host_list;
+ TAILQ_HEAD(comp_list, ol_tx_stats_ring_item) comp_list;
+ uint8_t num_free;
+ uint8_t num_host_stat;
+ uint8_t num_comp_stat;
+};
+
#define TX_STATS_RING_SZ 32
#define INVALID_TX_MSDU_ID (-1)
static struct ol_tx_stats_ring_head *tx_stats_ring_head;
static struct ol_tx_stats_ring_item *tx_stats_ring;
-static int ol_per_pkt_tx_stats_enabled = 0;
+static bool __ol_per_pkt_tx_stats_enabled = false;
static int ol_tx_stats_ring_init(void)
{
@@ -96,8 +123,17 @@ static int ol_tx_stats_ring_init(void)
vos_mem_zero(head, sizeof(*head));
vos_mem_zero(ring, sizeof(*ring) * TX_STATS_RING_SZ);
- for (i = 0; i < TX_STATS_RING_SZ; i++)
+
+ TAILQ_INIT(&head->free_list);
+ TAILQ_INIT(&head->host_list);
+ TAILQ_INIT(&head->comp_list);
+
+ for (i = 0; i < TX_STATS_RING_SZ; i++) {
ring[i].msdu_id = INVALID_TX_MSDU_ID;
+ TAILQ_INSERT_HEAD(&head->free_list, &ring[i], list);
+ }
+ head->num_free = TX_STATS_RING_SZ;
+
adf_os_spinlock_init(&head->mutex);
return 0;
@@ -116,11 +152,11 @@ static void ol_tx_stats_ring_deinit(void)
}
}
-void ol_per_pkt_tx_stats_enable(int enable)
+void ol_per_pkt_tx_stats_enable(bool enable)
{
int ret = 0;
- if (ol_per_pkt_tx_stats_enabled == !!enable)
+ if (__ol_per_pkt_tx_stats_enabled == enable)
return;
if (enable)
@@ -129,15 +165,122 @@ void ol_per_pkt_tx_stats_enable(int enable)
ol_tx_stats_ring_deinit();
if (!ret)
- ol_per_pkt_tx_stats_enabled = !!enable;
+ __ol_per_pkt_tx_stats_enabled = enable;
else
- ol_per_pkt_tx_stats_enabled = 0;
+ __ol_per_pkt_tx_stats_enabled = false;
adf_os_mb();
}
+bool ol_per_pkt_tx_stats_enabled(void)
+{
+ return __ol_per_pkt_tx_stats_enabled;
+}
+
+static inline int __free_list_empty(void)
+{
+ return TAILQ_EMPTY(&tx_stats_ring_head->free_list);
+}
+
+static inline int __host_list_empty(void)
+{
+ return TAILQ_EMPTY(&tx_stats_ring_head->host_list);
+}
+
+static inline int __comp_list_empty(void)
+{
+ return TAILQ_EMPTY(&tx_stats_ring_head->comp_list);
+}
+
+static inline struct ol_tx_stats_ring_item *__get_ring_item(void)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+ struct ol_tx_stats_ring_item *item = NULL;
+
+ if (!__free_list_empty()) {
+ item = TAILQ_FIRST(&h->free_list);
+ TAILQ_REMOVE(&h->free_list, item, list);
+ h->num_free--;
+ } else if (!__comp_list_empty()) {
+ /* Discard the oldest one. */
+ item = TAILQ_LAST(&h->comp_list, comp_list);
+ TAILQ_REMOVE(&h->comp_list, item, list);
+ h->num_comp_stat--;
+ } else if (!__host_list_empty()) {
+ item = TAILQ_LAST(&h->host_list, host_list);
+ TAILQ_REMOVE(&h->host_list, item, list);
+ h->num_host_stat--;
+ }
+
+ return item;
+}
+
+static inline struct ol_tx_stats_ring_item *
+__get_ring_item_host(uint32_t msdu_id)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+ struct ol_tx_stats_ring_item *item = NULL;
+ struct ol_tx_stats_ring_item *temp = NULL;
+
+ if (__host_list_empty())
+ goto exit;
+
+ TAILQ_FOREACH_REVERSE(temp, &h->host_list, host_list, list) {
+ if (temp && (temp->msdu_id == msdu_id)) {
+ item = temp;
+ TAILQ_REMOVE(&h->host_list, item, list);
+ h->num_host_stat--;
+ goto exit;
+ }
+ }
+
+exit:
+ return item;
+}
+
+static inline struct ol_tx_stats_ring_item *__get_ring_item_comp(void)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+ struct ol_tx_stats_ring_item *item = NULL;
+
+ if (__comp_list_empty())
+ goto exit;
+
+ item = TAILQ_LAST(&h->comp_list, comp_list);
+ TAILQ_REMOVE(&h->comp_list, item, list);
+ h->num_comp_stat--;
+
+exit:
+ return item;
+}
+
+static inline void __put_ring_item_host(struct ol_tx_stats_ring_item *item)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+
+ TAILQ_INSERT_HEAD(&h->host_list, item, list);
+ h->num_host_stat++;
+}
+
+static inline void __put_ring_item_comp(struct ol_tx_stats_ring_item *item)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+
+ TAILQ_INSERT_HEAD(&h->comp_list, item, list);
+ h->num_comp_stat++;
+}
+
+static inline void __free_ring_item(struct ol_tx_stats_ring_item *item)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+
+ TAILQ_INSERT_HEAD(&h->free_list, item, list);
+ h->num_free++;
+}
+
/**
- * ol_tx_stats_ring_enque() - enqueue the tx per packet stats
+ * ol_tx_stats_ring_enque_host() - enqueue the tx stats fields of a packet
+ * collected from tx path of host driver
* @msdu_id: ol_tx_desc_id
* @chan_freq: channel freqency
* @bandwidth: channel bandwith like 10 or 20MHz
@@ -145,26 +288,23 @@ void ol_per_pkt_tx_stats_enable(int enable)
* @datarate: data rate used
*
* This interface is for caller from TXRX layer in interrupt context.
- *
- * Return: None
*/
-void ol_tx_stats_ring_enque(uint32_t msdu_id, uint32_t chan_freq,
- uint32_t bandwidth, uint8_t *mac_address,
- uint8_t datarate, uint8_t power)
+void ol_tx_stats_ring_enque_host(uint32_t msdu_id, uint32_t chan_freq,
+ uint32_t bandwidth, uint8_t *mac_address,
+ uint8_t datarate)
{
struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
- struct ol_tx_stats_ring_item *ring = tx_stats_ring;
struct ol_tx_stats_ring_item *item;
static uint32_t seq_no = 0;
- if (!h || !ring)
+ if (!h)
return;
adf_os_spin_lock(&h->mutex);
- item = &ring[h->head++];
- if (h->head == TX_STATS_RING_SZ)
- h->head = 0;
+ item = __get_ring_item();
+ if (!item)
+ goto exit;
item->msdu_id = msdu_id;
item->stats.seq_no = seq_no++;
@@ -172,25 +312,44 @@ void ol_tx_stats_ring_enque(uint32_t msdu_id, uint32_t chan_freq,
item->stats.bandwidth = bandwidth;
vos_mem_copy(item->stats.mac_address, mac_address, 6);
item->stats.datarate = datarate;
- item->stats.tx_power = power;
-
- /* if ring is full, discard the oldest one. */
- if (h->head == h->tail) {
- item = &ring[h->tail++];
- if (h->tail == TX_STATS_RING_SZ)
- h->tail = 0;
- item->msdu_id = INVALID_TX_MSDU_ID;
- }
+ __put_ring_item_host(item);
+exit:
adf_os_spin_unlock(&h->mutex);
+}
+
+/**
+ * ol_tx_stats_ring_enque_comp() - enqueue the tx power of a packet from FW
+ * to form a complete tx stats item, which can be delivered to user
+ * @msdu_id: ol_tx_desc_id
+ * @tx_power: tx power used from FW
+ *
+ * This interface is for caller from WMA layer context.
+ */
+void ol_tx_stats_ring_enque_comp(uint32_t msdu_id, uint32_t tx_power)
+{
+ struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
+ struct ol_tx_stats_ring_item *item;
+
+ if (!h)
+ return;
+
+ adf_os_spin_lock(&h->mutex);
+
+ item = __get_ring_item_host(msdu_id);
+ if (!item)
+ goto exit;
+
+ item->stats.tx_power = (uint8_t)tx_power;
+ __put_ring_item_comp(item);
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "%s(), msdu_id=%u,head=%u,tail=%u\n",
- __func__, msdu_id, h->head, h->tail);
+exit:
+ adf_os_spin_unlock(&h->mutex);
}
/**
- * ol_tx_stats_ring_deque() - dequeue a tx per packet stats
+ * ol_tx_stats_ring_deque() - dequeue a complete tx stats item to user
* @stats: tx per packet stats
*
* This interface is for caller from user space process context.
@@ -200,25 +359,19 @@ void ol_tx_stats_ring_enque(uint32_t msdu_id, uint32_t chan_freq,
int ol_tx_stats_ring_deque(struct ol_tx_per_pkt_stats *stats)
{
struct ol_tx_stats_ring_head *h = tx_stats_ring_head;
- struct ol_tx_stats_ring_item *ring = tx_stats_ring;
struct ol_tx_stats_ring_item *item;
int ret = 0;
- if (!h || !ring)
+ if (!h)
return ret;
adf_os_spin_lock(&h->mutex);
- if (h->head == h->tail) {
+ item = __get_ring_item_comp();
+ if (!item)
goto exit;
- }
- item = &ring[h->tail++];
- if (h->tail == TX_STATS_RING_SZ)
- h->tail = 0;
-
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "%s(), msdu_id=%u,head=%u,tail=%u\n",
- __func__, item->msdu_id, h->head, h->tail);
+ __free_ring_item(item);
vos_mem_copy(stats, &item->stats, sizeof(*stats));
item->msdu_id = INVALID_TX_MSDU_ID;
@@ -226,7 +379,6 @@ int ol_tx_stats_ring_deque(struct ol_tx_per_pkt_stats *stats)
exit:
adf_os_spin_unlock(&h->mutex);
-
return ret;
}
#endif /* WLAN_FEATURE_DSRC */
@@ -888,7 +1040,7 @@ ol_collect_per_pkt_tx_stats(ol_txrx_vdev_handle vdev,
struct ol_txrx_ocb_chan_info *chan_info;
int i;
- if (!ol_per_pkt_tx_stats_enabled)
+ if (!ol_per_pkt_tx_stats_enabled())
return;
chan_info = &vdev->ocb_channel_info[0];
@@ -899,9 +1051,10 @@ ol_collect_per_pkt_tx_stats(ol_txrx_vdev_handle vdev,
break;
}
}
- ol_tx_stats_ring_enque(msdu_id, tx_ctrl->channel_freq,
- chan_info->bandwidth, chan_info->mac_address,
- tx_ctrl->datarate, tx_ctrl->pwr);
+
+ ol_tx_stats_ring_enque_host(msdu_id, tx_ctrl->channel_freq,
+ chan_info->bandwidth, chan_info->mac_address,
+ tx_ctrl->datarate);
}
#else
static void dsrc_update_broadcast_frame_sa(ol_txrx_vdev_handle vdev,
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx.h b/CORE/CLD_TXRX/TXRX/ol_tx.h
index 08a625e75594..986efea00ba7 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx.h
+++ b/CORE/CLD_TXRX/TXRX/ol_tx.h
@@ -37,7 +37,15 @@
#include <ol_txrx_api.h> /* ol_txrx_vdev_handle */
#include <ol_txrx_types.h> /* ol_tx_desc_t, ol_txrx_msdu_info_t */
-#ifdef WLAN_FEATURE_DSRC
+/**
+ * struct ol_tx_per_pkt_stats - tx stats info of each packet sent out
+ * @seq_no: sequential number
+ * @chan_freq: channel freqency that this packet used
+ * @bandwidth: channel bandwidth
+ * @datarate: data rate
+ * @tx_power: tx power
+ * @mac_address: source MAC address that this packet used
+ */
struct ol_tx_per_pkt_stats {
uint32_t seq_no;
uint32_t chan_freq;
@@ -47,20 +55,51 @@ struct ol_tx_per_pkt_stats {
uint8_t mac_address[6];
};
+#ifdef WLAN_FEATURE_DSRC
void
-ol_per_pkt_tx_stats_enable(int enable);
+ol_per_pkt_tx_stats_enable(bool enable);
+
+bool
+ol_per_pkt_tx_stats_enabled(void);
void
-ol_tx_stats_ring_enque(uint32_t msdu_id, uint32_t chan_freq,
- uint32_t bandwidth, uint8_t *mac_address,
- uint8_t datarate, uint8_t power);
+ol_tx_stats_ring_enque_host(uint32_t msdu_id, uint32_t chan_freq,
+ uint32_t bandwidth, uint8_t *mac_address,
+ uint8_t datarate);
+
+void
+ol_tx_stats_ring_enque_comp(uint32_t msdu_id, uint32_t tx_power);
int
ol_tx_stats_ring_deque(struct ol_tx_per_pkt_stats *stats);
#else
static inline void
-ol_per_pkt_tx_stats_enable(int enable)
+ol_per_pkt_tx_stats_enable(bool enable)
+{
+}
+
+static inline bool
+ol_per_pkt_tx_stats_enabled(void)
+{
+ return false;
+}
+
+static inline void
+ol_tx_stats_ring_enque_host(uint32_t msdu_id, uint32_t chan_freq,
+ uint32_t bandwidth, uint8_t *mac_address,
+ uint8_t datarate)
+{
+}
+
+static inline void
+ol_tx_stats_ring_enque_comp(uint32_t msdu_id, uint32_t tx_power)
+{
+}
+
+static inline int
+ol_tx_stats_ring_deque(struct ol_tx_per_pkt_stats *stats)
{
+ return 0;
}
#endif /* WLAN_FEATURE_DSRC */
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx_desc.c b/CORE/CLD_TXRX/TXRX/ol_tx_desc.c
index 793ef8baf1af..2c45b1f6bffe 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx_desc.c
+++ b/CORE/CLD_TXRX/TXRX/ol_tx_desc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -111,6 +111,30 @@ ol_tx_desc_alloc_hl(struct ol_txrx_pdev_t *pdev, struct ol_txrx_vdev_t *vdev)
return tx_desc;
}
+#ifdef WLAN_FEATURE_DSRC
+static inline void
+__ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
+{
+ ((union ol_tx_desc_list_elem_t *)tx_desc)->next = NULL;
+ if (pdev->tx_desc.freelist) {
+ pdev->tx_desc.last->next =
+ (union ol_tx_desc_list_elem_t *)tx_desc;
+ } else {
+ pdev->tx_desc.freelist =
+ (union ol_tx_desc_list_elem_t *)tx_desc;
+ }
+ pdev->tx_desc.last = (union ol_tx_desc_list_elem_t *)tx_desc;
+}
+#else
+static inline void
+__ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
+{
+ ((union ol_tx_desc_list_elem_t *)tx_desc)->next =
+ pdev->tx_desc.freelist;
+ pdev->tx_desc.freelist = (union ol_tx_desc_list_elem_t *)tx_desc;
+}
+#endif /* WLAN_FEATURE_DSRC */
+
void
ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
{
@@ -121,9 +145,8 @@ ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
tx_desc->entry_timestamp_ticks = 0xffffffff;
#endif
#endif
- ((union ol_tx_desc_list_elem_t *)tx_desc)->next =
- pdev->tx_desc.freelist;
- pdev->tx_desc.freelist = (union ol_tx_desc_list_elem_t *) tx_desc;
+
+ __ol_tx_desc_free(pdev, tx_desc);
pdev->tx_desc.num_free++;
#if defined(CONFIG_PER_VDEV_TX_DESC_POOL)
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx_send.c b/CORE/CLD_TXRX/TXRX/ol_tx_send.c
index dfcc640018b7..a12636092ac2 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx_send.c
+++ b/CORE/CLD_TXRX/TXRX/ol_tx_send.c
@@ -534,14 +534,42 @@ ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits)
OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev);
}
+static inline int
+ol_tx_get_retries_size(u_int32_t *msg_word, int num_msdus)
+{
+ struct htt_tx_compl_ind_append_retries *list = NULL;
+ int offset;
+ int i = 0;
+
+ if (!HTT_TX_COMPL_IND_APPEND_GET(*msg_word))
+ return 0;
+
+ /* offset in 32 bits word */
+ offset = 1 + ((num_msdus + 1) >> 1);
+ list = (struct htt_tx_compl_ind_append_retries *)(msg_word + offset);
+ while (list[i].flag && (i < num_msdus)) {
+ i++;
+ }
+
+ return (i * sizeof(struct htt_tx_compl_ind_append_retries)) >> 2;
+}
+
+static inline int
+ol_tx_get_txtstamps_size(u_int32_t *msg_word, int num_msdus)
+{
+ if (!HTT_TX_COMPL_IND_APPEND1_GET(*msg_word))
+ return 0;
+
+ return (num_msdus * sizeof(struct htt_tx_compl_ind_append_txtstamp))
+ >> 2;
+}
+
#ifdef WLAN_FEATURE_TSF_PLUS
-static inline struct htt_tx_compl_ind_append_txtstamp *ol_tx_get_txtstamps(
- u_int32_t *msg_word, int num_msdus)
+static inline struct htt_tx_compl_ind_append_txtstamp *
+ol_tx_get_txtstamps(u_int32_t *msg_word, int num_msdus)
{
u_int32_t has_tx_tsf;
- u_int32_t has_retry;
struct htt_tx_compl_ind_append_txtstamp *txtstamp_list = NULL;
- struct htt_tx_compl_ind_append_retries *retry_list = NULL;
int offset_dwords;
has_tx_tsf = HTT_TX_COMPL_IND_APPEND1_GET(*msg_word);
@@ -549,30 +577,15 @@ static inline struct htt_tx_compl_ind_append_txtstamp *ol_tx_get_txtstamps(
return NULL;
offset_dwords = 1 + ((num_msdus + 1) >> 1);
-
- has_retry = HTT_TX_COMPL_IND_APPEND_GET(*msg_word);
- if (has_retry) {
- int retry_index = 0;
- int width_for_each_retry =
- (sizeof(struct htt_tx_compl_ind_append_retries) +
- 3) >> 2;
-
- retry_list = (struct htt_tx_compl_ind_append_retries *)
- (msg_word + offset_dwords);
- while (retry_list) {
- if (retry_list[retry_index++].flag == 0)
- break;
- }
- offset_dwords += retry_index * width_for_each_retry;
- }
+ offset_dwords += ol_tx_get_retries_size(msg_word, num_msdus);
txtstamp_list = (struct htt_tx_compl_ind_append_txtstamp *)
(msg_word + offset_dwords);
return txtstamp_list;
}
-static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev,
- adf_nbuf_t netbuf, u_int64_t ts)
+static inline void
+ol_tx_timestamp(ol_txrx_pdev_handle pdev, adf_nbuf_t netbuf, u_int64_t ts)
{
if (!netbuf)
return;
@@ -581,17 +594,60 @@ static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev,
pdev->ol_tx_timestamp_cb(netbuf, ts);
}
#else
-static inline struct htt_tx_compl_ind_append_txtstamp *ol_tx_get_txtstamps(
- u_int32_t *msg_word, int num_msdus)
+static inline struct htt_tx_compl_ind_append_txtstamp *
+ol_tx_get_txtstamps(u_int32_t *msg_word, int num_msdus)
{
return NULL;
}
-static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev,
- adf_nbuf_t netbuf, u_int64_t ts)
+static inline void
+ol_tx_timestamp(ol_txrx_pdev_handle pdev, adf_nbuf_t netbuf, u_int64_t ts)
{
}
-#endif
+#endif /* WLAN_FEATURE_TSF_PLUS */
+
+#ifdef WLAN_FEATURE_DSRC
+#define DSRC_INVALID_TX_POWER 0xffff
+
+static inline struct htt_tx_compl_ind_append_txpower *
+ol_tx_get_txpowers(u_int32_t *msg_word, int num_msdus)
+{
+ struct htt_tx_compl_ind_append_txpower *txpower_list = NULL;
+ int offset_dwords;
+
+ /* Check if tx power exists. */
+ if (!HTT_TX_COMPL_IND_APPEND2_GET(*msg_word))
+ return NULL;
+
+ offset_dwords = 1 + ((num_msdus + 1) >> 1);
+ offset_dwords += ol_tx_get_retries_size(msg_word, num_msdus);
+ offset_dwords += ol_tx_get_txtstamps_size(msg_word, num_msdus);
+ txpower_list = (struct htt_tx_compl_ind_append_txpower *)
+ (msg_word + offset_dwords);
+
+ return txpower_list;
+}
+
+static inline void
+ol_tx_power_handler(u_int16_t desc_id, u_int16_t tx_power)
+{
+ if (DSRC_INVALID_TX_POWER == tx_power)
+ return;
+
+ ol_tx_stats_ring_enque_comp(desc_id, tx_power);
+}
+#else
+static inline struct htt_tx_compl_ind_append_txpower *
+ol_tx_get_txpowers(u_int32_t *msg_word, int num_msdus)
+{
+ return NULL;
+}
+
+static inline void
+ol_tx_power_handler(u_int16_t desc_id, u_int16_t tx_power)
+{
+}
+#endif /* WLAN_FEATURE_DSRC */
/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of ol_tx_completion_handler().
* any change in ol_tx_completion_handler() must be mirrored in ol_tx_inspect_handler().
@@ -616,6 +672,7 @@ ol_tx_completion_handler(
ol_tx_desc_list tx_descs;
uint32_t is_tx_desc_freed = 0;
struct htt_tx_compl_ind_append_txtstamp *txtstamp_list = NULL;
+ struct htt_tx_compl_ind_append_txpower *txpower_list = NULL;
u_int32_t *msg_word = (u_int32_t *)msg;
u_int16_t *desc_ids = (u_int16_t *)(msg_word + 1);
@@ -631,8 +688,10 @@ ol_tx_completion_handler(
}
OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus);
- if (status == htt_tx_status_ok)
+ if (status == htt_tx_status_ok) {
txtstamp_list = ol_tx_get_txtstamps(msg_word, num_msdus);
+ txpower_list = ol_tx_get_txpowers(msg_word, num_msdus);
+ }
trace_str = (status) ? "OT:C:F:" : "OT:C:S:";
for (i = 0; i < num_msdus; i++) {
@@ -640,10 +699,14 @@ ol_tx_completion_handler(
tx_desc = ol_tx_desc_find(pdev, tx_desc_id);
tx_desc->status = status;
netbuf = tx_desc->netbuf;
+
if (txtstamp_list)
ol_tx_timestamp(pdev, netbuf,
(u_int64_t)txtstamp_list->timestamp[i]);
+ if (txpower_list)
+ ol_tx_power_handler(tx_desc_id, txpower_list->tx_power[i]);
+
NBUF_UPDATE_TX_PKT_COUNT(netbuf, NBUF_TX_PKT_FREE);
DPTRACE(adf_dp_trace_ptr(netbuf,
ADF_DP_TRACE_FREE_PACKET_PTR_RECORD,
diff --git a/CORE/CLD_TXRX/TXRX/ol_txrx.c b/CORE/CLD_TXRX/TXRX/ol_txrx.c
index 690bbbeaa9a6..3dd048bc3c3b 100644
--- a/CORE/CLD_TXRX/TXRX/ol_txrx.c
+++ b/CORE/CLD_TXRX/TXRX/ol_txrx.c
@@ -496,12 +496,13 @@ ol_txrx_pdev_attach(
void *htt_tx_desc;
u_int32_t paddr_lo;
- if (i == (desc_pool_size - 1))
+ if (i == (desc_pool_size - 1)) {
c_element->next = NULL;
- else
+ pdev->tx_desc.last = c_element;
+ } else {
c_element->next = (union ol_tx_desc_list_elem_t *)
ol_tx_desc_find(pdev, i + 1);
-
+ }
htt_tx_desc = htt_tx_desc_alloc(pdev->htt_pdev, &paddr_lo);
if (! htt_tx_desc) {
VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_FATAL,
diff --git a/CORE/CLD_TXRX/TXRX/ol_txrx_types.h b/CORE/CLD_TXRX/TXRX/ol_txrx_types.h
index b0f572ef22c0..75974104ffe2 100644
--- a/CORE/CLD_TXRX/TXRX/ol_txrx_types.h
+++ b/CORE/CLD_TXRX/TXRX/ol_txrx_types.h
@@ -621,6 +621,7 @@ struct ol_txrx_pdev_t {
u_int16_t pool_size;
u_int16_t num_free;
union ol_tx_desc_list_elem_t *freelist;
+ union ol_tx_desc_list_elem_t *last;
uint32_t page_size;
uint16_t desc_reserved_size;
uint8_t page_divider;
diff --git a/CORE/HDD/src/wlan_hdd_debugfs_ocb.c b/CORE/HDD/src/wlan_hdd_debugfs_ocb.c
index 8c4fd1821825..9ea98101e1a5 100644
--- a/CORE/HDD/src/wlan_hdd_debugfs_ocb.c
+++ b/CORE/HDD/src/wlan_hdd_debugfs_ocb.c
@@ -22,7 +22,9 @@
#include "wlan_hdd_debugfs.h"
#include "wlan_hdd_debugfs_ocb.h"
#include "ol_tx.h"
+#include "wma_api.h"
#include "wlan_hdd_ocb.h"
+#include "adf_os_time.h"
#define WLAN_DSRC_COMMAND_MAX_SIZE 8
#define WLAN_DSRC_CHAN_STATS_ENABLE 1
@@ -332,6 +334,16 @@ int wlan_hdd_create_dsrc_chan_stats_file(hdd_adapter_t *adapter,
return 0;
}
+static inline bool __tx_stats_enabled(void)
+{
+ return ol_per_pkt_tx_stats_enabled();
+}
+
+static inline void __enable_tx_stats(bool enable)
+{
+ ol_per_pkt_tx_stats_enable(enable);
+}
+
/**
* __per_pkt_tx_stats_read() - read DSRC per-packet tx stats by DSRC app
* @file: file pointer
@@ -361,6 +373,9 @@ static ssize_t __per_pkt_tx_stats_read(struct file *file,
if (ret)
return ret;
+ if (!__tx_stats_enabled())
+ return ret;
+
ret = ol_tx_stats_ring_deque(&tx_stats);
if (ret) {
ret = sizeof(tx_stats);
@@ -392,16 +407,21 @@ static ssize_t per_pkt_tx_stats_read(struct file *file,
*
* Return: 0 on success, error number otherwise
*/
-static int __enable_per_pkt_tx_stats(int enable)
+static int __enable_per_pkt_tx_stats(bool enable)
{
- static int __enable = 0;
int ret = 0;
- if ((__enable && enable) || (!__enable && !enable))
+ if (enable == __tx_stats_enabled())
return ret;
- ol_per_pkt_tx_stats_enable(enable);
- __enable = enable;
+ ret = process_wma_set_command(0, WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE,
+ enable ? 1 : 0, PDEV_CMD);
+ if (!ret) {
+ adf_os_msleep(100);
+ __enable_tx_stats(enable);
+ } else {
+ hddLog(LOGE,FL("WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE failed"));
+ }
return ret;
}
@@ -463,7 +483,7 @@ static ssize_t __per_pkt_tx_stats_write(struct file *file,
goto failure;
}
- __enable_per_pkt_tx_stats((int)enable);
+ __enable_per_pkt_tx_stats(!!enable);
vos_mem_free(cmd);
EXIT();
diff --git a/CORE/SERVICES/BMI/ol_fw.c b/CORE/SERVICES/BMI/ol_fw.c
index 6e6360ece52b..dab571ea0a9e 100644
--- a/CORE/SERVICES/BMI/ol_fw.c
+++ b/CORE/SERVICES/BMI/ol_fw.c
@@ -2840,7 +2840,8 @@ ol_sdio_extra_initialization(struct ol_softc *scn)
param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET |
HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE);
- if (!vos_is_ptp_tx_opt_enabled())
+ if (!vos_is_ptp_tx_opt_enabled() &&
+ !vos_is_ocb_per_pkt_tx_comp_msg_needed())
param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
/* enable TX completion to collect tx_desc for pktlog */
diff --git a/CORE/SERVICES/COMMON/adf/adf_os_time.h b/CORE/SERVICES/COMMON/adf/adf_os_time.h
index 0c0c11189732..6c92692a5bf3 100644
--- a/CORE/SERVICES/COMMON/adf/adf_os_time.h
+++ b/CORE/SERVICES/COMMON/adf/adf_os_time.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -117,6 +117,16 @@ adf_os_mdelay(int msecs)
}
/**
+ * adf_os_msleep() - sleep in milliseconds.
+ * @msecs: milliseconds to sleep
+ */
+static inline void
+adf_os_msleep(int msecs)
+{
+ __adf_os_msleep(msecs);
+}
+
+/**
* @brief Check if _a is later than _b.
*/
#define adf_os_time_after(_a, _b) __adf_os_time_after(_a, _b)
diff --git a/CORE/SERVICES/COMMON/adf/linux/adf_os_time_pvt.h b/CORE/SERVICES/COMMON/adf/linux/adf_os_time_pvt.h
index d8e07af89614..7eda8c9583f1 100644
--- a/CORE/SERVICES/COMMON/adf/linux/adf_os_time_pvt.h
+++ b/CORE/SERVICES/COMMON/adf/linux/adf_os_time_pvt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -103,6 +103,12 @@ __adf_os_mdelay(a_uint32_t msecs)
mdelay(msecs);
}
+static inline void
+__adf_os_msleep(a_uint32_t msecs)
+{
+ msleep(msecs);
+}
+
/**
* @brief Check if _a is later than _b.
*/
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index 63b2476022c8..93667eda3e53 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -17350,6 +17350,7 @@ static void wma_process_cli_set_cmd(tp_wma_handle wma,
case WMI_PDEV_PARAM_ANT_DIV_SELFTEST:
case WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL:
case WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE:
+ case WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE:
break;
default:
WMA_LOGE("Invalid wda_cli_set pdev command/Not"
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 6022e0a52e82..f1b77be7b990 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -356,6 +356,18 @@ static inline bool vos_is_ptp_tx_opt_enabled(void)
}
#endif
+#ifdef WLAN_FEATURE_DSRC
+static inline bool vos_is_ocb_per_pkt_tx_comp_msg_needed(void)
+{
+ return true;
+}
+#else
+static inline bool vos_is_ocb_per_pkt_tx_comp_msg_needed(void)
+{
+ return false;
+}
+#endif
+
v_U64_t vos_get_monotonic_boottime(void);
/**