فهرست منبع

qcacld-3.0: Change HDD IPA to comply with the refactored SKB CB

This change refactors IPA private data stored in skb control block,
which size is reduced to 32 bits.
Owner id is changed to 1 bit, to flag if the owner is IPA.
Callback function pointer is removed by adding the callback into cdf.
Skb control block priv data is reduced to 16 bits by storing the index
to the Tx descriptor list added in HDD.

Change-Id: I0eec0636794da3b4729b8be825afe6a1275915a4
CRs-Fixed: 982728
Yun Park 8 سال پیش
والد
کامیت
52b2b991c7
1فایلهای تغییر یافته به همراه141 افزوده شده و 83 حذف شده
  1. 141 83
      core/hdd/src/wlan_hdd_ipa.c

+ 141 - 83
core/hdd/src/wlan_hdd_ipa.c

@@ -278,8 +278,9 @@ struct hdd_ipa_stats {
 	uint64_t num_rx_ipa_write_done;
 	uint64_t num_max_ipa_tx_mul;
 	uint64_t num_rx_ipa_hw_maxed_out;
-	uint64_t max_pend_q_cnt;
 
+	uint64_t num_tx_desc_q_cnt;
+	uint64_t num_tx_desc_error;
 	uint64_t num_tx_comp_cnt;
 	uint64_t num_tx_queued;
 	uint64_t num_tx_dequeued;
@@ -404,6 +405,20 @@ struct ipa_uc_quota_ind {
 };
 #endif
 
+/**
+ * struct hdd_ipa_tx_desc
+ * @link: link to list head
+ * @priv: pointer to priv list entry
+ * @id: Tx desc idex
+ * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor
+ */
+struct hdd_ipa_tx_desc {
+	struct list_head link;
+	void *priv;
+	uint32_t id;
+	struct ipa_rx_data *ipa_tx_desc_ptr;
+};
+
 struct hdd_ipa_priv {
 	struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE];
 	struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE];
@@ -429,14 +444,11 @@ struct hdd_ipa_priv {
 	qdf_spinlock_t pm_lock;
 	bool suspended;
 
-	uint32_t pending_hw_desc_cnt;
-	uint32_t hw_desc_cnt;
-	spinlock_t q_lock;
-	uint32_t freeq_cnt;
-	struct list_head free_desc_head;
+	qdf_spinlock_t q_lock;
 
-	uint32_t pend_q_cnt;
 	struct list_head pend_desc_head;
+	struct hdd_ipa_tx_desc *tx_desc_list;
+	struct list_head free_tx_desc_head;
 
 	hdd_context_t *hdd_ctx;
 
@@ -494,31 +506,6 @@ struct hdd_ipa_priv {
 #endif
 };
 
-/**
- * FIXME: The following conversion routines are just stubs.
- *        They will be implemented fully by another update.
- *        The stubs will let the compile go ahead, and functionality
- *        is broken.
- * This should be OK and IPA is not enabled yet
- */
-static void *wlan_hdd_stub_priv_to_addr(uint32_t priv)
-{
-	void    *vaddr;
-	uint32_t ipa_priv = priv;
-
-	vaddr = &ipa_priv; /* just to use the var */
-	vaddr = NULL;
-	return vaddr;
-}
-
-static uint32_t wlan_hdd_stub_addr_to_priv(void *ptr)
-{
-	uint32_t       ipa_priv = 0;
-
-	BUG_ON(ptr == NULL);
-	return ipa_priv;
-}
-
 #define HDD_IPA_WLAN_FRAG_HEADER        sizeof(struct frag_header)
 #define HDD_IPA_WLAN_IPA_HEADER         sizeof(struct ipa_header)
 #define HDD_IPA_WLAN_CLD_HDR_LEN        sizeof(struct hdd_ipa_cld_hdr)
@@ -1212,14 +1199,7 @@ static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
 		&hdd_ipa->pm_work,
 		&hdd_ipa->pm_lock,
 		hdd_ipa->suspended);
-	hdd_info("\npending_hw_desc_cnt: %d\n"
-		"hw_desc_cnt: %d\n"
-		"q_lock: %p\n"
-		"freeq_cnt: %d\n"
-		"free_desc_head----\n"
-		"\tnext: %p\n"
-		"\tprev: %p\n"
-		"pend_q_cnt: %d\n"
+	hdd_err("\nq_lock: %p\n"
 		"pend_desc_head----\n"
 		"\tnext: %p\n"
 		"\tprev: %p\n"
@@ -1232,13 +1212,7 @@ static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa)
 		"activated_fw_pipe: %d\n"
 		"sap_num_connected_sta: %d\n"
 		"sta_connected: %d\n",
-		hdd_ipa->pending_hw_desc_cnt,
-		hdd_ipa->hw_desc_cnt,
 		&hdd_ipa->q_lock,
-		hdd_ipa->freeq_cnt,
-		hdd_ipa->free_desc_head.next,
-		hdd_ipa->free_desc_head.prev,
-		hdd_ipa->pend_q_cnt,
 		hdd_ipa->pend_desc_head.next,
 		hdd_ipa->pend_desc_head.prev,
 		hdd_ipa->hdd_ctx,
@@ -3701,14 +3675,6 @@ static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa)
 	if (atomic_read(&hdd_ipa->tx_ref_cnt))
 		return -EAGAIN;
 
-	spin_lock_bh(&hdd_ipa->q_lock);
-	if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) &&
-		(hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) {
-		spin_unlock_bh(&hdd_ipa->q_lock);
-		return -EAGAIN;
-	}
-	spin_unlock_bh(&hdd_ipa->q_lock);
-
 	qdf_spin_lock_bh(&hdd_ipa->pm_lock);
 
 	if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) {
@@ -4383,12 +4349,31 @@ static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt,
 void hdd_ipa_nbuf_cb(qdf_nbuf_t skb)
 {
 	struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
+	struct ipa_rx_data *ipa_tx_desc;
+	struct hdd_ipa_tx_desc *tx_desc;
+	uint16_t id;
+
+	HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%x", QDF_NBUF_CB_TX_IPA_PRIV(skb));
+
+	if (!qdf_nbuf_ipa_owned_get(skb)) {
+		dev_kfree_skb_any(skb);
+		return;
+	}
 
-	HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "%p",
-		wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
-	/* FIXME: This is broken; PRIV_DATA is now 31 bits */
-	ipa_free_skb((struct ipa_rx_data *)
-		wlan_hdd_stub_priv_to_addr(QDF_NBUF_CB_TX_IPA_PRIV(skb)));
+	/* Get Tx desc pointer from SKB CB */
+	id = QDF_NBUF_CB_TX_IPA_PRIV(skb);
+	tx_desc = hdd_ipa->tx_desc_list + id;
+	ipa_tx_desc = tx_desc->ipa_tx_desc_ptr;
+
+	/* Return Tx Desc to IPA */
+	ipa_free_skb(ipa_tx_desc);
+
+	/* Return to free tx desc list */
+	qdf_spin_lock_bh(&hdd_ipa->q_lock);
+	tx_desc->ipa_tx_desc_ptr = NULL;
+	list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head);
+	hdd_ipa->stats.num_tx_desc_q_cnt--;
+	qdf_spin_unlock_bh(&hdd_ipa->q_lock);
 
 	hdd_ipa->stats.num_tx_comp_cnt++;
 
@@ -4411,6 +4396,7 @@ static void hdd_ipa_send_pkt_to_tl(
 	struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa;
 	hdd_adapter_t *adapter = NULL;
 	qdf_nbuf_t skb;
+	struct hdd_ipa_tx_desc *tx_desc;
 
 	qdf_spin_lock_bh(&iface_context->interface_lock);
 	adapter = iface_context->adapter;
@@ -4442,10 +4428,9 @@ static void hdd_ipa_send_pkt_to_tl(
 	skb = ipa_tx_desc->skb;
 
 	qdf_mem_set(skb->cb, sizeof(skb->cb), 0);
+
+	/* Store IPA Tx buffer ownership into SKB CB */
 	qdf_nbuf_ipa_owned_set(skb);
-	/* FIXME: This is broken. No such field in cb any more:
-	 * NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb;
-	 */
 	if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
 		qdf_nbuf_mapped_paddr_set(skb,
 					  ipa_tx_desc->dma_addr
@@ -4456,8 +4441,25 @@ static void hdd_ipa_send_pkt_to_tl(
 	} else
 		qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr);
 
-	/* FIXME: This is broken: priv_data is 31 bits */
-	qdf_nbuf_ipa_priv_set(skb, wlan_hdd_stub_addr_to_priv(ipa_tx_desc));
+	qdf_spin_lock_bh(&hdd_ipa->q_lock);
+	/* get free Tx desc and assign ipa_tx_desc pointer */
+	if (!list_empty(&hdd_ipa->free_tx_desc_head)) {
+		tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head,
+					   struct hdd_ipa_tx_desc, link);
+		list_del(&tx_desc->link);
+		tx_desc->ipa_tx_desc_ptr = ipa_tx_desc;
+		hdd_ipa->stats.num_tx_desc_q_cnt++;
+		qdf_spin_unlock_bh(&hdd_ipa->q_lock);
+		/* Store Tx Desc index into SKB CB */
+		QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id;
+	} else {
+		hdd_ipa->stats.num_tx_desc_error++;
+		qdf_spin_unlock_bh(&hdd_ipa->q_lock);
+		HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!");
+		ipa_free_skb(ipa_tx_desc);
+		hdd_ipa_rm_try_release(hdd_ipa);
+		return;
+	}
 
 	adapter->stats.tx_bytes += ipa_tx_desc->skb->len;
 
@@ -4475,7 +4477,6 @@ static void hdd_ipa_send_pkt_to_tl(
 	atomic_inc(&hdd_ipa->tx_ref_cnt);
 
 	iface_context->stats.num_tx++;
-
 }
 
 /**
@@ -4752,6 +4753,49 @@ int hdd_ipa_resume(hdd_context_t *hdd_ctx)
 	return ret;
 }
 
+/**
+ * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
+ * @hdd_ipa: Global HDD IPA context
+ *
+ * Return: 0 on success, negative errno on error
+ */
+static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa)
+{
+	int i;
+	uint32_t max_desc_cnt;
+	struct hdd_ipa_tx_desc *tmp_desc;
+
+	max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
+
+	INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head);
+
+	tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc)*max_desc_cnt);
+
+	if (!tmp_desc) {
+		HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+			    "Free Tx descriptor allocation failed");
+		return -ENOMEM;
+	}
+
+	hdd_ipa->tx_desc_list = tmp_desc;
+
+	qdf_spin_lock_bh(&hdd_ipa->q_lock);
+	for (i = 0; i < max_desc_cnt; i++) {
+		tmp_desc->id = i;
+		tmp_desc->ipa_tx_desc_ptr = NULL;
+		list_add_tail(&tmp_desc->link,
+			      &hdd_ipa->free_tx_desc_head);
+		tmp_desc++;
+	}
+
+	hdd_ipa->stats.num_tx_desc_q_cnt = 0;
+	hdd_ipa->stats.num_tx_desc_error = 0;
+
+	qdf_spin_unlock_bh(&hdd_ipa->q_lock);
+
+	return 0;
+}
+
 /**
  * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes
  * @hdd_ipa: Global HDD IPA context
@@ -4844,6 +4888,11 @@ static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
 		hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1;
 	}
 
+       /* Allocate free Tx desc list */
+	ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa);
+	if (ret)
+		goto setup_sys_pipe_fail;
+
 	return ret;
 
 setup_sys_pipe_fail:
@@ -4866,6 +4915,10 @@ setup_sys_pipe_fail:
 static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
 {
 	int ret = 0, i;
+	uint32_t max_desc_cnt;
+	struct hdd_ipa_tx_desc *tmp_desc;
+	struct ipa_rx_data *ipa_tx_desc;
+
 	for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) {
 		if (hdd_ipa->sys_pipe[i].conn_hdl_valid) {
 			ret =
@@ -4878,6 +4931,24 @@ static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa)
 			hdd_ipa->sys_pipe[i].conn_hdl_valid = 0;
 		}
 	}
+
+	if (hdd_ipa->tx_desc_list) {
+		max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount;
+
+		qdf_spin_lock_bh(&hdd_ipa->q_lock);
+		for (i = 0; i < max_desc_cnt; i++) {
+			tmp_desc = hdd_ipa->tx_desc_list + i;
+			ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr;
+			if (ipa_tx_desc)
+				ipa_free_skb(ipa_tx_desc);
+		}
+		tmp_desc = hdd_ipa->tx_desc_list;
+		hdd_ipa->tx_desc_list = NULL;
+		hdd_ipa->stats.num_tx_desc_q_cnt = 0;
+		hdd_ipa->stats.num_tx_desc_error = 0;
+		qdf_spin_unlock_bh(&hdd_ipa->q_lock);
+		qdf_mem_free(tmp_desc);
+	}
 }
 
 /**
@@ -4980,6 +5051,9 @@ static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa,
 	/* Call the ipa api to register interface */
 	ret = ipa_register_intf(ifname, &tx_intf, &rx_intf);
 
+	/* Register IPA Tx desc free callback */
+	qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb);
+
 register_interface_fail:
 	qdf_mem_free(tx_prop);
 	qdf_mem_free(rx_prop);
@@ -6032,6 +6106,7 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx)
 
 	INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
 	qdf_spinlock_create(&hdd_ipa->pm_lock);
+	qdf_spinlock_create(&hdd_ipa->q_lock);
 	qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head);
 
 	ret = hdd_ipa_setup_rm(hdd_ipa);
@@ -6165,6 +6240,7 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
 	qdf_spin_unlock_bh(&hdd_ipa->pm_lock);
 
 	qdf_spinlock_destroy(&hdd_ipa->pm_lock);
+	qdf_spinlock_destroy(&hdd_ipa->q_lock);
 
 	/* destory the interface lock */
 	for (i = 0; i < HDD_IPA_MAX_IFACE; i++) {
@@ -6172,24 +6248,6 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx)
 		qdf_spinlock_destroy(&iface_context->interface_lock);
 	}
 
-	/* This should never hit but still make sure that there are no pending
-	 * descriptor in IPA hardware
-	 */
-	if (hdd_ipa->pending_hw_desc_cnt != 0) {
-		HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
-			    "IPA Pending write done: %d Waiting!",
-			    hdd_ipa->pending_hw_desc_cnt);
-
-		for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) {
-			usleep_range(100, 100);
-		}
-
-		HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
-			    "IPA Pending write done: desc: %d %s(%d)!",
-			    hdd_ipa->pending_hw_desc_cnt,
-			    hdd_ipa->pending_hw_desc_cnt == 0 ? "completed"
-			    : "leak", i);
-	}
 	if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
 		if (ipa_uc_dereg_rdyCB())
 			HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,