From 534a143d8f2d0ba61510032c236c76934689dfaa Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 24 Oct 2019 06:44:11 +0530 Subject: [PATCH] qcacmn: Add support to flush rx packets for a vdev When a particular vdev is deleted, the corresponding rx packets which have been queued to the rx thread are not flushed. Hence when such packets are submitted to the network stack, the dev for this skb will be invalid, since we have already freed the adapter. Flush out the packets in the rx thread queues, before deleting the vdev. CRs-Fixed: 2543392 Change-Id: I2490d0f5ce965f62152613a17a59232521ca058f --- dp/inc/cdp_txrx_cmn_struct.h | 9 ++++++++ dp/wifi3.0/dp_main.c | 2 ++ dp/wifi3.0/dp_rx.c | 18 ++++++++++++++- dp/wifi3.0/dp_rx.h | 9 ++++++++ dp/wifi3.0/dp_types.h | 2 ++ qdf/inc/qdf_nbuf.h | 41 ++++++++++++++++++++++++++++++++++ qdf/linux/src/i_qdf_nbuf.h | 43 ++++++++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 1 deletion(-) diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 885b2a4dcf1c..2b6ec910800c 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -671,6 +671,14 @@ typedef bool (*ol_txrx_tx_flow_control_is_pause_fp)(void *osif_dev); */ typedef QDF_STATUS(*ol_txrx_rx_fp)(void *osif_dev, qdf_nbuf_t msdu_list); +/** + * ol_txrx_rx_flush_fp - receive function to hand batches of data + * frames from txrx to OS shim + * @osif_dev: handle to the OSIF virtual device object + * @vdev_id: vdev_if of the packets to be flushed + */ +typedef QDF_STATUS(*ol_txrx_rx_flush_fp)(void *osif_dev, uint8_t vdev_id); + /** * ol_txrx_rx_gro_flush_ind - function to send GRO flush indication to stack * for a given RX Context Id. @@ -832,6 +840,7 @@ struct ol_txrx_ops { struct { ol_txrx_rx_fp rx; ol_txrx_rx_fp rx_stack; + ol_txrx_rx_flush_fp rx_flush; ol_txrx_rx_gro_flush_ind_fp rx_gro_flush; ol_txrx_rx_check_wai_fp wai_check; ol_txrx_rx_mon_fp mon; diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 12a298411698..9f8ad3290dd8 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -4869,6 +4869,7 @@ static void dp_vdev_register_wifi3(struct cdp_vdev *vdev_handle, vdev->ctrl_vdev = ctrl_vdev; vdev->osif_rx = txrx_ops->rx.rx; vdev->osif_rx_stack = txrx_ops->rx.rx_stack; + vdev->osif_rx_flush = txrx_ops->rx.rx_flush; vdev->osif_gro_flush = txrx_ops->rx.rx_gro_flush; vdev->osif_rsim_rx_decap = txrx_ops->rx.rsim_rx_decap; vdev->osif_get_key = txrx_ops->get_key; @@ -5085,6 +5086,7 @@ static void dp_vdev_detach_wifi3(struct cdp_vdev *vdev_handle, qdf_spin_lock_bh(&pdev->vdev_list_lock); dp_tx_vdev_detach(vdev); + dp_rx_vdev_detach(vdev); /* remove the vdev from its parent pdev's list */ TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem); QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH, diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 049447d0cc69..4c9dd0ff921c 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -2268,8 +2268,24 @@ done: return rx_bufs_used; /* Assume no scale factor for now */ } +QDF_STATUS dp_rx_vdev_detach(struct dp_vdev *vdev) +{ + QDF_STATUS ret; + + if (vdev->osif_rx_flush) { + ret = vdev->osif_rx_flush(vdev->osif_vdev, vdev->vdev_id); + if (!ret) { + dp_err("Failed to flush rx pkts for vdev %d\n", + vdev->vdev_id); + return ret; + } + } + + return QDF_STATUS_SUCCESS; +} + /** - * dp_rx_detach() - detach dp rx + * dp_rx_pdev_detach() - detach dp rx * @pdev: core txrx pdev context * * This function will detach DP RX into main device context diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 0303695ccff6..3940f34bf650 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -445,6 +445,15 @@ void dp_rx_pdev_detach(struct dp_pdev *pdev); void dp_print_napi_stats(struct dp_soc *soc); +/** + * dp_rx_vdev_detach() - detach vdev from dp rx + * @vdev: virtual device instance + * + * Return: QDF_STATUS_SUCCESS: success + * QDF_STATUS_E_RESOURCES: Error return + */ +QDF_STATUS dp_rx_vdev_detach(struct dp_vdev *vdev); + uint32_t dp_rx_process(struct dp_intr *int_ctx, hal_ring_handle_t hal_ring_hdl, uint8_t reo_ring_num, diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 25400bbe5ff5..b0c7aab99eb2 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1738,6 +1738,8 @@ struct dp_vdev { ol_txrx_rx_fp osif_rx; /* callback to deliver rx frames to the OS */ ol_txrx_rx_fp osif_rx_stack; + /* call back function to flush out queued rx packets*/ + ol_txrx_rx_flush_fp osif_rx_flush; ol_txrx_rsim_rx_decap_fp osif_rsim_rx_decap; ol_txrx_get_key_fp osif_get_key; ol_txrx_tx_free_ext_fp osif_tx_free_ext; diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h index 154d5952ef6a..b19d0b1a65ef 100644 --- a/qdf/inc/qdf_nbuf.h +++ b/qdf/inc/qdf_nbuf.h @@ -757,6 +757,9 @@ qdf_nbuf_set_send_complete_flag(qdf_nbuf_t buf, bool flag) __qdf_nbuf_set_send_complete_flag(buf, flag); } +#define QDF_NBUF_QUEUE_WALK_SAFE(queue, var, tvar) \ + __qdf_nbuf_queue_walk_safe(queue, var, tvar) + #ifdef NBUF_MAP_UNMAP_DEBUG /** * qdf_nbuf_map_check_for_leaks() - check for nbut map leaks @@ -964,6 +967,28 @@ void qdf_nbuf_queue_head_purge(qdf_nbuf_queue_head_t *nbuf_queue_head) return __qdf_nbuf_queue_head_purge(nbuf_queue_head); } +/** + * qdf_nbuf_queue_head_lock() - Acquire the nbuf_queue_head lock + * @head: nbuf_queue_head of the nbuf_list for which lock is to be acquired + * + * Return: void + */ +static inline void qdf_nbuf_queue_head_lock(qdf_nbuf_queue_head_t *head) +{ + __qdf_nbuf_queue_head_lock(head); +} + +/** + * qdf_nbuf_queue_head_unlock() - Release the nbuf queue lock + * @head: nbuf_queue_head of the nbuf_list for which lock is to be release + * + * Return: void + */ +static inline void qdf_nbuf_queue_head_unlock(qdf_nbuf_queue_head_t *head) +{ + __qdf_nbuf_queue_head_unlock(head); +} + static inline void qdf_nbuf_sync_for_cpu(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) { @@ -1866,6 +1891,22 @@ static inline void qdf_nbuf_set_tail_pointer(qdf_nbuf_t buf, int len) __qdf_nbuf_set_tail_pointer(buf, len); } +/** + * qdf_nbuf_unlink_no_lock() - unlink a nbuf from nbuf list + * @buf: Network buf instance + * @list: list to use + * + * This is a lockless version, driver must acquire locks if it + * needs to synchronize + * + * Return: none + */ +static inline void +qdf_nbuf_unlink_no_lock(qdf_nbuf_t buf, qdf_nbuf_queue_head_t *list) +{ + __qdf_nbuf_unlink_no_lock(buf, list); +} + /** * qdf_nbuf_reset() - reset the buffer data and pointer * @buf: Network buf instance diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index 9dae8a7c2520..6b50cb174459 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -705,6 +705,9 @@ typedef void (*qdf_nbuf_free_t)(__qdf_nbuf_t); #define __qdf_nbuf_data_attr_set(skb, data_attr) \ (QDF_NBUF_CB_TX_DATA_ATTR(skb) = (data_attr)) +#define __qdf_nbuf_queue_walk_safe(queue, var, tvar) \ + skb_queue_walk_safe(queue, var, tvar) + /** * __qdf_nbuf_num_frags_init() - init extra frags * @skb: sk buffer @@ -1085,6 +1088,22 @@ __qdf_nbuf_set_tail_pointer(struct sk_buff *skb, int len) skb_set_tail_pointer(skb, len); } +/** + * __qdf_nbuf_unlink_no_lock() - unlink an skb from skb queue + * @skb: Pointer to network buffer + * @list: list to use + * + * This is a lockless version, driver must acquire locks if it + * needs to synchronize + * + * Return: none + */ +static inline void +__qdf_nbuf_unlink_no_lock(struct sk_buff *skb, struct sk_buff_head *list) +{ + __skb_unlink(skb, list); +} + /** * __qdf_nbuf_reset() - reset the buffer data and pointer * @buf: Network buf instance @@ -2204,6 +2223,30 @@ void __qdf_nbuf_queue_head_purge(struct sk_buff_head *skb_queue_head) return skb_queue_purge(skb_queue_head); } +/** + * __qdf_nbuf_queue_head_lock() - Acquire the skb list lock + * @head: skb list for which lock is to be acquired + * + * Return: void + */ +static inline +void __qdf_nbuf_queue_head_lock(struct sk_buff_head *skb_queue_head) +{ + spin_lock_bh(&skb_queue_head->lock); +} + +/** + * __qdf_nbuf_queue_head_unlock() - Release the skb list lock + * @head: skb list for which lock is to be release + * + * Return: void + */ +static inline +void __qdf_nbuf_queue_head_unlock(struct sk_buff_head *skb_queue_head) +{ + spin_unlock_bh(&skb_queue_head->lock); +} + #ifdef CONFIG_NBUF_AP_PLATFORM #include #else