diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index dab6ab63a7..98f0ada154 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -1965,6 +1965,13 @@ static int dp_soc_cmn_setup(struct dp_soc *soc) reo_params.rx_hash_enabled = true; } + /* setup the global rx defrag waitlist */ + TAILQ_INIT(&soc->rx.defrag.waitlist); + soc->rx.defrag.timeout_ms = + wlan_cfg_get_rx_defrag_min_timeout(soc->wlan_cfg_ctx); + soc->rx.flags.defrag_timeout_check = + wlan_cfg_get_defrag_timeout_check(soc->wlan_cfg_ctx); + out: hal_reo_setup(soc->hal_soc, &reo_params); diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index b64e3277b0..6d2361b656 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -83,7 +83,70 @@ static void dp_rx_clear_saved_desc_info(struct dp_peer *peer, unsigned tid) peer->rx_tid[tid].dst_ring_desc = NULL; } -#ifdef DEFRAG_TIMEOUT +/* + * dp_rx_reorder_flush_frag(): Flush the frag list + * @peer: Pointer to the peer data structure + * @tid: Transmit ID (TID) + * + * Flush the per-TID frag list + * + * Returns: None + */ +void dp_rx_reorder_flush_frag(struct dp_peer *peer, + unsigned int tid) +{ + struct dp_rx_reorder_array_elem *rx_reorder_array_elem; + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("Flushing TID %d"), tid); + + rx_reorder_array_elem = peer->rx_tid[tid].array; + if (rx_reorder_array_elem->head) { + dp_rx_defrag_frames_free(rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } +} + +/* + * dp_rx_defrag_waitlist_flush(): Flush SOC defrag wait list + * @soc: DP SOC + * + * Flush fragments of all waitlisted TID's + * + * Returns: None + */ +void dp_rx_defrag_waitlist_flush(struct dp_soc *soc) +{ + struct dp_rx_tid *rx_reorder, *tmp; + uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + TAILQ_FOREACH_SAFE(rx_reorder, &soc->rx.defrag.waitlist, + defrag_waitlist_elem, tmp) { + struct dp_peer *peer; + struct dp_rx_tid *rx_reorder_base; + unsigned int tid; + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("Current time %u"), now_ms); + + if (rx_reorder->defrag_timeout_ms > now_ms) + break; + + tid = rx_reorder->tid; + /* get index 0 of the rx_reorder array */ + rx_reorder_base = rx_reorder - tid; + peer = + container_of(rx_reorder_base, struct dp_peer, + rx_tid[0]); + + TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); + //dp_rx_defrag_waitlist_remove(peer, tid); + dp_rx_reorder_flush_frag(peer, tid); + } +} + /* * dp_rx_defrag_waitlist_add(): Update per-PDEV defrag wait list * @peer: Pointer to the peer data structure @@ -98,6 +161,9 @@ static void dp_rx_defrag_waitlist_add(struct dp_peer *peer, unsigned tid) struct dp_soc *psoc = peer->vdev->pdev->soc; struct dp_rx_tid *rx_reorder = &peer->rx_tid[tid]; + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("Adding TID %u to waitlist"), tid); + /* TODO: use LIST macros instead of TAIL macros */ TAILQ_INSERT_TAIL(&psoc->rx.defrag.waitlist, rx_reorder, defrag_waitlist_elem); @@ -112,7 +178,7 @@ static void dp_rx_defrag_waitlist_add(struct dp_peer *peer, unsigned tid) * * Returns: None */ -static void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid) +void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid) { struct dp_pdev *pdev = peer->vdev->pdev; struct dp_soc *soc = pdev->soc; @@ -125,23 +191,16 @@ static void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid) return; } - rx_reorder = &peer->rx_tid[tid]; + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("Remove TID %u from waitlist"), tid); - if (rx_reorder->defrag_waitlist_elem.tqe_next != NULL) { - - TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder, - defrag_waitlist_elem); - rx_reorder->defrag_waitlist_elem.tqe_next = NULL; - rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; - } else if (rx_reorder->defrag_waitlist_elem.tqe_prev == NULL) { - - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "waitlist->tqe_prev is NULL"); - rx_reorder->defrag_waitlist_elem.tqe_next = NULL; - qdf_assert(0); + TAILQ_FOREACH(rx_reorder, &soc->rx.defrag.waitlist, + defrag_waitlist_elem) { + if (rx_reorder->tid == tid) + TAILQ_REMOVE(&soc->rx.defrag.waitlist, + rx_reorder, defrag_waitlist_elem); } } -#endif /* * dp_rx_defrag_fraglist_insert(): Create a per-sequence fragment list @@ -1257,17 +1316,18 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, rx_reorder_array_elem->head = NULL; rx_reorder_array_elem->tail = NULL; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s mismatch, dropping earlier sequence ", + (rxseq == rx_tid->curr_seq_num) + ? "address" + : "seq number"); + /* * The sequence number for this fragment becomes the * new sequence number to be processed */ rx_tid->curr_seq_num = rxseq; - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s mismatch, dropping earlier sequence ", - (rxseq == rx_tid->curr_seq_num) - ? "address" - : "seq number"); } } else { /* Start of a new sequence */ @@ -1314,13 +1374,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, } -#ifdef DEFRAG_TIMEOUT - /* TODO: handle fragment timeout gracefully */ - if (pdev->soc->rx.flags.defrag_timeout_check) { + if (pdev->soc->rx.flags.defrag_timeout_check) dp_rx_defrag_waitlist_remove(peer, tid); - goto end; - } -#endif + /* Yet to receive more fragments for this sequence number */ if (!all_frag_present) { uint32_t now_ms = @@ -1329,6 +1385,8 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, peer->rx_tid[tid].defrag_timeout_ms = now_ms + pdev->soc->rx.defrag.timeout_ms; + dp_rx_defrag_waitlist_add(peer, tid); + return QDF_STATUS_SUCCESS; } diff --git a/dp/wifi3.0/dp_rx_defrag.h b/dp/wifi3.0/dp_rx_defrag.h index fe8b13a9d7..57f96027fe 100644 --- a/dp/wifi3.0/dp_rx_defrag.h +++ b/dp/wifi3.0/dp_rx_defrag.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -139,4 +139,8 @@ uint8_t dp_rx_get_pkt_dir(uint8_t *rx_desc_info) return mac_hdr->i_fc[1] & IEEE80211_FC1_DIR_MASK; } +void dp_rx_defrag_waitlist_flush(struct dp_soc *soc); +void dp_rx_reorder_flush_frag(struct dp_peer *peer, + unsigned int tid); +void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid); #endif /* _DP_RX_DEFRAG_H */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index aa28fb9bbc..42263f4c4c 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -879,6 +879,8 @@ dp_rx_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) done: hal_srng_access_end(hal_soc, hal_ring); + if (soc->rx.flags.defrag_timeout_check) + dp_rx_defrag_waitlist_flush(soc); /* Assume MAC id = 0, owner = 0 */ if (rx_bufs_used) { diff --git a/wlan_cfg/wlan_cfg.c b/wlan_cfg/wlan_cfg.c index a23d2b0ba6..baf926d986 100644 --- a/wlan_cfg/wlan_cfg.c +++ b/wlan_cfg/wlan_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -187,6 +187,7 @@ #define WLAN_CFG_HTT_PKT_TYPE 2 #define WLAN_CFG_MAX_PEER_ID 64 +#define WLAN_CFG_RX_DEFRAG_TIMEOUT 100 #ifdef CONFIG_MCL static const int tx_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = { @@ -351,6 +352,9 @@ struct wlan_cfg_dp_soc_ctxt *wlan_cfg_soc_attach() /*Enable checksum offload by default*/ wlan_cfg_ctx->tcp_udp_checksumoffload = 1; + wlan_cfg_ctx->defrag_timeout_check = 1; + wlan_cfg_ctx->rx_defrag_min_timeout = WLAN_CFG_RX_DEFRAG_TIMEOUT; + return wlan_cfg_ctx; } @@ -697,6 +701,17 @@ int wlan_cfg_get_checksum_offload(struct wlan_cfg_dp_soc_ctxt *cfg) { return cfg->tcp_udp_checksumoffload; } + +int wlan_cfg_get_rx_defrag_min_timeout(struct wlan_cfg_dp_soc_ctxt *cfg) +{ + return cfg->rx_defrag_min_timeout; +} + +int wlan_cfg_get_defrag_timeout_check(struct wlan_cfg_dp_soc_ctxt *cfg) +{ + return cfg->defrag_timeout_check; +} + #ifdef QCA_LL_TX_FLOW_CONTROL_V2 /** * wlan_cfg_get_tx_flow_stop_queue_th() - Get flow control stop threshold diff --git a/wlan_cfg/wlan_cfg.h b/wlan_cfg/wlan_cfg.h index 9d030b4f01..802860f776 100644 --- a/wlan_cfg/wlan_cfg.h +++ b/wlan_cfg/wlan_cfg.h @@ -1,5 +1,5 @@ /* -* * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. +* * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -146,11 +146,13 @@ struct wlan_cfg_dp_soc_ctxt { bool tso_enabled; bool napi_enabled; bool tcp_udp_checksumoffload; + bool defrag_timeout_check; int nss_cfg; #ifdef QCA_LL_TX_FLOW_CONTROL_V2 uint32_t tx_flow_stop_queue_threshold; uint32_t tx_flow_start_queue_offset; #endif + uint32_t rx_defrag_min_timeout; }; /** @@ -663,4 +665,7 @@ int wlan_cfg_get_tx_flow_stop_queue_th(struct wlan_cfg_dp_soc_ctxt *cfg); int wlan_cfg_get_tx_flow_start_queue_offset(struct wlan_cfg_dp_soc_ctxt *cfg); #endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ +int wlan_cfg_get_rx_defrag_min_timeout(struct wlan_cfg_dp_soc_ctxt *cfg); + +int wlan_cfg_get_defrag_timeout_check(struct wlan_cfg_dp_soc_ctxt *cfg); #endif