From 34721398d568d7d99dac2da40369a604210229ed Mon Sep 17 00:00:00 2001 From: "Ruchi, Agrawal" Date: Mon, 13 Nov 2017 18:02:09 +0530 Subject: [PATCH] qcacmn: Host CCE Classification Changes Host CCE Classification changes for RAW Mode workaround H/w CCE hangs while classfiying raw packets so the classification is moved to host Change-Id: I75cfc6b140a7983fcdfb797c93b9fd57f01c5ee3 --- dp/inc/cdp_txrx_cmn_struct.h | 4 ++ dp/wifi3.0/dp_main.c | 10 +++++ dp/wifi3.0/dp_tx.c | 83 +++++++++++++++++++++++++++++++++++- dp/wifi3.0/dp_types.h | 6 +++ qdf/inc/qdf_nbuf.h | 34 +++++++++++++++ qdf/linux/src/i_qdf_nbuf.h | 2 + qdf/linux/src/qdf_nbuf.c | 54 +++++++++++++++++++++++ 7 files changed, 192 insertions(+), 1 deletion(-) diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 38553af3eada..defebd0ff5ba 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -108,6 +108,7 @@ */ enum cdp_cfg_param_type { CDP_CFG_MAX_PEER_ID, + CDP_CFG_CCE_DISABLE, CDP_CFG_NUM_PARAMS }; @@ -938,6 +939,9 @@ struct cdp_tx_ingress_stats { /* Resource Full: Congestion Control */ uint32_t res_full; } dropped; + + /*Number of packets classified by CCE*/ + uint32_t cce_classified; }; struct cdp_vdev_stats { diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index f469616043dd..49fccd47591d 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3830,6 +3830,7 @@ static inline void dp_aggregate_pdev_stats(struct dp_pdev *pdev) DP_STATS_AGGR(pdev, vdev, tx_i.dropped.enqueue_fail); DP_STATS_AGGR(pdev, vdev, tx_i.dropped.desc_na); DP_STATS_AGGR(pdev, vdev, tx_i.dropped.res_full); + DP_STATS_AGGR(pdev, vdev, tx_i.cce_classified); pdev->stats.tx_i.dropped.dropped_pkt.num = pdev->stats.tx_i.dropped.dma_error + @@ -3944,6 +3945,9 @@ dp_print_pdev_tx_stats(struct dp_pdev *pdev) pdev->stats.tx_i.nawds_mcast.num); DP_PRINT_STATS(" Bytes = %d", pdev->stats.tx_i.nawds_mcast.bytes); + DP_PRINT_STATS("CCE Classified:"); + DP_TRACE(FATAL, " CCE Classified Packets: %u", + pdev->stats.tx_i.cce_classified); } /** @@ -5686,6 +5690,7 @@ void *dp_soc_attach_wifi3(void *osif_soc, void *hif_handle, } wlan_cfg_set_rx_hash(soc->wlan_cfg_ctx, rx_hash); + soc->cce_disable = false; if (soc->cdp_soc.ol_ops->get_dp_cfg_param) { int ret = soc->cdp_soc.ol_ops->get_dp_cfg_param(soc->osif_soc, @@ -5694,6 +5699,11 @@ void *dp_soc_attach_wifi3(void *osif_soc, void *hif_handle, if (ret != -EINVAL) { wlan_cfg_set_max_peer_id(soc->wlan_cfg_ctx, ret); } + + ret = soc->cdp_soc.ol_ops->get_dp_cfg_param(soc->osif_soc, + CDP_CFG_CCE_DISABLE); + if (ret) + soc->cce_disable = true; } qdf_spinlock_create(&soc->peer_ref_mutex); diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 839d6d1d914e..cdf42b5773a2 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -868,6 +868,68 @@ static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev, return QDF_STATUS_SUCCESS; } + +/** + * dp_cce_classify() - Classify the frame based on CCE rules + * @vdev: DP vdev handle + * @nbuf: skb + * + * Classify frames based on CCE rules + * Return: bool( true if classified, + * else false) + */ +static bool dp_cce_classify(qdf_nbuf_t nbuf) +{ + struct ether_header *eh = NULL; + uint16_t ether_type; + qdf_llc_t *llcHdr; + qdf_nbuf_t nbuf_clone = NULL; + + eh = (struct ether_header *) qdf_nbuf_data(nbuf); + ether_type = eh->ether_type; + + llcHdr = (qdf_llc_t *)(nbuf->data + sizeof(struct ether_header)); + + if (qdf_unlikely(DP_FRAME_IS_SNAP(llcHdr))) { + ether_type = (uint16_t)*(nbuf->data + 2*ETHER_ADDR_LEN + + sizeof(*llcHdr)); + nbuf_clone = qdf_nbuf_clone(nbuf); + qdf_nbuf_pull_head(nbuf_clone, sizeof(*llcHdr)); + + if (ether_type == htons(ETHERTYPE_8021Q)) { + qdf_nbuf_pull_head(nbuf_clone, sizeof(*llcHdr) + +sizeof(qdf_net_vlanhdr_t)); + } + } else { + if (ether_type == htons(ETHERTYPE_8021Q)) { + nbuf_clone = qdf_nbuf_clone(nbuf); + qdf_nbuf_pull_head(nbuf_clone, + sizeof(qdf_net_vlanhdr_t)); + } + } + + if (qdf_unlikely(nbuf_clone)) + nbuf = nbuf_clone; + + if (qdf_unlikely(qdf_nbuf_is_ipv4_eapol_pkt(nbuf) + || qdf_nbuf_is_ipv4_arp_pkt(nbuf) + || qdf_nbuf_is_ipv4_wapi_pkt(nbuf) + || qdf_nbuf_is_ipv4_tdls_pkt(nbuf) + || (qdf_nbuf_is_ipv4_pkt(nbuf) + && qdf_nbuf_is_ipv4_dhcp_pkt(nbuf)) + || (qdf_nbuf_is_ipv6_pkt(nbuf) && + qdf_nbuf_is_ipv6_dhcp_pkt(nbuf)))) { + if (qdf_unlikely(nbuf_clone != NULL)) + qdf_nbuf_free(nbuf_clone); + return true; + } + + if (qdf_unlikely(nbuf_clone != NULL)) + qdf_nbuf_free(nbuf_clone); + + return false; +} + /** * dp_tx_classify_tid() - Obtain TID to be used for this frame * @vdev: DP vdev handle @@ -928,7 +990,6 @@ static void dp_tx_classify_tid(struct dp_vdev *vdev, qdf_nbuf_t nbuf, L3datap = hdr_ptr + sizeof(struct ether_header) + sizeof(*llcHdr); } - } else { if (ether_type == htons(ETHERTYPE_8021Q)) { evh = (qdf_ethervlan_header_t *) eh; @@ -1068,6 +1129,14 @@ static qdf_nbuf_t dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, return nbuf; } + if (qdf_unlikely(soc->cce_disable)) { + if (dp_cce_classify(nbuf) == true) { + DP_STATS_INC(vdev, tx_i.cce_classified, 1); + tid = DP_VO_TID; + tx_desc->flags |= DP_TX_DESC_FLAG_TO_FW; + } + } + dp_tx_update_tdls_flags(tx_desc); if (qdf_unlikely(hal_srng_access_start(soc->hal_soc, hal_srng))) { @@ -1138,6 +1207,7 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, struct dp_pdev *pdev = vdev->pdev; struct dp_soc *soc = pdev->soc; struct dp_tx_desc_s *tx_desc; + bool is_cce_classified = false; QDF_STATUS status; struct dp_tx_queue *tx_q = &msdu_info->tx_queue; @@ -1151,6 +1221,14 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, return nbuf; } + if (qdf_unlikely(soc->cce_disable)) { + is_cce_classified = dp_cce_classify(nbuf); + if (is_cce_classified) { + DP_STATS_INC(vdev, tx_i.cce_classified, 1); + msdu_info->tid = DP_VO_TID; + } + } + if (msdu_info->frm_type == dp_tx_frm_me) nbuf = msdu_info->u.sg_info.curr_seg->nbuf; @@ -1183,6 +1261,9 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, tx_desc->flags |= DP_TX_DESC_FLAG_ME; } + if (is_cce_classified) + tx_desc->flags |= DP_TX_DESC_FLAG_TO_FW; + /* * Enqueue the Tx MSDU descriptor to HW for transmit */ diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index be84e9688cf3..04f6ef505390 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -125,6 +125,9 @@ union dp_rx_desc_list_elem_t; (_a)[4] == 0xff && \ (_a)[5] == 0xff) #define IS_LLC_PRESENT(typeorlen) ((typeorlen) >= 0x600) +#define DP_FRAME_IS_SNAP(_llc) ((_llc)->llc_dsap == 0xaa && \ + (_llc)->llc_ssap == 0xaa && \ + (_llc)->llc_un.type_snap.control == 0x3) #define DP_FRAME_FC0_TYPE_MASK 0x0c #define DP_FRAME_FC0_TYPE_DATA 0x08 #define DP_FRAME_IS_DATA(_frame) \ @@ -585,6 +588,9 @@ struct dp_soc { /* Number of PDEVs */ uint8_t pdev_count; + /*cce disable*/ + bool cce_disable; + /* Link descriptor memory banks */ struct { void *base_vaddr_unaligned; diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h index 1ca15817ad23..327864078f0c 100644 --- a/qdf/inc/qdf_nbuf.h +++ b/qdf/inc/qdf_nbuf.h @@ -60,6 +60,7 @@ #define QDF_NBUF_TRAC_EAPOL_ETH_TYPE 0x888E #define QDF_NBUF_TRAC_WAPI_ETH_TYPE 0x88b4 #define QDF_NBUF_TRAC_ARP_ETH_TYPE 0x0806 +#define QDF_NBUF_TRAC_TDLS_ETH_TYPE 0x890D #define QDF_NBUF_TRAC_IPV4_ETH_TYPE 0x0800 #define QDF_NBUF_TRAC_IPV6_ETH_TYPE 0x86dd #define QDF_NBUF_DEST_MAC_OFFSET 0 @@ -71,10 +72,14 @@ #define QDF_NBUF_TRAC_IPV4_ADDR_BCAST_MASK 0xF0000000 #define QDF_NBUF_TRAC_IPV6_DEST_ADDR_OFFSET 38 #define QDF_NBUF_TRAC_IPV6_DEST_ADDR 0xFF00 +#define QDF_NBUF_TRAC_IPV6_OFFSET 14 +#define QDF_NBUF_TRAC_IPV6_HEADER_SIZE 40 #define QDF_NBUF_TRAC_ICMP_TYPE 1 #define QDF_NBUF_TRAC_TCP_TYPE 6 #define QDF_NBUF_TRAC_UDP_TYPE 17 #define QDF_NBUF_TRAC_ICMPV6_TYPE 0x3a +#define QDF_NBUF_TRAC_DHCP6_SRV_PORT 547 +#define QDF_NBUF_TRAC_DHCP6_CLI_PORT 546 /* EAPOL Related MASK */ #define EAPOL_PACKET_TYPE_OFFSET 15 @@ -1769,6 +1774,21 @@ bool qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data) return __qdf_nbuf_data_is_ipv4_dhcp_pkt(data); } +/** + * qdf_nbuf_data_is_ipv6_dhcp_pkt() - check if it is DHCP packet. + * @data: Pointer to DHCP packet data buffer + * + * This func. checks whether it is a DHCP packet or not. + * + * Return: true if it is a DHCP packet + * false if not + */ +static inline +bool qdf_nbuf_is_ipv6_dhcp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv6_dhcp_pkt(qdf_nbuf_data(buf)); +} + /** * qdf_nbuf_is_ipv4_eapol_pkt() - check if packet is a eapol packet or not * @buf: buffer @@ -1812,6 +1832,20 @@ bool qdf_nbuf_is_ipv4_wapi_pkt(qdf_nbuf_t buf) return __qdf_nbuf_is_ipv4_wapi_pkt(buf); } +/** + * qdf_nbuf_is_ipv4_tdls_pkt() - check if packet is a tdls packet or not + * @buf: buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is TDLS packet + */ +static inline +bool qdf_nbuf_is_ipv4_tdls_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_is_ipv4_tdls_pkt(buf); +} + /** * qdf_nbuf_is_ipv4_arp_pkt() - check if packet is a arp packet or not * @buf: buffer diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index 11468d9c4ee9..e89182c043a4 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -626,6 +626,7 @@ QDF_STATUS __qdf_nbuf_frag_map( void qdf_nbuf_classify_pkt(struct sk_buff *skb); bool __qdf_nbuf_is_ipv4_wapi_pkt(struct sk_buff *skb); +bool __qdf_nbuf_is_ipv4_tdls_pkt(struct sk_buff *skb); bool __qdf_nbuf_data_is_ipv4_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv6_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv4_mcast_pkt(uint8_t *data); @@ -637,6 +638,7 @@ bool __qdf_nbuf_data_is_ipv4_tcp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv6_udp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv6_tcp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv6_dhcp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv4_eapol_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv4_arp_pkt(uint8_t *data); enum qdf_proto_subtype __qdf_nbuf_data_get_dhcp_subtype(uint8_t *data); diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c index baa527de4cdb..c87e320a765a 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -1033,6 +1033,30 @@ bool __qdf_nbuf_is_ipv4_wapi_pkt(struct sk_buff *skb) else return false; } +EXPORT_SYMBOL(__qdf_nbuf_is_ipv4_wapi_pkt); + +/** + * __qdf_nbuf_is_ipv4_tdls_pkt() - check if skb data is a tdls packet + * @skb: Pointer to network buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is tdls packet + * false otherwise. + */ +bool __qdf_nbuf_is_ipv4_tdls_pkt(struct sk_buff *skb) +{ + uint16_t ether_type; + + ether_type = *(uint16_t *)(skb->data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET); + + if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_TDLS_ETH_TYPE)) + return true; + else + return false; +} +EXPORT_SYMBOL(__qdf_nbuf_is_ipv4_tdls_pkt); /** * __qdf_nbuf_data_is_ipv4_arp_pkt() - check if skb data is a arp packet @@ -1080,6 +1104,36 @@ bool __qdf_nbuf_data_is_ipv6_pkt(uint8_t *data) } EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv6_pkt); +/** + * __qdf_nbuf_data_is_ipv6_dhcp_pkt() - check if skb data is a dhcp packet + * @data: Pointer to network data buffer + * + * This api is for ipv6 packet. + * + * Return: true if packet is DHCP packet + * false otherwise + */ +bool __qdf_nbuf_data_is_ipv6_dhcp_pkt(uint8_t *data) +{ + uint16_t sport; + uint16_t dport; + + sport = *(uint16_t *)(data + QDF_NBUF_TRAC_IPV6_OFFSET + + QDF_NBUF_TRAC_IPV6_HEADER_SIZE); + dport = *(uint16_t *)(data + QDF_NBUF_TRAC_IPV6_OFFSET + + QDF_NBUF_TRAC_IPV6_HEADER_SIZE + + sizeof(uint16_t)); + + if (((sport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP6_SRV_PORT)) && + (dport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP6_CLI_PORT))) || + ((sport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP6_CLI_PORT)) && + (dport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP6_SRV_PORT)))) + return true; + else + return false; +} +EXPORT_SYMBOL(__qdf_nbuf_data_is_ipv6_dhcp_pkt); + /** * __qdf_nbuf_data_is_ipv4_mcast_pkt() - check if it is IPV4 multicast packet. * @data: Pointer to IPV4 packet data buffer