summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
/**