Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4dc399fb authored by Vevek Venkatesan's avatar Vevek Venkatesan
Browse files

qcacmn: add Tx descriptor history in Tx and comp rings

Add the history support to log Tx descriptors programmed
in Tx and completion HW rings.

Change-Id: I60954c93e2595e7dad1251c459eed8afc761e917
CRs-Fixed: 2924614
parent 0885ca51
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -4298,6 +4298,62 @@ static inline void dp_soc_rx_history_detach(struct dp_soc *soc)
}
#endif

#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY
/**
 * dp_soc_tx_history_attach() - Attach the ring history record buffers
 * @soc: DP soc structure
 *
 * This function allocates the memory for recording the tx tcl ring and
 * the tx comp ring entries. There is no error returned in case
 * of allocation failure since the record function checks if the history is
 * initialized or not. We do not want to fail the driver load in case of
 * failure to allocate memory for debug history.
 *
 * Returns: None
 */
static void dp_soc_tx_history_attach(struct dp_soc *soc)
{
	uint32_t tx_tcl_hist_size;
	uint32_t tx_comp_hist_size;

	tx_tcl_hist_size = sizeof(*soc->tx_tcl_history);
	soc->tx_tcl_history = dp_context_alloc_mem(soc, DP_TX_TCL_HIST_TYPE,
						   tx_tcl_hist_size);
	if (soc->tx_tcl_history)
		qdf_atomic_init(&soc->tx_tcl_history->index);

	tx_comp_hist_size = sizeof(*soc->tx_comp_history);
	soc->tx_comp_history = dp_context_alloc_mem(soc, DP_TX_COMP_HIST_TYPE,
						    tx_comp_hist_size);
	if (soc->tx_comp_history)
		qdf_atomic_init(&soc->tx_comp_history->index);
}

/**
 * dp_soc_tx_history_detach() - Detach the ring history record buffers
 * @soc: DP soc structure
 *
 * This function frees the memory for recording the tx tcl ring and
 * the tx comp ring entries.
 *
 * Returns: None
 */
static void dp_soc_tx_history_detach(struct dp_soc *soc)
{
	dp_context_free_mem(soc, DP_TX_TCL_HIST_TYPE, soc->tx_tcl_history);
	dp_context_free_mem(soc, DP_TX_COMP_HIST_TYPE, soc->tx_comp_history);
}

#else
static inline void dp_soc_tx_history_attach(struct dp_soc *soc)
{
}

static inline void dp_soc_tx_history_detach(struct dp_soc *soc)
{
}
#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */

/*
* dp_pdev_attach_wifi3() - attach txrx pdev
* @txrx_soc: Datapath SOC handle
@@ -4863,6 +4919,7 @@ static void dp_soc_detach(struct cdp_soc_t *txrx_soc)
	dp_hw_link_desc_pool_banks_free(soc, WLAN_INVALID_PDEV_ID);
	wlan_cfg_soc_detach(soc->wlan_cfg_ctx);
	dp_soc_tx_hw_desc_history_detach(soc);
	dp_soc_tx_history_detach(soc);
	dp_soc_rx_history_detach(soc);
	if (soc->mon_vdev_timer_state & MON_VDEV_TIMER_INIT) {
		qdf_timer_free(&soc->mon_vdev_timer);
@@ -12156,6 +12213,7 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc,

	dp_soc_tx_hw_desc_history_attach(soc);
	dp_soc_rx_history_attach(soc);
	dp_soc_tx_history_attach(soc);
	wlan_set_srng_cfg(&soc->wlan_srng_cfg);
	soc->wlan_cfg_ctx = wlan_cfg_soc_attach(soc->ctrl_psoc);
	if (!soc->wlan_cfg_ctx) {
+144 −0
Original line number Diff line number Diff line
@@ -189,6 +189,124 @@ dp_tx_outstanding_dec(struct dp_pdev *pdev)
}
#endif //QCA_TX_LIMIT_CHECK

#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY
static inline enum dp_tx_event_type dp_tx_get_event_type(uint32_t flags)
{
	enum dp_tx_event_type type;

	if (flags & DP_TX_DESC_FLAG_FLUSH)
		type = DP_TX_DESC_FLUSH;
	else if (flags & DP_TX_DESC_FLAG_TX_COMP_ERR)
		type = DP_TX_COMP_UNMAP_ERR;
	else if (flags & DP_TX_DESC_FLAG_COMPLETED_TX)
		type = DP_TX_COMP_UNMAP;
	else
		type = DP_TX_DESC_UNMAP;

	return type;
}

static inline void
dp_tx_desc_history_add(struct dp_soc *soc, dma_addr_t paddr,
		       qdf_nbuf_t skb, uint32_t sw_cookie,
		       enum dp_tx_event_type type)
{
	struct dp_tx_desc_event *entry;
	uint32_t idx;

	if (qdf_unlikely(!soc->tx_tcl_history || !soc->tx_comp_history))
		return;

	switch (type) {
	case DP_TX_COMP_UNMAP:
	case DP_TX_COMP_UNMAP_ERR:
	case DP_TX_COMP_MSDU_EXT:
		idx = dp_history_get_next_index(&soc->tx_comp_history->index,
						DP_TX_COMP_HISTORY_SIZE);
		entry = &soc->tx_comp_history->entry[idx];
		break;
	case DP_TX_DESC_MAP:
	case DP_TX_DESC_UNMAP:
	case DP_TX_DESC_COOKIE:
	case DP_TX_DESC_FLUSH:
		idx = dp_history_get_next_index(&soc->tx_tcl_history->index,
						DP_TX_TCL_HISTORY_SIZE);
		entry = &soc->tx_tcl_history->entry[idx];
		break;
	default:
		dp_info_rl("Invalid dp_tx_event_type: %d", type);
		return;
	}

	entry->skb = skb;
	entry->paddr = paddr;
	entry->sw_cookie = sw_cookie;
	entry->type = type;
	entry->ts = qdf_get_log_timestamp();
}

static inline void
dp_tx_tso_seg_history_add(struct dp_soc *soc,
			  struct qdf_tso_seg_elem_t *tso_seg,
			  qdf_nbuf_t skb, uint32_t sw_cookie,
			  enum dp_tx_event_type type)
{
	int i;

	for (i = 1; i < tso_seg->seg.num_frags; i++) {
		dp_tx_desc_history_add(soc, tso_seg->seg.tso_frags[i].paddr,
				       skb, sw_cookie, type);
	}

	if (!tso_seg->next)
		dp_tx_desc_history_add(soc, tso_seg->seg.tso_frags[0].paddr,
				       skb, 0xFFFFFFFF, type);
}

static inline void
dp_tx_tso_history_add(struct dp_soc *soc, struct qdf_tso_info_t tso_info,
		      qdf_nbuf_t skb, uint32_t sw_cookie,
		      enum dp_tx_event_type type)
{
	struct qdf_tso_seg_elem_t *curr_seg = tso_info.tso_seg_list;
	uint32_t num_segs = tso_info.num_segs;

	while (num_segs) {
		dp_tx_tso_seg_history_add(soc, curr_seg, skb, sw_cookie, type);
		curr_seg = curr_seg->next;
		num_segs--;
	}
}

#else
static inline enum dp_tx_event_type dp_tx_get_event_type(uint32_t flags)
{
	return DP_TX_DESC_INVAL_EVT;
}

static inline void
dp_tx_desc_history_add(struct dp_soc *soc, dma_addr_t paddr,
		       qdf_nbuf_t skb, uint32_t sw_cookie,
		       enum dp_tx_event_type type)
{
}

static inline void
dp_tx_tso_seg_history_add(struct dp_soc *soc,
			  struct qdf_tso_seg_elem_t *tso_seg,
			  qdf_nbuf_t skb, uint32_t sw_cookie,
			  enum dp_tx_event_type type)
{
}

static inline void
dp_tx_tso_history_add(struct dp_soc *soc, struct qdf_tso_info_t tso_info,
		      qdf_nbuf_t skb, uint32_t sw_cookie,
		      enum dp_tx_event_type type)
{
}
#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */

#if defined(FEATURE_TSO)
/**
 * dp_tx_tso_unmap_segment() - Unmap TSO segment
@@ -666,6 +784,8 @@ static QDF_STATUS dp_tx_prepare_tso(struct dp_vdev *vdev,

		return QDF_STATUS_E_INVAL;
	}
	dp_tx_tso_history_add(soc, msdu_info->u.tso_info,
			      msdu, 0, DP_TX_DESC_MAP);

	tso_info->curr_seg = tso_info->tso_seg_list;

@@ -1060,6 +1180,8 @@ static struct dp_tx_desc_s *dp_tx_prepare_desc(struct dp_vdev *vdev,
		DP_STATS_INC(vdev, tx_i.dropped.desc_na.num, 1);
		return NULL;
	}
	dp_tx_tso_seg_history_add(soc, msdu_info->u.tso_info.curr_seg,
				  nbuf, tx_desc->id, DP_TX_DESC_COOKIE);

	dp_tx_outstanding_inc(pdev);

@@ -1505,6 +1627,8 @@ dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
					tx_desc->pkt_offset;
		type = HAL_TX_BUF_TYPE_BUFFER;
		tx_desc->dma_addr = qdf_nbuf_mapped_paddr_get(tx_desc->nbuf);
		dp_tx_desc_history_add(soc, tx_desc->dma_addr, tx_desc->nbuf,
				       tx_desc->id, DP_TX_DESC_MAP);
	}

	qdf_assert_always(tx_desc->dma_addr);
@@ -2156,6 +2280,8 @@ dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
	if (status != QDF_STATUS_SUCCESS) {
		dp_err_rl("Tx_hw_enqueue Fail tx_desc %pK queue %d",
			  tx_desc, tx_q->ring_id);
		dp_tx_desc_history_add(soc, tx_desc->dma_addr, nbuf,
				       tx_desc->id, DP_TX_DESC_UNMAP);
		qdf_nbuf_unmap_nbytes_single(vdev->osdev, nbuf,
					     QDF_DMA_TO_DEVICE,
					     nbuf->len);
@@ -2187,6 +2313,7 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc,
				       struct dp_tx_desc_s *desc)
{
	qdf_nbuf_t nbuf = desc->nbuf;
	enum dp_tx_event_type type = dp_tx_get_event_type(desc->flags);

	/* nbuf already freed in vdev detach path */
	if (!nbuf)
@@ -2201,6 +2328,10 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc,
		/* TSO free */
		if (hal_tx_ext_desc_get_tso_enable(
					desc->msdu_ext_desc->vaddr)) {
			dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf,
					       desc->id, DP_TX_COMP_MSDU_EXT);
			dp_tx_tso_seg_history_add(soc, desc->tso_desc,
						  desc->nbuf, desc->id, type);
			/* unmap eash TSO seg before free the nbuf */
			dp_tx_tso_unmap_segment(soc, desc->tso_desc,
						desc->tso_num_desc);
@@ -2209,6 +2340,7 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc,
		}
	}

	dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf, desc->id, type);
	qdf_nbuf_unmap_nbytes_single(soc->osdev, nbuf,
				     QDF_DMA_TO_DEVICE, nbuf->len);

@@ -2305,6 +2437,10 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
			}

			if (msdu_info->frm_type == dp_tx_frm_tso) {
				dp_tx_tso_seg_history_add(
						soc,
						msdu_info->u.tso_info.curr_seg,
						nbuf, 0, DP_TX_DESC_UNMAP);
				dp_tx_tso_unmap_segment(soc,
							msdu_info->u.tso_info.
							curr_seg,
@@ -4135,6 +4271,7 @@ dp_tx_comp_process_desc(struct dp_soc *soc,
			struct dp_peer *peer)
{
	uint64_t time_latency = 0;

	/*
	 * m_copy/tx_capture modes are not supported for
	 * scatter gather packets
@@ -4170,6 +4307,7 @@ dp_tx_comp_process_desc(struct dp_soc *soc,
		}
	}

	desc->flags |= DP_TX_DESC_FLAG_COMPLETED_TX;
	dp_tx_comp_free_buf(soc, desc);
}

@@ -4396,6 +4534,8 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc,
			 * performance impact so avoided the wrapper call here
			 */
			next = desc->next;
			dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf,
					       desc->id, DP_TX_COMP_UNMAP);
			qdf_mem_unmap_nbytes_single(soc->osdev,
						    desc->dma_addr,
						    QDF_DMA_TO_DEVICE,
@@ -4465,6 +4605,7 @@ void dp_tx_process_htt_completion(struct dp_tx_desc_s *tx_desc, uint8_t *status,

	if (qdf_unlikely(tx_desc->pdev->is_pdev_down)) {
		dp_info_rl("pdev in down state %d", tx_desc->id);
		tx_desc->flags |= DP_TX_DESC_FLAG_TX_COMP_ERR;
		dp_tx_comp_free_buf(soc, tx_desc);
		dp_tx_desc_release(tx_desc, tx_desc->pool_id);
		return;
@@ -4730,6 +4871,7 @@ uint32_t dp_tx_comp_handler(struct dp_intr *int_ctx, struct dp_soc *soc,
			if (qdf_unlikely(tx_desc->pdev->is_pdev_down)) {
				dp_info_rl("pdev in down state %d", tx_desc_id);

				tx_desc->flags |= DP_TX_DESC_FLAG_TX_COMP_ERR;
				dp_tx_comp_free_buf(soc, tx_desc);
				dp_tx_desc_release(tx_desc, tx_desc->pool_id);
				goto next_desc;
@@ -5029,6 +5171,7 @@ void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev,
				 * in this TX desc.
				 */
				if (force_free) {
					tx_desc->flags |= DP_TX_DESC_FLAG_FLUSH;
					dp_tx_comp_free_buf(soc, tx_desc);
					dp_tx_desc_release(tx_desc, i);
				} else {
@@ -5092,6 +5235,7 @@ void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev,

			if (dp_is_tx_desc_flush_match(pdev, vdev, tx_desc)) {
				if (force_free) {
					tx_desc->flags |= DP_TX_DESC_FLAG_FLUSH;
					dp_tx_comp_free_buf(soc, tx_desc);
					dp_tx_desc_release(tx_desc, i);
				} else {
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@
#define DP_TX_DESC_FLAG_TDLS_FRAME	0x100
#define DP_TX_DESC_FLAG_ALLOCATED	0x200
#define DP_TX_DESC_FLAG_MESH_MODE	0x400
#define DP_TX_DESC_FLAG_TX_COMP_ERR	0x1000
#define DP_TX_DESC_FLAG_FLUSH		0x2000

#define DP_TX_EXT_DESC_FLAG_METADATA_VALID 0x1

+42 −0
Original line number Diff line number Diff line
@@ -385,6 +385,8 @@ enum dp_ctxt_type {
	DP_RX_RING_HIST_TYPE,
	DP_RX_ERR_RING_HIST_TYPE,
	DP_RX_REINJECT_RING_HIST_TYPE,
	DP_TX_TCL_HIST_TYPE,
	DP_TX_COMP_HIST_TYPE,
	DP_FISA_RX_FT_TYPE,
	DP_RX_REFILL_RING_HIST_TYPE,
	DP_TX_HW_DESC_HIST_TYPE,
@@ -1241,6 +1243,41 @@ struct dp_rx_refill_history {

#endif

enum dp_tx_event_type {
	DP_TX_DESC_INVAL_EVT = 0,
	DP_TX_DESC_MAP,
	DP_TX_DESC_COOKIE,
	DP_TX_DESC_FLUSH,
	DP_TX_DESC_UNMAP,
	DP_TX_COMP_UNMAP,
	DP_TX_COMP_UNMAP_ERR,
	DP_TX_COMP_MSDU_EXT,
};

#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY
/* Size must be in 2 power, for bitwise index rotation */
#define DP_TX_TCL_HISTORY_SIZE 0x4000
#define DP_TX_COMP_HISTORY_SIZE 0x4000

struct dp_tx_desc_event {
	qdf_nbuf_t skb;
	dma_addr_t paddr;
	uint32_t sw_cookie;
	enum dp_tx_event_type type;
	uint64_t ts;
};

struct dp_tx_tcl_history {
	qdf_atomic_t index;
	struct dp_tx_desc_event entry[DP_TX_TCL_HISTORY_SIZE];
};

struct dp_tx_comp_history {
	qdf_atomic_t index;
	struct dp_tx_desc_event entry[DP_TX_COMP_HISTORY_SIZE];
};
#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */

/* structure to record recent operation related variable */
struct dp_last_op_info {
	/* last link desc buf info through WBM release ring */
@@ -1627,6 +1664,11 @@ struct dp_soc {
	struct dp_rx_reinject_history *rx_reinject_ring_history;
#endif

#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY
	struct dp_tx_tcl_history *tx_tcl_history;
	struct dp_tx_comp_history *tx_comp_history;
#endif

	qdf_spinlock_t ast_lock;
	/*Timer for AST entry ageout maintainance */
	qdf_timer_t ast_aging_timer;