| /* |
| * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /* |
| * This file was originally distributed by Qualcomm Atheros, Inc. |
| * under proprietary terms before Copyright ownership was assigned |
| * to the Linux Foundation. |
| */ |
| |
| #ifndef _OL_TXRX_INTERNAL__H_ |
| #define _OL_TXRX_INTERNAL__H_ |
| |
| #include <qdf_util.h> /* qdf_assert */ |
| #include <qdf_nbuf.h> /* qdf_nbuf_t */ |
| #include <qdf_mem.h> /* qdf_mem_set */ |
| #include <cds_ieee80211_common.h> /* ieee80211_frame */ |
| #include <ol_htt_rx_api.h> /* htt_rx_msdu_desc_completes_mpdu, etc. */ |
| |
| #include <ol_txrx_types.h> |
| |
| #include <ol_txrx_dbg.h> |
| #include <enet.h> /* ETHERNET_HDR_LEN, etc. */ |
| #include <ipv4.h> /* IPV4_HDR_LEN, etc. */ |
| #include <ipv6.h> /* IPV6_HDR_LEN, etc. */ |
| #include <ip_prot.h> /* IP_PROTOCOL_TCP, etc. */ |
| |
| #ifdef ATH_11AC_TXCOMPACT |
| #define OL_TX_DESC_NO_REFS(tx_desc) 1 |
| #define OL_TX_DESC_REF_INIT(tx_desc) /* no-op */ |
| #define OL_TX_DESC_REF_INC(tx_desc) /* no-op */ |
| #else |
| #define OL_TX_DESC_NO_REFS(tx_desc) \ |
| qdf_atomic_dec_and_test(&tx_desc->ref_cnt) |
| #define OL_TX_DESC_REF_INIT(tx_desc) qdf_atomic_init(&tx_desc->ref_cnt) |
| #define OL_TX_DESC_REF_INC(tx_desc) qdf_atomic_inc(&tx_desc->ref_cnt) |
| #endif |
| |
| #ifndef TXRX_ASSERT_LEVEL |
| #define TXRX_ASSERT_LEVEL 3 |
| #endif |
| |
| #ifdef __KLOCWORK__ |
| #define TXRX_ASSERT1(x) do { if (!(x)) abort(); } while (0) |
| #define TXRX_ASSERT2(x) do { if (!(x)) abort(); } while (0) |
| #else /* #ifdef __KLOCWORK__ */ |
| |
| #if TXRX_ASSERT_LEVEL > 0 |
| #define TXRX_ASSERT1(condition) qdf_assert((condition)) |
| #else |
| #define TXRX_ASSERT1(condition) |
| #endif |
| |
| #if TXRX_ASSERT_LEVEL > 1 |
| #define TXRX_ASSERT2(condition) qdf_assert((condition)) |
| #else |
| #define TXRX_ASSERT2(condition) |
| #endif |
| #endif /* #ifdef __KLOCWORK__ */ |
| |
| #ifdef TXRX_PRINT_ENABLE |
| |
| #include <stdarg.h> /* va_list */ |
| #include <qdf_types.h> /* qdf_vprint */ |
| |
| #define ol_txrx_log(level, args...) \ |
| QDF_TRACE(QDF_MODULE_ID_TXRX, level, ## args) |
| #define ol_txrx_logfl(level, format, args...) \ |
| ol_txrx_log(level, FL(format), ## args) |
| |
| #define ol_txrx_alert(format, args...) \ |
| ol_txrx_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) |
| #define ol_txrx_err(format, args...) \ |
| ol_txrx_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) |
| #define ol_txrx_warn(format, args...) \ |
| ol_txrx_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) |
| #define ol_txrx_info(format, args...) \ |
| ol_txrx_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) |
| #define ol_txrx_info_high(format, args...) \ |
| ol_txrx_logfl(QDF_TRACE_LEVEL_INFO_HIGH, format, ## args) |
| #define ol_txrx_dbg(format, args...) \ |
| ol_txrx_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) |
| |
| /* |
| * define PN check failure message print rate |
| * as 1 second |
| */ |
| #define TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS 1000 |
| |
| #else |
| #define ol_txrx_log(level, args...) |
| #define ol_txrx_logfl(level, format, args...) |
| #define ol_txrx_alert(format, args...) |
| #define ol_txrx_err(format, args...) |
| #define ol_txrx_warn(format, args...) |
| #define ol_txrx_info(format, args...) |
| #define ol_txrx_info_high(format, args...) |
| #define ol_txrx_dbg(format, args...) |
| #endif /* TXRX_PRINT_ENABLE */ |
| |
| /*--- tx credit debug printouts ---*/ |
| |
| #ifndef DEBUG_CREDIT |
| #define DEBUG_CREDIT 0 |
| #endif |
| |
| #if DEBUG_CREDIT |
| #define TX_CREDIT_DEBUG_PRINT(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) |
| #else |
| #define TX_CREDIT_DEBUG_PRINT(fmt, ...) |
| #endif |
| |
| /*--- tx scheduler debug printouts ---*/ |
| |
| #ifdef HOST_TX_SCHED_DEBUG |
| #define TX_SCHED_DEBUG_PRINT(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) |
| #else |
| #define TX_SCHED_DEBUG_PRINT(fmt, ...) |
| #endif |
| #define TX_SCHED_DEBUG_PRINT_ALWAYS(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) |
| |
| #define OL_TXRX_LIST_APPEND(head, tail, elem) \ |
| do { \ |
| if (!(head)) { \ |
| (head) = (elem); \ |
| } else { \ |
| qdf_nbuf_set_next((tail), (elem)); \ |
| } \ |
| (tail) = (elem); \ |
| } while (0) |
| |
| static inline void |
| ol_rx_mpdu_list_next(struct ol_txrx_pdev_t *pdev, |
| void *mpdu_list, |
| qdf_nbuf_t *mpdu_tail, qdf_nbuf_t *next_mpdu) |
| { |
| htt_pdev_handle htt_pdev = pdev->htt_pdev; |
| qdf_nbuf_t msdu; |
| |
| /* |
| * For now, we use a simply flat list of MSDUs. |
| * So, traverse the list until we reach the last MSDU within the MPDU. |
| */ |
| TXRX_ASSERT2(mpdu_list); |
| msdu = mpdu_list; |
| while (!htt_rx_msdu_desc_completes_mpdu |
| (htt_pdev, htt_rx_msdu_desc_retrieve(htt_pdev, msdu))) { |
| msdu = qdf_nbuf_next(msdu); |
| TXRX_ASSERT2(msdu); |
| } |
| /* msdu now points to the last MSDU within the first MPDU */ |
| *mpdu_tail = msdu; |
| *next_mpdu = qdf_nbuf_next(msdu); |
| } |
| |
| /*--- txrx stats macros ---*/ |
| |
| /* unconditional defs */ |
| #define TXRX_STATS_INCR(pdev, field) TXRX_STATS_ADD(pdev, field, 1) |
| |
| /* default conditional defs (may be undefed below) */ |
| |
| #define TXRX_STATS_INIT(_pdev) \ |
| qdf_mem_set(&((_pdev)->stats), sizeof((_pdev)->stats), 0x0) |
| #define TXRX_STATS_ADD(_pdev, _field, _delta) { \ |
| _pdev->stats._field += _delta; } |
| #define TXRX_STATS_MSDU_INCR(pdev, field, netbuf) \ |
| do { \ |
| TXRX_STATS_INCR((pdev), pub.field.pkts); \ |
| TXRX_STATS_ADD((pdev), pub.field.bytes, qdf_nbuf_len(netbuf)); \ |
| } while (0) |
| |
| /* conditional defs based on verbosity level */ |
| |
| |
| #define TXRX_STATS_MSDU_LIST_INCR(pdev, field, netbuf_list) \ |
| do { \ |
| qdf_nbuf_t tmp_list = netbuf_list; \ |
| while (tmp_list) { \ |
| TXRX_STATS_MSDU_INCR(pdev, field, tmp_list); \ |
| tmp_list = qdf_nbuf_next(tmp_list); \ |
| } \ |
| } while (0) |
| |
| #define TXRX_STATS_MSDU_INCR_TX_STATUS(status, pdev, netbuf) do { \ |
| if (status == htt_tx_status_ok) \ |
| TXRX_STATS_MSDU_INCR(pdev, tx.delivered, netbuf); \ |
| else if (status == htt_tx_status_discard) \ |
| TXRX_STATS_MSDU_INCR(pdev, tx.dropped.target_discard, \ |
| netbuf); \ |
| else if (status == htt_tx_status_no_ack) \ |
| TXRX_STATS_MSDU_INCR(pdev, tx.dropped.no_ack, netbuf); \ |
| else if (status == htt_tx_status_download_fail) \ |
| TXRX_STATS_MSDU_INCR(pdev, tx.dropped.download_fail, \ |
| netbuf); \ |
| else \ |
| /* NO-OP */; \ |
| } while (0) |
| |
| #define TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs) \ |
| do { \ |
| if (_p_cntrs == 1) { \ |
| TXRX_STATS_ADD(_pdev, pub.tx.comp_histogram.pkts_1, 1);\ |
| } else if (_p_cntrs > 2 && _p_cntrs <= 10) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_2_10, 1); \ |
| } else if (_p_cntrs > 10 && _p_cntrs <= 20) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_11_20, 1); \ |
| } else if (_p_cntrs > 20 && _p_cntrs <= 30) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_21_30, 1); \ |
| } else if (_p_cntrs > 30 && _p_cntrs <= 40) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_31_40, 1); \ |
| } else if (_p_cntrs > 40 && _p_cntrs <= 50) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_41_50, 1); \ |
| } else if (_p_cntrs > 50 && _p_cntrs <= 60) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_51_60, 1); \ |
| } else { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.comp_histogram.pkts_61_plus, 1); \ |
| } \ |
| } while (0) |
| |
| #define TXRX_STATS_UPDATE_TX_STATS(_pdev, _status, _p_cntrs, _b_cntrs) \ |
| do { \ |
| switch (status) { \ |
| case htt_tx_status_ok: \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.delivered.pkts, _p_cntrs); \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.delivered.bytes, _b_cntrs); \ |
| break; \ |
| case htt_tx_status_discard: \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.dropped.target_discard.pkts, _p_cntrs);\ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.dropped.target_discard.bytes, _b_cntrs);\ |
| break; \ |
| case htt_tx_status_no_ack: \ |
| TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.pkts, \ |
| _p_cntrs); \ |
| TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.bytes, \ |
| _b_cntrs); \ |
| break; \ |
| case htt_tx_status_download_fail: \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.dropped.download_fail.pkts, _p_cntrs); \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.dropped.download_fail.bytes, _b_cntrs);\ |
| break; \ |
| default: \ |
| break; \ |
| } \ |
| TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs); \ |
| } while (0) |
| |
| |
| /*--- txrx sequence number trace macros ---*/ |
| |
| #define TXRX_SEQ_NUM_ERR(_status) (0xffff - _status) |
| |
| #if defined(ENABLE_RX_REORDER_TRACE) |
| |
| A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev); |
| void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev); |
| void ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, |
| uint8_t tid, |
| uint16_t reorder_idx, |
| uint16_t seq_num, int num_mpdus); |
| |
| #define OL_RX_REORDER_TRACE_ATTACH ol_rx_reorder_trace_attach |
| #define OL_RX_REORDER_TRACE_DETACH ol_rx_reorder_trace_detach |
| #define OL_RX_REORDER_TRACE_ADD ol_rx_reorder_trace_add |
| |
| #else |
| |
| #define OL_RX_REORDER_TRACE_ATTACH(_pdev) A_OK |
| #define OL_RX_REORDER_TRACE_DETACH(_pdev) |
| #define OL_RX_REORDER_TRACE_ADD(pdev, tid, reorder_idx, seq_num, num_mpdus) |
| |
| #endif /* ENABLE_RX_REORDER_TRACE */ |
| |
| /*--- txrx packet number trace macros ---*/ |
| |
| #if defined(ENABLE_RX_PN_TRACE) |
| |
| A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev); |
| void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev); |
| void ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, |
| struct ol_txrx_peer_t *peer, |
| uint16_t tid, void *rx_desc); |
| |
| #define OL_RX_PN_TRACE_ATTACH ol_rx_pn_trace_attach |
| #define OL_RX_PN_TRACE_DETACH ol_rx_pn_trace_detach |
| #define OL_RX_PN_TRACE_ADD ol_rx_pn_trace_add |
| |
| #else |
| |
| #define OL_RX_PN_TRACE_ATTACH(_pdev) A_OK |
| #define OL_RX_PN_TRACE_DETACH(_pdev) |
| #define OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc) |
| |
| #endif /* ENABLE_RX_PN_TRACE */ |
| |
| static inline int ol_txrx_ieee80211_hdrsize(const void *data) |
| { |
| const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; |
| int size = sizeof(struct ieee80211_frame); |
| |
| /* NB: we don't handle control frames */ |
| TXRX_ASSERT1((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != |
| IEEE80211_FC0_TYPE_CTL); |
| if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == |
| IEEE80211_FC1_DIR_DSTODS) |
| size += IEEE80211_ADDR_LEN; |
| if (IEEE80211_QOS_HAS_SEQ(wh)) { |
| size += sizeof(uint16_t); |
| /* Qos frame with Order bit set indicates an HTC frame */ |
| if (wh->i_fc[1] & IEEE80211_FC1_ORDER) |
| size += sizeof(struct ieee80211_htc); |
| } |
| return size; |
| } |
| |
| /*--- frame display utility ---*/ |
| |
| enum ol_txrx_frm_dump_options { |
| ol_txrx_frm_dump_contents = 0x1, |
| ol_txrx_frm_dump_tcp_seq = 0x2, |
| }; |
| |
| #ifdef TXRX_DEBUG_DATA |
| static inline void |
| ol_txrx_frms_dump(const char *name, |
| struct ol_txrx_pdev_t *pdev, |
| qdf_nbuf_t frm, |
| enum ol_txrx_frm_dump_options display_options, int max_len) |
| { |
| #define TXRX_FRM_DUMP_MAX_LEN 128 |
| uint8_t local_buf[TXRX_FRM_DUMP_MAX_LEN] = { 0 }; |
| uint8_t *p; |
| |
| if (name) { |
| QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, "%s\n", |
| name); |
| } |
| while (frm) { |
| p = qdf_nbuf_data(frm); |
| if (display_options & ol_txrx_frm_dump_tcp_seq) { |
| int tcp_offset; |
| int l2_hdr_size; |
| uint16_t ethtype; |
| uint8_t ip_prot; |
| |
| if (pdev->frame_format == wlan_frm_fmt_802_3) { |
| struct ethernet_hdr_t *enet_hdr = |
| (struct ethernet_hdr_t *)p; |
| l2_hdr_size = ETHERNET_HDR_LEN; |
| |
| /* |
| * LLC/SNAP present? |
| */ |
| ethtype = (enet_hdr->ethertype[0] << 8) | |
| enet_hdr->ethertype[1]; |
| if (!IS_ETHERTYPE(ethertype)) { |
| /* 802.3 format */ |
| struct llc_snap_hdr_t *llc_hdr; |
| |
| llc_hdr = (struct llc_snap_hdr_t *) |
| (p + l2_hdr_size); |
| l2_hdr_size += LLC_SNAP_HDR_LEN; |
| ethtype = (llc_hdr->ethertype[0] << 8) | |
| llc_hdr->ethertype[1]; |
| } |
| } else { |
| struct llc_snap_hdr_t *llc_hdr; |
| |
| /* (generic?) 802.11 */ |
| l2_hdr_size = sizeof(struct ieee80211_frame); |
| llc_hdr = (struct llc_snap_hdr_t *) |
| (p + l2_hdr_size); |
| l2_hdr_size += LLC_SNAP_HDR_LEN; |
| ethtype = (llc_hdr->ethertype[0] << 8) | |
| llc_hdr->ethertype[1]; |
| } |
| if (ethtype == ETHERTYPE_IPV4) { |
| struct ipv4_hdr_t *ipv4_hdr; |
| |
| ipv4_hdr = |
| (struct ipv4_hdr_t *)(p + l2_hdr_size); |
| ip_prot = ipv4_hdr->protocol; |
| tcp_offset = l2_hdr_size + IPV4_HDR_LEN; |
| } else if (ethtype == ETHERTYPE_IPV6) { |
| struct ipv6_hdr_t *ipv6_hdr; |
| |
| ipv6_hdr = |
| (struct ipv6_hdr_t *)(p + l2_hdr_size); |
| ip_prot = ipv6_hdr->next_hdr; |
| tcp_offset = l2_hdr_size + IPV6_HDR_LEN; |
| } else { |
| QDF_TRACE(QDF_MODULE_ID_TXRX, |
| QDF_TRACE_LEVEL_INFO, |
| "frame %p non-IP ethertype (%x)\n", |
| frm, ethtype); |
| goto NOT_IP_TCP; |
| } |
| if (ip_prot == IP_PROTOCOL_TCP) { |
| #if NEVERDEFINED |
| struct tcp_hdr_t *tcp_hdr; |
| uint32_t tcp_seq_num; |
| |
| tcp_hdr = (struct tcp_hdr_t *)(p + tcp_offset); |
| tcp_seq_num = |
| (tcp_hdr->seq_num[0] << 24) | |
| (tcp_hdr->seq_num[1] << 16) | |
| (tcp_hdr->seq_num[1] << 8) | |
| (tcp_hdr->seq_num[1] << 0); |
| QDF_TRACE(QDF_MODULE_ID_TXRX, |
| QDF_TRACE_LEVEL_INFO, |
| "frame %p: TCP seq num = %d\n", frm, |
| tcp_seq_num); |
| #else |
| QDF_TRACE(QDF_MODULE_ID_TXRX, |
| QDF_TRACE_LEVEL_INFO, |
| "frame %p: TCP seq num = %d\n", frm, |
| ((*(p + tcp_offset + 4)) << 24) | |
| ((*(p + tcp_offset + 5)) << 16) | |
| ((*(p + tcp_offset + 6)) << 8) | |
| (*(p + tcp_offset + 7))); |
| #endif |
| } else { |
| QDF_TRACE(QDF_MODULE_ID_TXRX, |
| QDF_TRACE_LEVEL_INFO, |
| "frame %p non-TCP IP protocol (%x)\n", |
| frm, ip_prot); |
| } |
| } |
| NOT_IP_TCP: |
| if (display_options & ol_txrx_frm_dump_contents) { |
| int i, frag_num, len_lim; |
| |
| len_lim = max_len; |
| if (len_lim > qdf_nbuf_len(frm)) |
| len_lim = qdf_nbuf_len(frm); |
| if (len_lim > TXRX_FRM_DUMP_MAX_LEN) |
| len_lim = TXRX_FRM_DUMP_MAX_LEN; |
| |
| /* |
| * Gather frame contents from netbuf fragments |
| * into a contiguous buffer. |
| */ |
| frag_num = 0; |
| i = 0; |
| while (i < len_lim) { |
| int frag_bytes; |
| |
| frag_bytes = |
| qdf_nbuf_get_frag_len(frm, frag_num); |
| if (frag_bytes > len_lim - i) |
| frag_bytes = len_lim - i; |
| if (frag_bytes > 0) { |
| p = qdf_nbuf_get_frag_vaddr(frm, |
| frag_num); |
| qdf_mem_copy(&local_buf[i], p, |
| frag_bytes); |
| } |
| frag_num++; |
| i += frag_bytes; |
| } |
| |
| QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, |
| "frame %p data (%p), hex dump of bytes 0-%d of %d:\n", |
| frm, p, len_lim - 1, (int)qdf_nbuf_len(frm)); |
| p = local_buf; |
| while (len_lim > 16) { |
| QDF_TRACE(QDF_MODULE_ID_TXRX, |
| QDF_TRACE_LEVEL_INFO, |
| " " /* indent */ |
| "%02x %02x %02x %02x %02x %02x %02x %02x " |
| "%02x %02x %02x %02x %02x %02x %02x %02x\n", |
| *(p + 0), *(p + 1), *(p + 2), |
| *(p + 3), *(p + 4), *(p + 5), |
| *(p + 6), *(p + 7), *(p + 8), |
| *(p + 9), *(p + 10), *(p + 11), |
| *(p + 12), *(p + 13), *(p + 14), |
| *(p + 15)); |
| p += 16; |
| len_lim -= 16; |
| } |
| QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, |
| " " /* indent */); |
| while (len_lim > 0) { |
| QDF_TRACE(QDF_MODULE_ID_TXRX, |
| QDF_TRACE_LEVEL_INFO, "%02x ", *p); |
| p++; |
| len_lim--; |
| } |
| QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, |
| "\n"); |
| } |
| frm = qdf_nbuf_next(frm); |
| } |
| } |
| #else |
| #define ol_txrx_frms_dump(name, pdev, frms, display_options, max_len) |
| #endif /* TXRX_DEBUG_DATA */ |
| |
| #ifdef SUPPORT_HOST_STATISTICS |
| |
| #define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) \ |
| ol_rx_err_statistics(pdev->ctrl_pdev, vdev->vdev_id, err_type, \ |
| sec_type, is_mcast) |
| |
| #define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) \ |
| do { \ |
| int is_mcast; \ |
| enum htt_sec_type sec_type; \ |
| is_mcast = htt_rx_msdu_is_wlan_mcast( \ |
| pdev->htt_pdev, rx_desc); \ |
| sec_type = peer->security[is_mcast \ |
| ? txrx_sec_mcast \ |
| : txrx_sec_ucast].sec_type; \ |
| OL_RX_ERR_STATISTICS(pdev, vdev, err_type, \ |
| pdev->sec_types[sec_type], \ |
| is_mcast); \ |
| } while (false) |
| |
| #ifdef CONFIG_HL_SUPPORT |
| |
| /** |
| * ol_rx_err_inv_get_wifi_header() - retrieve wifi header |
| * @pdev: handle to the physical device |
| * @rx_msdu: msdu of which header needs to be retrieved |
| * |
| * Return: wifi header |
| */ |
| static inline |
| struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( |
| struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) |
| { |
| return NULL; |
| } |
| #else |
| |
| static inline |
| struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( |
| struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) |
| { |
| struct ieee80211_frame *wh = NULL; |
| |
| if (ol_cfg_frame_type(pdev) == wlan_frm_fmt_native_wifi) |
| /* For windows, it is always native wifi header .*/ |
| wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu); |
| |
| return wh; |
| } |
| #endif |
| |
| #define OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu) \ |
| do { \ |
| struct ieee80211_frame *wh = NULL; \ |
| /*FIX THIS : */ \ |
| /* Here htt_rx_mpdu_wifi_hdr_retrieve should be used. */ \ |
| /*But at present it seems it does not work.*/ \ |
| /*wh = (struct ieee80211_frame *) */ \ |
| /*htt_rx_mpdu_wifi_hdr_retrieve(pdev->htt_pdev, rx_desc);*/ \ |
| /* this only apply to LL device.*/ \ |
| wh = ol_rx_err_inv_get_wifi_header(pdev->ctrl_pdev, rx_msdu); \ |
| ol_rx_err_inv_peer_statistics(pdev->ctrl_pdev, \ |
| wh, OL_RX_ERR_UNKNOWN_PEER); \ |
| } while (false) |
| |
| #define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) \ |
| do { \ |
| enum ol_rx_err_type err_type = OL_RX_ERR_NONE; \ |
| if (rx_status == htt_rx_status_decrypt_err) \ |
| err_type = OL_RX_ERR_DECRYPT; \ |
| else if (rx_status == htt_rx_status_tkip_mic_err) \ |
| err_type = OL_RX_ERR_TKIP_MIC; \ |
| else if (rx_status == htt_rx_status_mpdu_length_err) \ |
| err_type = OL_RX_ERR_MPDU_LENGTH; \ |
| else if (rx_status == htt_rx_status_mpdu_encrypt_required_err) \ |
| err_type = OL_RX_ERR_ENCRYPT_REQUIRED; \ |
| else if (rx_status == htt_rx_status_err_dup) \ |
| err_type = OL_RX_ERR_DUP; \ |
| else if (rx_status == htt_rx_status_err_fcs) \ |
| err_type = OL_RX_ERR_FCS; \ |
| else \ |
| err_type = OL_RX_ERR_UNKNOWN; \ |
| \ |
| if (vdev != NULL && peer != NULL) { \ |
| OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, \ |
| rx_mpdu_desc, err_type); \ |
| } else { \ |
| OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu); \ |
| } \ |
| } while (false) |
| #else |
| #define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) |
| #define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) |
| #define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) |
| #endif /* SUPPORT_HOST_STATISTICS */ |
| |
| #ifdef QCA_ENABLE_OL_TXRX_PEER_STATS |
| #define OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, type, msdu) \ |
| do { \ |
| qdf_spin_lock_bh(&peer->vdev->pdev->peer_stat_mutex); \ |
| peer->stats.tx_or_rx.frms.type += 1; \ |
| peer->stats.tx_or_rx.bytes.type += qdf_nbuf_len(msdu); \ |
| qdf_spin_unlock_bh(&peer->vdev->pdev->peer_stat_mutex); \ |
| } while (0) |
| #define OL_TXRX_PEER_STATS_UPDATE(peer, tx_or_rx, msdu) \ |
| do { \ |
| struct ol_txrx_vdev_t *vdev = peer->vdev; \ |
| struct ol_txrx_pdev_t *pdev = vdev->pdev; \ |
| uint8_t *dest_addr; \ |
| if (pdev->frame_format == wlan_frm_fmt_802_3) { \ |
| dest_addr = qdf_nbuf_data(msdu); \ |
| } else { /* 802.11 format */ \ |
| struct ieee80211_frame *frm; \ |
| frm = (struct ieee80211_frame *) qdf_nbuf_data(msdu); \ |
| if (vdev->opmode == wlan_op_mode_ap) { \ |
| dest_addr = (uint8_t *) &(frm->i_addr1[0]); \ |
| } else { \ |
| dest_addr = (uint8_t *) &(frm->i_addr3[0]); \ |
| } \ |
| } \ |
| if (qdf_unlikely(IEEE80211_IS_BROADCAST(dest_addr))) { \ |
| OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ |
| bcast, msdu); \ |
| } else if (qdf_unlikely(IEEE80211_IS_MULTICAST(dest_addr))) { \ |
| OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ |
| mcast, msdu); \ |
| } else { \ |
| OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ |
| ucast, msdu); \ |
| } \ |
| } while (0) |
| #define OL_TX_PEER_STATS_UPDATE(peer, msdu) \ |
| OL_TXRX_PEER_STATS_UPDATE(peer, tx, msdu) |
| #define OL_RX_PEER_STATS_UPDATE(peer, msdu) \ |
| OL_TXRX_PEER_STATS_UPDATE(peer, rx, msdu) |
| #define OL_TXRX_PEER_STATS_MUTEX_INIT(pdev) \ |
| qdf_spinlock_create(&pdev->peer_stat_mutex) |
| #define OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev) \ |
| qdf_spinlock_destroy(&pdev->peer_stat_mutex) |
| #else |
| #define OL_TX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ |
| #define OL_RX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ |
| #define OL_TXRX_PEER_STATS_MUTEX_INIT(peer) /* no-op */ |
| #define OL_TXRX_PEER_STATS_MUTEX_DESTROY(peer) /* no-op */ |
| #endif |
| |
| #ifndef DEBUG_HTT_CREDIT |
| #define DEBUG_HTT_CREDIT 0 |
| #endif |
| |
| #if defined(FEATURE_TSO_DEBUG) |
| #define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) \ |
| do { \ |
| if (_p_cntrs == 1) { \ |
| TXRX_STATS_ADD(_pdev, pub.tx.tso.tso_hist.pkts_1, 1); \ |
| } else if (_p_cntrs >= 2 && _p_cntrs <= 5) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.tso.tso_hist.pkts_2_5, 1); \ |
| } else if (_p_cntrs > 5 && _p_cntrs <= 10) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.tso.tso_hist.pkts_6_10, 1); \ |
| } else if (_p_cntrs > 10 && _p_cntrs <= 15) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.tso.tso_hist.pkts_11_15, 1); \ |
| } else if (_p_cntrs > 15 && _p_cntrs <= 20) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.tso.tso_hist.pkts_16_20, 1); \ |
| } else if (_p_cntrs > 20) { \ |
| TXRX_STATS_ADD(_pdev, \ |
| pub.tx.tso.tso_hist.pkts_20_plus, 1); \ |
| } \ |
| } while (0) |
| |
| #define TXRX_STATS_TSO_RESET_MSDU(pdev, idx) \ |
| do { \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg \ |
| = 0; \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].tso_seg_idx \ |
| = 0; \ |
| } while (0) |
| |
| #define TXRX_STATS_TSO_MSDU_IDX(pdev) \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx |
| |
| #define TXRX_STATS_TSO_MSDU(pdev, idx) \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx] |
| |
| #define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg |
| |
| #define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].gso_size |
| |
| #define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].total_len |
| |
| #define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) \ |
| pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].nr_frags |
| |
| #define TXRX_STATS_TSO_CURR_MSDU(pdev, idx) \ |
| TXRX_STATS_TSO_MSDU(pdev, idx) |
| |
| #define TXRX_STATS_TSO_SEG_IDX(pdev, idx) \ |
| TXRX_STATS_TSO_CURR_MSDU(pdev, idx).tso_seg_idx |
| |
| #define TXRX_STATS_TSO_INC_SEG(pdev, idx) \ |
| do { \ |
| TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg++; \ |
| TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg &= \ |
| NUM_MAX_TSO_SEGS_MASK; \ |
| } while (0) |
| |
| #define TXRX_STATS_TSO_RST_SEG(pdev, idx) \ |
| TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg = 0 |
| |
| #define TXRX_STATS_TSO_RST_SEG_IDX(pdev, idx) \ |
| TXRX_STATS_TSO_CURR_MSDU(pdev, idx).tso_seg_idx = 0 |
| |
| #define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) \ |
| TXRX_STATS_TSO_MSDU(pdev, msdu_idx).tso_segs[seg_idx] |
| |
| #define TXRX_STATS_TSO_CURR_SEG(pdev, idx) \ |
| TXRX_STATS_TSO_SEG(pdev, idx, \ |
| TXRX_STATS_TSO_SEG_IDX(pdev, idx)) \ |
| |
| #define TXRX_STATS_TSO_INC_SEG_IDX(pdev, idx) \ |
| do { \ |
| TXRX_STATS_TSO_SEG_IDX(pdev, idx)++; \ |
| TXRX_STATS_TSO_SEG_IDX(pdev, idx) &= NUM_MAX_TSO_SEGS_MASK; \ |
| } while (0) |
| |
| #define TXRX_STATS_TSO_SEG_UPDATE(pdev, idx, tso_seg) \ |
| (TXRX_STATS_TSO_CURR_SEG(pdev, idx) = tso_seg) |
| |
| #define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, idx, size) \ |
| (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).gso_size = size) |
| |
| #define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, idx, len) \ |
| (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).total_len = len) |
| |
| #define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, idx, frags) \ |
| (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).nr_frags = frags) |
| |
| #else |
| #define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) /* no-op */ |
| #define TXRX_STATS_TSO_RESET_MSDU(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_MSDU_IDX(pdev) /* no-op */ |
| #define TXRX_STATS_TSO_MSDU(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_CURR_MSDU(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_INC_MSDU_IDX(pdev) /* no-op */ |
| #define TXRX_STATS_TSO_SEG_IDX(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) /* no-op */ |
| #define TXRX_STATS_TSO_CURR_SEG(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_INC_SEG_IDX(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_SEG_UPDATE(pdev, idx, tso_seg) /* no-op */ |
| #define TXRX_STATS_TSO_INC_SEG(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_RST_SEG(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_RST_SEG_IDX(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, idx, size) /* no-op */ |
| #define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, idx, len) /* no-op */ |
| #define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, idx, frags) /* no-op */ |
| #define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) /* no-op */ |
| #define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) /* no-op */ |
| |
| #endif /* FEATURE_TSO_DEBUG */ |
| |
| #ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL |
| |
| void |
| ol_txrx_update_group_credit( |
| struct ol_tx_queue_group_t *group, |
| int32_t credit, |
| u_int8_t absolute); |
| #endif |
| |
| #endif /* _OL_TXRX_INTERNAL__H_ */ |