Ver Fonte

qcacmn: Add DSCP_TID changes for Lithium

Add command to set mapid for each VAP using:
iwpriv athX s_dscp_mapid  N

Add command to change tid values in PDEV maps using:
iwpriv wifiX s_dscp_tid_map <MAP_ID> <TOS> <TID>

Change-Id: I510a40e71ecec5c453dd2dff1b13fd5ebedbe98a
CRs-Fixed: 1108452
Ishank Jain há 8 anos atrás
pai
commit
949674c4cb

+ 35 - 0
dp/inc/cdp_txrx_cmn.h

@@ -400,4 +400,39 @@ cdp_get_peer_mac_addr_frm_id(ol_txrx_soc_handle soc, uint16_t peer_id,
 				peer_id, mac_addr);
 	return CDP_INVALID_VDEV_ID;
 }
+
+/**
+ * cdp_set_vdev_dscp_tid_map(): function to set DSCP-tid map in the vap
+ * @vdev: vdev handle
+ * @map_id: id of the tid map
+ *
+ * Return: void
+ */
+static inline void cdp_set_vdev_dscp_tid_map(ol_txrx_soc_handle soc,
+		struct cdp_vdev *vdev, uint8_t map_id)
+{
+	if (soc->ops->cmn_drv_ops->set_vdev_dscp_tid_map)
+		return soc->ops->cmn_drv_ops->set_vdev_dscp_tid_map(vdev,
+				map_id);
+	return;
+}
+
+/**
+ * cdp_set_pdev_dscp_tid_map(): function to change tid values in DSCP-tid map
+ * @pdev: pdev handle
+ * @map_id: id of the tid map
+ * @tos: index value in map that needs to be changed
+ * @tid: tid value passed by user
+ *
+ * Return: void
+ */
+static inline void cdp_set_pdev_dscp_tid_map(ol_txrx_soc_handle soc,
+		struct cdp_pdev *pdev, uint8_t map_id, uint8_t tos, uint8_t tid)
+{
+	if (soc->ops->cmn_drv_ops->set_pdev_dscp_tid_map) {
+		return soc->ops->cmn_drv_ops->set_pdev_dscp_tid_map(pdev,
+				map_id, tos, tid);
+	}
+	return;
+}
 #endif /* _CDP_TXRX_CMN_H_ */

+ 7 - 0
dp/inc/cdp_txrx_ops.h

@@ -186,6 +186,13 @@ struct cdp_cmn_ops {
 
 	uint8_t (*get_peer_mac_addr_frm_id)(struct cdp_soc_t *soc_handle,
 			uint16_t peer_id, uint8_t *mac_addr);
+
+	void (*set_vdev_dscp_tid_map)(struct cdp_vdev *vdev_handle,
+			uint8_t map_id);
+
+	void (*set_pdev_dscp_tid_map)(struct cdp_pdev *pdev, uint8_t map_id,
+			uint8_t tos, uint8_t tid);
+
 };
 
 struct cdp_ctrl_ops {

+ 88 - 0
dp/wifi3.0/dp_main.c

@@ -40,6 +40,31 @@
 #define DP_NSS_LENGTH (6*SS_COUNT)
 #define DP_RXDMA_ERR_LENGTH (6*MAX_RXDMA_ERRORS)
 #define DP_REO_ERR_LENGTH (6*REO_ERROR_TYPE_MAX)
+
+/**
+ * default_dscp_tid_map - Default DSCP-TID mapping
+ *
+ * DSCP        TID     AC
+ * 000000      0       WME_AC_BE
+ * 001000      1       WME_AC_BK
+ * 010000      1       WME_AC_BK
+ * 011000      0       WME_AC_BE
+ * 100000      5       WME_AC_VI
+ * 101000      5       WME_AC_VI
+ * 110000      6       WME_AC_VO
+ * 111000      6       WME_AC_VO
+ */
+static uint8_t default_dscp_tid_map[DSCP_TID_MAP_MAX] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	5, 5, 5, 5, 5, 5, 5, 5,
+	5, 5, 5, 5, 5, 5, 5, 5,
+	6, 6, 6, 6, 6, 6, 6, 6,
+	6, 6, 6, 6, 6, 6, 6, 6,
+};
+
 /**
  * dp_setup_srng - Internal function to setup SRNG rings used by data path
  */
@@ -987,6 +1012,28 @@ static int dp_rxdma_ring_setup(struct dp_soc *soc,
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+
+/**
+ * dp_dscp_tid_map_setup(): Initialize the dscp-tid maps
+ * @pdev - DP_PDEV handle
+ *
+ * Return: void
+ */
+static inline void
+dp_dscp_tid_map_setup(struct dp_pdev *pdev)
+{
+	uint8_t map_id;
+	for (map_id = 0; map_id < DP_MAX_TID_MAPS; map_id++) {
+		qdf_mem_copy(pdev->dscp_tid_map[map_id], default_dscp_tid_map,
+				sizeof(default_dscp_tid_map));
+	}
+	for (map_id = 0; map_id < HAL_MAX_HW_DSCP_TID_MAPS; map_id++) {
+		hal_tx_set_dscp_tid_map(pdev->soc->hal_soc,
+				pdev->dscp_tid_map[map_id],
+				map_id);
+	}
+}
+
 /*
 * dp_pdev_attach_wifi3() - attach txrx pdev
 * @osif_pdev: Opaque PDEV handle from OSIF/HDD
@@ -1119,6 +1166,7 @@ static struct cdp_pdev *dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc,
 	dp_local_peer_id_pool_init(pdev);
 #endif
 	dp_lro_hash_setup(soc);
+	dp_dscp_tid_map_setup(pdev);
 
 	return (struct cdp_pdev *)pdev;
 
@@ -1446,6 +1494,7 @@ static struct cdp_vdev *dp_vdev_attach_wifi3(struct cdp_pdev *txrx_pdev,
 
 	vdev->tx_encap_type = wlan_cfg_pkt_type(soc->wlan_cfg_ctx);
 	vdev->rx_decap_type = wlan_cfg_pkt_type(soc->wlan_cfg_ctx);
+	vdev->dscp_tid_map_id = 0;
 
 	/* TODO: Initialize default HTT meta data that will be used in
 	 * TCL descriptors for packets transmitted from this VDEV
@@ -2708,6 +2757,42 @@ dp_get_peer_stats(struct cdp_pdev *pdev_handle, char *mac_addr)
 		return;
 }
 
+/*
+ * dp_set_vdev_dscp_tid_map_wifi3(): Update Map ID selected for particular vdev
+ * @vdev_handle: DP_VDEV handle
+ * @map_id:ID of map that needs to be updated
+ *
+ * Return: void
+ */
+static void dp_set_vdev_dscp_tid_map_wifi3(struct cdp_vdev *vdev_handle,
+		uint8_t map_id)
+{
+	struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle;
+	vdev->dscp_tid_map_id = map_id;
+	return;
+}
+
+/**
+ * dp_set_pdev_dscp_tid_map_wifi3(): update dscp tid map in pdev
+ * @pdev: DP_PDEV handle
+ * @map_id: ID of map that needs to be updated
+ * @tos: index value in map
+ * @tid: tid value passed by the user
+ *
+ * Return: void
+ */
+static void dp_set_pdev_dscp_tid_map_wifi3(struct cdp_pdev *pdev_handle,
+		uint8_t map_id, uint8_t tos, uint8_t tid)
+{
+	uint8_t dscp;
+	struct dp_pdev *pdev = (struct dp_pdev *) pdev_handle;
+	dscp = (tos >> DP_IP_DSCP_SHIFT) & DP_IP_DSCP_MASK;
+	pdev->dscp_tid_map[map_id][dscp] = tid;
+	hal_tx_update_dscp_tid(pdev->soc->hal_soc, tid,
+			map_id, dscp);
+	return;
+}
+
 static struct cdp_cmn_ops dp_ops_cmn = {
 	.txrx_soc_attach_target = dp_soc_attach_target_wifi3,
 	.txrx_vdev_attach = dp_vdev_attach_wifi3,
@@ -2727,6 +2812,9 @@ static struct cdp_cmn_ops dp_ops_cmn = {
 	.addba_responsesetup = dp_addba_responsesetup_wifi3,
 	.delba_process = dp_delba_process_wifi3,
 	.get_peer_mac_addr_frm_id = dp_get_peer_mac_addr_frm_id,
+	/* TODO: get API's for dscp-tid need to be added*/
+	.set_vdev_dscp_tid_map = dp_set_vdev_dscp_tid_map_wifi3,
+	.set_pdev_dscp_tid_map = dp_set_pdev_dscp_tid_map_wifi3,
 	/* TODO: Add other functions */
 };
 

+ 1 - 1
dp/wifi3.0/dp_rx.c

@@ -739,7 +739,7 @@ done:
 			}
 		}
 
-		if (qdf_unlikely(vdev->rx_decap_type == htt_pkt_type_raw))
+		if (qdf_unlikely(vdev->rx_decap_type == htt_cmn_pkt_type_raw))
 			dp_rx_deliver_raw(vdev, deliver_list_head);
 		else if (qdf_likely(vdev->osif_rx) && deliver_list_head)
 			vdev->osif_rx(vdev->osif_vdev, deliver_list_head);

+ 116 - 35
dp/wifi3.0/dp_tx.c

@@ -48,30 +48,6 @@
 /* disable TQM_BYPASS */
 #define TQM_BYPASS_WAR 0
 
-/*
- * default_dscp_tid_map - Default DSCP-TID mapping
- *
- * DSCP        TID     AC
- * 000000      0       WME_AC_BE
- * 001000      1       WME_AC_BK
- * 010000      1       WME_AC_BK
- * 011000      0       WME_AC_BE
- * 100000      5       WME_AC_VI
- * 101000      5       WME_AC_VI
- * 110000      6       WME_AC_VO
- * 111000      6       WME_AC_VO
- */
-static uint8_t default_dscp_tid_map[64] = {
-	0, 0, 0, 0, 0, 0, 0, 0,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	5, 5, 5, 5, 5, 5, 5, 5,
-	5, 5, 5, 5, 5, 5, 5, 5,
-	6, 6, 6, 6, 6, 6, 6, 6,
-	6, 6, 6, 6, 6, 6, 6, 6,
-};
-
 /**
  * dp_tx_get_queue() - Returns Tx queue IDs to be used for this Tx frame
  * @vdev: DP Virtual device handle
@@ -669,6 +645,8 @@ static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
 	hal_tx_desc_set_buf_length(hal_tx_desc_cached, length);
 	hal_tx_desc_set_buf_offset(hal_tx_desc_cached, tx_desc->pkt_offset);
 	hal_tx_desc_set_encap_type(hal_tx_desc_cached, tx_desc->tx_encap_type);
+	hal_tx_desc_set_dscp_tid_table_id(hal_tx_desc_cached,
+			vdev->dscp_tid_map_id);
 
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
 			"%s length:%d , type = %d, dma_addr %llx, offset %d\n",
@@ -730,15 +708,122 @@ static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
  * Extract the DSCP or PCP information from frame and map into TID value.
  * Software based TID classification is required when more than 2 DSCP-TID
  * mapping tables are needed.
- * Hardware supports 2 DSCP-TID mapping tables.
+ * Hardware supports 2 DSCP-TID mapping tables
  *
- * Return:
+ * Return: void
  */
-static int dp_tx_classify_tid(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
-			      struct dp_tx_msdu_info_s *msdu_info)
+static void dp_tx_classify_tid(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
+		struct dp_tx_msdu_info_s *msdu_info)
 {
-	/* TODO */
-	return 0;
+	uint8_t tos = 0, dscp_tid_override = 0;
+	uint8_t *hdr_ptr, *L3datap;
+	uint8_t is_mcast = 0;
+	struct ether_header *eh = NULL;
+	qdf_ethervlan_header_t *evh = NULL;
+	uint16_t   ether_type;
+	qdf_llc_t *llcHdr;
+	struct dp_pdev *pdev = (struct dp_pdev *)vdev->pdev;
+
+	/* for mesh packets don't do any classification */
+	if (qdf_unlikely(vdev->mesh_vdev))
+		return;
+
+	if (qdf_likely(vdev->tx_encap_type != htt_cmn_pkt_type_raw)) {
+		eh = (struct ether_header *) nbuf->data;
+		hdr_ptr = eh->ether_dhost;
+		L3datap = hdr_ptr + sizeof(struct ether_header);
+	} else {
+		qdf_dot3_qosframe_t *qos_wh =
+			(qdf_dot3_qosframe_t *) nbuf->data;
+		msdu_info->tid = qos_wh->i_fc[0] & DP_FC0_SUBTYPE_QOS ?
+			qos_wh->i_qos[0] & DP_QOS_TID : 0;
+		return;
+	}
+
+	is_mcast = DP_FRAME_IS_MULTICAST(hdr_ptr);
+	ether_type = eh->ether_type;
+	/*
+	 * Check if packet is dot3 or eth2 type.
+	 */
+	if (IS_LLC_PRESENT(ether_type)) {
+		ether_type = (uint16_t)*(nbuf->data + 2*ETHER_ADDR_LEN +
+				sizeof(*llcHdr));
+
+		if (ether_type == htons(ETHERTYPE_8021Q)) {
+			L3datap = hdr_ptr + sizeof(qdf_ethervlan_header_t) +
+				sizeof(*llcHdr);
+			ether_type = (uint16_t)*(nbuf->data + 2*ETHER_ADDR_LEN
+					+ sizeof(*llcHdr) +
+					sizeof(qdf_net_vlanhdr_t));
+		} else {
+			L3datap = hdr_ptr + sizeof(struct ether_header) +
+				sizeof(*llcHdr);
+		}
+
+	} else {
+		if (ether_type == htons(ETHERTYPE_8021Q)) {
+			evh = (qdf_ethervlan_header_t *) eh;
+			ether_type = evh->ether_type;
+			L3datap = hdr_ptr + sizeof(qdf_ethervlan_header_t);
+		}
+	}
+	/*
+	 * Find priority from IP TOS DSCP field
+	 */
+	if (qdf_nbuf_is_ipv4_pkt(nbuf)) {
+		qdf_net_iphdr_t *ip = (qdf_net_iphdr_t *) L3datap;
+		if (qdf_nbuf_is_ipv4_dhcp_pkt(nbuf)) {
+			/* Only for unicast frames */
+			if (!is_mcast) {
+				/* send it on VO queue */
+				msdu_info->tid = DP_VO_TID;
+			}
+		} else {
+			/*
+			 * IP frame: exclude ECN bits 0-1 and map DSCP bits 2-7
+			 * from TOS byte.
+			 */
+			tos = ip->ip_tos;
+			dscp_tid_override = 1;
+
+		}
+	} else if (qdf_nbuf_is_ipv6_pkt(nbuf)) {
+		/* TODO
+		 * use flowlabel
+		 *igmpmld cases to be handled in phase 2
+		 */
+		unsigned long ver_pri_flowlabel;
+		unsigned long pri;
+		ver_pri_flowlabel = *(unsigned long *) L3datap;
+		pri = (ntohl(ver_pri_flowlabel) & IPV6_FLOWINFO_PRIORITY) >>
+			DP_IPV6_PRIORITY_SHIFT;
+		tos = pri;
+		dscp_tid_override = 1;
+	} else if (qdf_nbuf_is_ipv4_eapol_pkt(nbuf))
+		msdu_info->tid = DP_VO_TID;
+	else if (qdf_nbuf_is_ipv4_arp_pkt(nbuf)) {
+		/* Only for unicast frames */
+		if (!is_mcast) {
+			/* send ucast arp on VO queue */
+			msdu_info->tid = DP_VO_TID;
+		}
+	}
+
+	/*
+	 * Assign all MCAST packets to BE
+	 */
+	if (qdf_unlikely(vdev->tx_encap_type != htt_cmn_pkt_type_raw)) {
+		if (is_mcast) {
+			tos = 0;
+			dscp_tid_override = 1;
+		}
+	}
+
+	if (dscp_tid_override == 1) {
+		tos = (tos >> DP_IP_DSCP_SHIFT) & DP_IP_DSCP_MASK;
+		msdu_info->tid = pdev->dscp_tid_map[vdev->dscp_tid_map_id][tos];
+	}
+	return;
 }
 
 /**
@@ -1197,7 +1282,7 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 	}
 
 	/* RAW */
-	if (qdf_unlikely(vdev->tx_encap_type == htt_pkt_type_raw)) {
+	if (qdf_unlikely(vdev->tx_encap_type == htt_cmn_pkt_type_raw)) {
 		nbuf = dp_tx_prepare_raw(vdev, nbuf, &seg_info, &msdu_info);
 		if (nbuf == NULL)
 			return NULL;
@@ -1979,10 +2064,6 @@ QDF_STATUS dp_tx_soc_attach(struct dp_soc *soc)
 	 */
 	soc->process_tx_status = 1;
 
-	/* Initialize Default DSCP-TID mapping table in TCL */
-	hal_tx_set_dscp_tid_map(soc->hal_soc, default_dscp_tid_map,
-			HAL_TX_DSCP_TID_MAP_TABLE_DEFAULT);
-
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
 			"%s HAL Tx init Success\n", __func__);
 

+ 17 - 3
dp/wifi3.0/dp_types.h

@@ -45,6 +45,16 @@
 #define REPT_MU_MIMO 1
 #define REPT_MU_OFDMA_MIMO 3
 #define REO_ERROR_TYPE_MAX (HAL_REO_ERR_QUEUE_DESC_BLOCKED_SET+1)
+#define DP_VO_TID 6
+
+#define DP_MAX_INTERRUPT_CONTEXTS 8
+#define DP_MAX_TID_MAPS 16 /* MAX TID MAPS AVAILABLE PER PDEV*/
+#define DSCP_TID_MAP_MAX    (64)
+#define DP_IP_DSCP_SHIFT 2
+#define DP_IP_DSCP_MASK 0x3f
+#define DP_FC0_SUBTYPE_QOS 0x80
+#define DP_QOS_TID 0x0f
+#define DP_IPV6_PRIORITY_SHIFT 20
 
 struct dp_soc_cmn;
 struct dp_pdev;
@@ -69,6 +79,7 @@ union dp_rx_desc_list_elem_t;
      (_a)[3] == 0xff &&                         \
      (_a)[4] == 0xff &&                         \
      (_a)[5] == 0xff)
+#define IS_LLC_PRESENT(typeorlen) ((typeorlen) >= 0x600)
 
 /**
  * macros to convert hw mac id to sw mac id:
@@ -581,6 +592,10 @@ struct dp_pdev {
 		qdf_spinlock_t lock;
 		struct dp_peer *map[OL_TXRX_NUM_LOCAL_PEER_IDS];
 	} local_peer_ids;
+
+	/* dscp_tid_map_*/
+	uint8_t dscp_tid_map[DP_MAX_TID_MAPS][DSCP_TID_MAP_MAX];
+
 	/* TBD */
 };
 
@@ -668,9 +683,9 @@ struct dp_vdev {
 	enum wlan_op_mode opmode;
 
 	/* Tx encapsulation type for this VAP */
-	enum htt_pkt_type tx_encap_type;
+	enum htt_cmn_pkt_type tx_encap_type;
 	/* Rx Decapsulation type for this VAP */
-	enum htt_pkt_type rx_decap_type;
+	enum htt_cmn_pkt_type rx_decap_type;
 
 	/* BSS peer */
 	struct dp_peer *vap_bss_peer;
@@ -771,5 +786,4 @@ struct dp_peer {
 	/* Peer Stats */
 	struct cdp_peer_stats stats;
 };
-
 #endif /* _DP_TYPES_H_ */

+ 38 - 0
hal/wifi3.0/hal_tx.h

@@ -75,6 +75,9 @@ do {                                            \
 
 #define HAL_TX_COMPLETION_DESC_LEN_DWORDS (NUM_OF_DWORDS_WBM_RELEASE_RING)
 #define HAL_TX_COMPLETION_DESC_LEN_BYTES (NUM_OF_DWORDS_WBM_RELEASE_RING*4)
+#define HAL_TX_BITS_PER_TID 3
+#define HAL_TX_NUM_DSCP_PER_REGISTER 10
+#define HAL_MAX_HW_DSCP_TID_MAPS 2
 
 #define HTT_META_HEADER_LEN_BYTES 64
 #define HAL_TX_EXT_DESC_WITH_META_DATA \
@@ -1025,6 +1028,41 @@ static inline void hal_tx_set_dscp_tid_map(void *hal_soc, uint8_t *map,
 	}
 }
 
+/**
+ * hal_tx_update_dscp_tid() - Update the dscp tid map table as updated by user
+ * @soc: HAL SoC context
+ * @map: DSCP-TID mapping table
+ * @id : MAP ID
+ * @dscp: DSCP_TID map index
+ *
+ * Return: void
+ */
+static inline void hal_tx_update_dscp_tid(void *hal_soc, uint8_t tid,
+		uint8_t id, uint8_t dscp)
+{
+	int index;
+	uint32_t addr;
+	uint32_t value;
+
+	struct hal_soc *soc = (struct hal_soc *)hal_soc;
+
+	if (id == HAL_TX_DSCP_TID_MAP_TABLE_DEFAULT)
+		addr =
+			HWIO_TCL_R0_DSCP_TID1_MAP_0_ADDR(
+					SEQ_WCSS_UMAC_MAC_TCL_REG_OFFSET);
+	else
+		addr =
+			HWIO_TCL_R0_DSCP_TID2_MAP_0_ADDR(
+					SEQ_WCSS_UMAC_MAC_TCL_REG_OFFSET);
+
+	index = dscp % HAL_TX_NUM_DSCP_PER_REGISTER;
+	addr += 4 * (dscp/HAL_TX_NUM_DSCP_PER_REGISTER);
+	value = tid << (HAL_TX_BITS_PER_TID * index);
+
+	HAL_REG_WRITE(soc, addr,
+			(value & HWIO_TCL_R0_DSCP_TID1_MAP_1_RMSK));
+}
+
 /**
  * hal_tx_init_data_ring() - Initialize all the TCL Descriptors in SRNG
  * @hal_soc: Handle to HAL SoC structure

+ 59 - 0
qdf/inc/qdf_net_types.h

@@ -463,4 +463,63 @@ static inline int32_t qdf_csum_ipv6(const in6_addr_t *saddr,
 	return (int32_t)__qdf_csum_ipv6(saddr, daddr, len, proto, sum);
 }
 
+typedef struct {
+	uint8_t i_fc[2];
+	uint8_t i_dur[2];
+	uint8_t i_addr1[QDF_NET_MAC_ADDR_MAX_LEN];
+	uint8_t i_addr2[QDF_NET_MAC_ADDR_MAX_LEN];
+	uint8_t i_addr3[QDF_NET_MAC_ADDR_MAX_LEN];
+	uint8_t i_seq[2];
+	uint8_t i_qos[2];
+} qdf_dot3_qosframe_t;
+
+typedef struct {
+	uint8_t ether_dhost[QDF_NET_MAC_ADDR_MAX_LEN];
+	uint8_t ether_shost[QDF_NET_MAC_ADDR_MAX_LEN];
+	uint16_t vlan_TCI;
+	uint16_t vlan_encapsulated_proto;
+	uint16_t ether_type;
+} qdf_ethervlan_header_t;
+
+typedef struct {
+	uint8_t llc_dsap;
+	uint8_t llc_ssap;
+	union {
+		struct {
+			uint8_t control;
+			uint8_t format_id;
+			uint8_t class;
+			uint8_t window_x2;
+		} __packed type_u;
+		struct {
+			uint8_t num_snd_x2;
+			uint8_t num_rcv_x2;
+		} __packed type_i;
+		struct {
+			uint8_t control;
+			uint8_t num_rcv_x2;
+		} __packed type_s;
+		struct {
+			uint8_t control;
+			/*
+			 * We cannot put the following fields in a structure
+			 * because the structure rounding might cause padding.
+			 */
+			uint8_t frmr_rej_pdu0;
+			uint8_t frmr_rej_pdu1;
+			uint8_t frmr_control;
+			uint8_t frmr_control_ext;
+			uint8_t frmr_cause;
+		} __packed type_frmr;
+		struct {
+			uint8_t  control;
+			uint8_t  org_code[3];
+			uint16_t ether_type;
+		} __packed type_snap;
+		struct {
+			uint8_t control;
+			uint8_t control_ext;
+		} __packed type_raw;
+	} llc_un /* XXX __packed ??? */;
+} qdf_llc_t;
 #endif /*_QDF_NET_TYPES_H*/

+ 5 - 0
qdf/linux/src/qdf_nbuf.c

@@ -739,6 +739,7 @@ bool __qdf_nbuf_data_is_ipv4_pkt(uint8_t *data)
 	else
 		return false;
 }
+EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv4_pkt);
 
 /**
  * __qdf_nbuf_data_is_ipv4_dhcp_pkt() - check if skb data is a dhcp packet
@@ -768,6 +769,7 @@ bool __qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data)
 	else
 		return false;
 }
+EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv4_dhcp_pkt);
 
 /**
  * __qdf_nbuf_data_is_ipv4_eapol_pkt() - check if skb data is a eapol packet
@@ -790,6 +792,7 @@ bool __qdf_nbuf_data_is_ipv4_eapol_pkt(uint8_t *data)
 	else
 		return false;
 }
+EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv4_eapol_pkt);
 
 /**
  * __qdf_nbuf_is_ipv4_wapi_pkt() - check if skb data is a wapi packet
@@ -834,6 +837,7 @@ bool __qdf_nbuf_data_is_ipv4_arp_pkt(uint8_t *data)
 	else
 		return false;
 }
+EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv4_arp_pkt);
 
 /**
  * __qdf_nbuf_data_is_ipv6_pkt() - check if it is IPV6 packet.
@@ -856,6 +860,7 @@ bool __qdf_nbuf_data_is_ipv6_pkt(uint8_t *data)
 	else
 		return false;
 }
+EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv6_pkt);
 
 /**
  * __qdf_nbuf_data_is_ipv4_mcast_pkt() - check if it is IPV4 multicast packet.