Browse Source

qca-wifi: API support for peer MultiQueue support

Lithium HW can parse each MSDU when packets are enqueued to transmit
classifier and each MSDU can get enqueued to different MSDU-Queue.
By default, there are 2 queues per TID – UDP and NON-UDP. Based on
the flow parsing, packets will be queued to either of them.
Enterprise customers uses RAW mode frames which transmit classifier
would not be able to identify L4 protocol for  UDP or NON-UDP queue
for encrypted frames.
Customer can also have different application based packets which needs
to be enqueued to differently prioritized queues. They can choose to
tag each MSDU based on application DPI and derive the flow priority
as below –
•	UDP
•	NON-UDP
•	HI-PRIO
•	LOW-PRIO
Customer needs API support from host which will provide an ast-index
based on a particular flow id given peer mac address. Based on the mac
address, host will find the associated peer and return the ast_index &
cache set number corresponding to the flow id from peer flow based ast
entry table. Customer will then program this ast-index and ast override
in transmit classifier CMD ring to enqueue MSDU to a specific
flow-queuein TQM.
Host API:
Input parameter – uint8_t *macaddress,uint8_t flowid,uint8_t tid
Output – uint16_t ast_index

Change-Id: I62b2308510ee7a43b153e125dc3bee6abbad0848
Mainak Sen 5 years ago
parent
commit
e1349928dd
2 changed files with 272 additions and 1 deletions
  1. 267 0
      dp/wifi3.0/dp_txrx_wds.c
  2. 5 1
      dp/wifi3.0/dp_txrx_wds.h

+ 267 - 0
dp/wifi3.0/dp_txrx_wds.c

@@ -32,6 +32,13 @@
 #define DP_VLAN_TAGGED_MULTICAST 1
 #define DP_VLAN_TAGGED_UNICAST 2
 #define DP_MAX_VLAN_IDS 4096
+#define DP_INVALID_AST_IDX 0xffff
+#define DP_INVALID_FLOW_PRIORITY 0xff
+#define DP_PEER_AST0_FLOW_MASK 0x4
+#define DP_PEER_AST1_FLOW_MASK 0x8
+#define DP_PEER_AST2_FLOW_MASK 0x1
+#define DP_PEER_AST3_FLOW_MASK 0x2
+#define DP_MAX_AST_INDEX_PER_PEER 4
 
 static void dp_ast_aging_timer_fn(void *soc_hdl)
 {
@@ -807,3 +814,263 @@ void dp_peer_multipass_list_init(struct dp_vdev *vdev)
 	qdf_spinlock_create(&vdev->mpass_peer_mutex);
 }
 #endif
+
+#ifdef QCA_PEER_MULTIQ_SUPPORT
+
+/**
+ * dp_peer_reset_flowq_map() - reset peer flowq map table
+ * @peer - dp peer handle
+ *
+ * Return: none
+ */
+void dp_peer_reset_flowq_map(struct dp_peer *peer)
+{
+	int i = 0;
+
+	if (!peer)
+		return;
+
+	for (i = 0; i < DP_PEER_AST_FLOWQ_MAX; i++) {
+		peer->peer_ast_flowq_idx[i].is_valid = false;
+		peer->peer_ast_flowq_idx[i].valid_tid_mask = false;
+		peer->peer_ast_flowq_idx[i].ast_idx = DP_INVALID_AST_IDX;
+		peer->peer_ast_flowq_idx[i].flowQ = DP_INVALID_FLOW_PRIORITY;
+	}
+}
+
+/**
+ * dp_peer_get_flowid_from_flowmask() - get flow id from flow mask
+ * @peer - dp peer handle
+ * @mask - flow mask
+ *
+ * Return: flow id
+ */
+static int dp_peer_get_flowid_from_flowmask(struct dp_peer *peer,
+		uint8_t mask)
+{
+	if (!peer) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+				"%s: Invalid peer\n", __func__);
+		return -1;
+	}
+
+	if (mask & DP_PEER_AST0_FLOW_MASK)
+		return DP_PEER_AST_FLOWQ_UDP;
+	else if (mask & DP_PEER_AST1_FLOW_MASK)
+		return DP_PEER_AST_FLOWQ_NON_UDP;
+	else if (mask & DP_PEER_AST2_FLOW_MASK)
+		return DP_PEER_AST_FLOWQ_HI_PRIO;
+	else if (mask & DP_PEER_AST3_FLOW_MASK)
+		return DP_PEER_AST_FLOWQ_LOW_PRIO;
+
+	return DP_PEER_AST_FLOWQ_MAX;
+}
+
+/**
+ * dp_peer_get_ast_valid() - get ast index valid from mask
+ * @mask - mask for ast valid bits
+ * @index - index for an ast
+ *
+ * Return - 1 if ast index is valid from mask else 0
+ */
+static inline bool dp_peer_get_ast_valid(uint8_t mask, uint16_t index)
+{
+	if (index == 0)
+		return 1;
+	return ((mask) & (1 << ((index) - 1)));
+}
+
+/**
+ * dp_peer_ast_index_flow_queue_map_create() - create ast index flow queue map
+ * @soc - genereic soc handle
+ * @is_wds - flag to indicate if peer is wds
+ * @peer_id - peer_id from htt peer map message
+ * @peer_mac_addr - mac address of the peer
+ * @ast_info - ast flow override information from peer map
+ *
+ * Return: none
+ */
+void dp_peer_ast_index_flow_queue_map_create(void *soc_hdl,
+		bool is_wds, uint16_t peer_id, uint8_t *peer_mac_addr,
+		struct dp_ast_flow_override_info *ast_info)
+{
+	struct dp_soc *soc = (struct dp_soc *)soc_hdl;
+	struct dp_peer *peer = NULL;
+	uint8_t i;
+
+	/*
+	 * Ast flow override feature is supported
+	 * only for connected client
+	 */
+	if (is_wds)
+		return;
+
+	peer = dp_peer_find_by_id(soc, peer_id);
+	if (!peer) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+				"%s: Invalid peer\n", __func__);
+		return;
+	}
+
+	/* Valid only in AP mode */
+	if (peer->vdev->opmode != wlan_op_mode_ap) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"%s: Peer ast flow map not in STA mode\n", __func__);
+		/* Release peer reference */
+		dp_peer_unref_del_find_by_id(peer);
+		return;
+	}
+
+	/* Making sure the peer is for this mac address */
+	if (!qdf_is_macaddr_equal((struct qdf_mac_addr *)peer_mac_addr,
+				(struct qdf_mac_addr *)peer->mac_addr.raw)) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+				"%s: Peer mac address mismatch\n", __func__);
+		dp_peer_unref_del_find_by_id(peer);
+		return;
+	}
+
+	/* Ast entry flow mapping not valid for self peer map */
+	if (qdf_is_macaddr_equal((struct qdf_mac_addr *)peer_mac_addr,
+				(struct qdf_mac_addr *)peer->vdev->mac_addr.raw)) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+				"%s: Ast flow mapping not valid for self peer \n", __func__);
+		dp_peer_unref_del_find_by_id(peer);
+		return;
+	}
+
+	/* Fill up ast index <---> flow id mapping table for this peer */
+	for (i = 0; i < DP_MAX_AST_INDEX_PER_PEER; i++) {
+
+		/* Check if this ast index is valid */
+		peer->peer_ast_flowq_idx[i].is_valid =
+			dp_peer_get_ast_valid(ast_info->ast_valid_mask, i);
+		if (!peer->peer_ast_flowq_idx[i].is_valid)
+			continue;
+
+		/* Get the flow queue id which is mapped to this ast index */
+		peer->peer_ast_flowq_idx[i].flowQ =
+			dp_peer_get_flowid_from_flowmask(peer,
+					ast_info->ast_flow_mask[i]);
+		/*
+		 * Update tid valid mask only if flow id HIGH or
+		 * Low priority
+		 */
+		if (peer->peer_ast_flowq_idx[i].flowQ ==
+				DP_PEER_AST_FLOWQ_HI_PRIO) {
+			peer->peer_ast_flowq_idx[i].valid_tid_mask =
+				ast_info->tid_valid_hi_pri_mask;
+		} else if (peer->peer_ast_flowq_idx[i].flowQ ==
+				DP_PEER_AST_FLOWQ_LOW_PRIO) {
+			peer->peer_ast_flowq_idx[i].valid_tid_mask =
+				ast_info->tid_valid_low_pri_mask;
+		}
+
+		/* Save the ast index for this entry */
+		peer->peer_ast_flowq_idx[i].ast_idx = ast_info->ast_idx[i];
+	}
+
+	if (soc->cdp_soc.ol_ops->peer_ast_flowid_map) {
+		soc->cdp_soc.ol_ops->peer_ast_flowid_map(
+				soc->ctrl_psoc, peer->peer_ids[0],
+				peer->vdev->vdev_id, peer_mac_addr);
+	}
+
+	/* Release peer reference */
+	dp_peer_unref_del_find_by_id(peer);
+}
+
+/**
+ * dp_peer_find_ast_index_by_flowq_id() - API to get ast idx for a given flowid
+ * @soc - soc handle
+ * @peer_mac_addr - mac address of the peer
+ * @flow_id - flow id to find ast index
+ *
+ * Return: ast index for a given flow id, -1 for fail cases
+ */
+int dp_peer_find_ast_index_by_flowq_id(struct cdp_soc_t *soc,
+		uint16_t vdev_id, uint8_t *peer_mac_addr,
+		uint8_t flow_id, uint8_t tid)
+{
+	struct dp_peer *peer = NULL;
+	uint8_t i;
+	uint16_t ast_index;
+
+	if (flow_id >= DP_PEER_AST_FLOWQ_MAX) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"Invalid Flow ID %d\n", flow_id);
+		return -1;
+	}
+
+	peer = dp_peer_find_hash_find((struct dp_soc *)soc,
+				peer_mac_addr, 0, vdev_id);
+	if (!peer) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"%s: Invalid peer\n", __func__);
+		return -1;
+	}
+
+	 /*
+	  * Loop over the ast entry <----> flow-id mapping to find
+	  * which ast index entry has this flow queue id enabled.
+	  */
+	for (i = 0; i < DP_PEER_AST_FLOWQ_MAX; i++) {
+		if (peer->peer_ast_flowq_idx[i].flowQ == flow_id)
+			/*
+			 * Found the matching index for this flow id
+			 */
+			break;
+	}
+
+	/*
+	 * No match found for this flow id
+	 */
+	if (i == DP_PEER_AST_FLOWQ_MAX) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"%s: ast index not found for flow %d\n", __func__, flow_id);
+		dp_peer_unref_delete(peer);
+		return -1;
+	}
+
+	/* Check whether this ast entry is valid */
+	if (!peer->peer_ast_flowq_idx[i].is_valid) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"%s: ast index is invalid for flow %d\n", __func__, flow_id);
+		dp_peer_unref_delete(peer);
+		return -1;
+	}
+
+	if (flow_id == DP_PEER_AST_FLOWQ_HI_PRIO ||
+			flow_id == DP_PEER_AST_FLOWQ_LOW_PRIO) {
+		/*
+		 * check if this tid is valid for Hi
+		 * and Low priority flow id
+		 */
+		if ((peer->peer_ast_flowq_idx[i].valid_tid_mask
+					& (1 << tid))) {
+			/* Release peer reference */
+			ast_index = peer->peer_ast_flowq_idx[i].ast_idx;
+			dp_peer_unref_delete(peer);
+			return ast_index;
+		} else {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+					"%s: TID %d is not valid for flow %d\n",
+					__func__, tid, flow_id);
+			/*
+			 * TID is not valid for this flow
+			 * Return -1
+			 */
+			dp_peer_unref_delete(peer);
+			return -1;
+		}
+	}
+
+	/*
+	 * TID valid check not required for
+	 * UDP/NON UDP flow id
+	 */
+	ast_index = peer->peer_ast_flowq_idx[i].ast_idx;
+	dp_peer_unref_delete(peer);
+	return ast_index;
+}
+#endif

+ 5 - 1
dp/wifi3.0/dp_txrx_wds.h

@@ -26,7 +26,11 @@
 ((DP_WDS_AST_AGING_TIMER_DEFAULT_MS / DP_AST_AGING_TIMER_DEFAULT_MS) - 1)
 void dp_soc_wds_attach(struct dp_soc *soc);
 void dp_soc_wds_detach(struct dp_soc *soc);
-
+#ifdef QCA_PEER_MULTIQ_SUPPORT
+int dp_peer_find_ast_index_by_flowq_id(struct cdp_soc_t *soc,
+	       uint16_t vdev_id, uint8_t *peer_mac_addr,
+	       uint8_t flow_id, uint8_t tid);
+#endif
 void
 dp_rx_da_learn(struct dp_soc *soc,
 	       uint8_t *rx_tlv_hdr,