diff --git a/components/dp/core/inc/wlan_dp_priv.h b/components/dp/core/inc/wlan_dp_priv.h index fdf52ae3d5..a8b51ad2e6 100644 --- a/components/dp/core/inc/wlan_dp_priv.h +++ b/components/dp/core/inc/wlan_dp_priv.h @@ -321,7 +321,7 @@ struct wlan_dp_intf { qdf_atomic_t num_active_task; uint32_t sap_tx_block_mask; - uint8_t gro_disallowed[DP_MAX_RX_THREADS]; + qdf_atomic_t gro_disallowed; uint8_t gro_flushed[DP_MAX_RX_THREADS]; bool runtime_disable_rx_thread; @@ -430,7 +430,8 @@ struct wlan_dp_psoc_context { struct { qdf_atomic_t rx_aggregation; uint8_t gro_force_flush[DP_MAX_RX_THREADS]; - bool force_gro_enable; + bool tc_based_dyn_gro; + uint32_t tc_ingress_prio; } dp_agg_param; diff --git a/components/dp/core/src/wlan_dp_bus_bandwidth.c b/components/dp/core/src/wlan_dp_bus_bandwidth.c index 62eeed40d5..8a4771f1af 100644 --- a/components/dp/core/src/wlan_dp_bus_bandwidth.c +++ b/components/dp/core/src/wlan_dp_bus_bandwidth.c @@ -1650,6 +1650,48 @@ static void dp_pld_request_bus_bandwidth(struct wlan_dp_psoc_context *dp_ctx, } } +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +/** + * dp_rx_check_qdisc_for_intf() - Check if any ingress qdisc is configured + * for given adapter + * @dp_intf: pointer to DP interface context + * + * The function checks if ingress qdisc is registered for a given + * net device. + * + * Return: None + */ +static void +dp_rx_check_qdisc_for_intf(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_callbacks *dp_ops; + QDF_STATUS status; + + dp_ops = &dp_intf->dp_ctx->dp_ops; + status = dp_ops->dp_rx_check_qdisc_configured(dp_intf->dev, + dp_intf->dp_ctx->dp_agg_param.tc_ingress_prio); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (qdf_likely(qdf_atomic_read(&dp_intf->gro_disallowed))) + return; + + dp_debug("ingress qdisc/filter configured disable GRO"); + qdf_atomic_set(&dp_intf->gro_disallowed, 1); + + return; + } else if (status == QDF_STATUS_E_NOSUPPORT) { + if (qdf_unlikely(qdf_atomic_read(&dp_intf->gro_disallowed))) { + dp_debug("ingress qdisc/filter removed enable GRO"); + qdf_atomic_set(&dp_intf->gro_disallowed, 0); + } + } +} +#else +static void +dp_rx_check_qdisc_for_intf(struct wlan_dp_intf *dp_intf) +{ +} +#endif + /** * __dp_bus_bw_work_handler() - Bus bandwidth work handler * @dp_ctx: handle to DP context @@ -1709,6 +1751,9 @@ static void __dp_bus_bw_work_handler(struct wlan_dp_psoc_context *dp_ctx) continue; } + if (dp_ctx->dp_agg_param.tc_based_dyn_gro) + dp_rx_check_qdisc_for_intf(dp_intf); + tx_packets += DP_BW_GET_DIFF( QDF_NET_DEV_STATS_TX_PKTS(&dp_intf->stats), dp_intf->prev_tx_packets); diff --git a/components/dp/core/src/wlan_dp_txrx.c b/components/dp/core/src/wlan_dp_txrx.c index a169d535f0..537a76c7db 100644 --- a/components/dp/core/src/wlan_dp_txrx.c +++ b/components/dp/core/src/wlan_dp_txrx.c @@ -961,11 +961,13 @@ static QDF_STATUS dp_gro_rx_bh_disable(struct wlan_dp_intf *dp_intf, uint32_t rx_aggregation; uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); uint8_t low_tput_force_flush = 0; + int32_t gro_disallowed; rx_aggregation = qdf_atomic_read(&dp_ctx->dp_agg_param.rx_aggregation); + gro_disallowed = qdf_atomic_read(&dp_intf->gro_disallowed); if (dp_get_current_throughput_level(dp_ctx) == PLD_BUS_WIDTH_IDLE || - !rx_aggregation || dp_intf->gro_disallowed[rx_ctx_id]) { + !rx_aggregation || gro_disallowed) { status = dp_ctx->dp_ops.dp_rx_napi_gro_flush(napi_to_use, nbuf, &low_tput_force_flush); if (!low_tput_force_flush) @@ -973,7 +975,7 @@ static QDF_STATUS dp_gro_rx_bh_disable(struct wlan_dp_intf *dp_intf, rx_gro_low_tput_flush++; if (!rx_aggregation) dp_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] = 1; - if (dp_intf->gro_disallowed[rx_ctx_id]) + if (gro_disallowed) dp_intf->gro_flushed[rx_ctx_id] = 1; } else { status = dp_ctx->dp_ops.dp_rx_napi_gro_receive(napi_to_use, @@ -1400,58 +1402,6 @@ void wlan_dp_set_fisa_disallowed_for_vdev(ol_txrx_soc_handle soc, #endif #ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION -/** - * dp_rx_check_qdisc_for_intf() - Check if any ingress qdisc is configured - * for given adapter - * @dp_intf: pointer to DP interface context - * @rx_ctx_id: Rx context id - * - * The function checks if ingress qdisc is registered for a given - * net device. - * - * Return: None - */ -static void -dp_rx_check_qdisc_for_intf(struct wlan_dp_intf *dp_intf, - uint8_t rx_ctx_id) -{ - ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); - struct wlan_dp_psoc_callbacks *dp_ops; - QDF_STATUS status; - - /* - * Restrict the qdisc based dynamic GRO enable/disable to - * standalone STA mode only. Reset the configuration for - * any other device mode or concurrency. - */ - if (dp_intf->device_mode != QDF_STA_MODE || - (qdf_atomic_read(&dp_intf->dp_ctx->rx_skip_qdisc_chk_conc))) - goto reset_wl; - - dp_ops = &dp_intf->dp_ctx->dp_ops; - status = dp_ops->dp_rx_check_qdisc_configured(dp_intf->dev, - rx_ctx_id); - if (QDF_IS_STATUS_SUCCESS(status)) { - if (qdf_likely(dp_intf->gro_disallowed[rx_ctx_id])) - return; - - dp_debug("ingress qdisc/filter configured disable GRO"); - dp_intf->gro_disallowed[rx_ctx_id] = 1; - wlan_dp_set_fisa_disallowed_for_vdev(soc, dp_intf->intf_id, - rx_ctx_id, 1); - return; - } - -reset_wl: - if (qdf_unlikely(dp_intf->gro_disallowed[rx_ctx_id])) { - dp_debug("ingress qdisc/filter removed enable GRO"); - wlan_dp_set_fisa_disallowed_for_vdev(soc, dp_intf->intf_id, - rx_ctx_id, 0); - dp_intf->gro_disallowed[rx_ctx_id] = 0; - dp_intf->gro_flushed[rx_ctx_id] = 0; - } -} - QDF_STATUS wlan_dp_rx_deliver_to_stack(struct wlan_dp_intf *dp_intf, qdf_nbuf_t nbuf) { @@ -1461,15 +1411,29 @@ QDF_STATUS wlan_dp_rx_deliver_to_stack(struct wlan_dp_intf *dp_intf, bool nbuf_receive_offload_ok = false; enum dp_nbuf_push_type push_type; uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); - - if (!dp_ctx->dp_agg_param.force_gro_enable) - /* rx_ctx_id is already verified for out-of-range */ - dp_rx_check_qdisc_for_intf(dp_intf, rx_ctx_id); + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + int32_t gro_disallowed; if (QDF_NBUF_CB_RX_TCP_PROTO(nbuf) && !QDF_NBUF_CB_RX_PEER_CACHED_FRM(nbuf)) nbuf_receive_offload_ok = true; + gro_disallowed = qdf_atomic_read(&dp_intf->gro_disallowed); + if (gro_disallowed == 0 && + dp_intf->gro_flushed[rx_ctx_id] != 0) { + if (qdf_likely(soc)) + wlan_dp_set_fisa_disallowed_for_vdev(soc, + dp_intf->intf_id, + rx_ctx_id, 0); + dp_intf->gro_flushed[rx_ctx_id] = 0; + } else if (gro_disallowed && + dp_intf->gro_flushed[rx_ctx_id] == 0) { + if (qdf_likely(soc)) + wlan_dp_set_fisa_disallowed_for_vdev(soc, + dp_intf->intf_id, + rx_ctx_id, 1); + } + if (nbuf_receive_offload_ok && dp_ctx->receive_offload_cb && !dp_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] && !dp_intf->gro_flushed[rx_ctx_id] && diff --git a/components/dp/dispatcher/inc/wlan_dp_public_struct.h b/components/dp/dispatcher/inc/wlan_dp_public_struct.h index 667433efb3..e84b58aa35 100644 --- a/components/dp/dispatcher/inc/wlan_dp_public_struct.h +++ b/components/dp/dispatcher/inc/wlan_dp_public_struct.h @@ -618,7 +618,7 @@ struct wlan_dp_psoc_callbacks { void (*dp_register_rx_offld_flush_cb)(enum dp_rx_offld_flush_cb type); QDF_STATUS (*dp_rx_check_qdisc_configured)(qdf_netdev_t dev, - uint8_t rx_ctx_id); + uint32_t prio); bool (*dp_is_gratuitous_arp_unsolicited_na)(qdf_nbuf_t nbuf); diff --git a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h index 3e28fa5832..328f45005d 100644 --- a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h +++ b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h @@ -256,19 +256,16 @@ bool ucfg_dp_is_ol_enabled(struct wlan_objmgr_psoc *psoc); /** * ucfg_dp_rx_handle_concurrency() - Handle concurrency setting in DP * @psoc: PSOC mapped to DP context - * @is_wifi3_0_target: true if it is wifi3.0 target - * @is_concurrency: Is concurrency enabled/disabled + * @disable: true/false to disable/enable the Rx offload * * Return: None */ void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, - bool is_wifi3_0_target, - bool is_concurrency); + bool disable); #else static inline void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, - bool is_wifi3_0_target, - bool is_concurrency) { } + bool disable) { } #endif /** @@ -1124,13 +1121,13 @@ void ucfg_dp_set_rx_aggregation_val(struct wlan_objmgr_psoc *psoc, uint32_t value); /** - * ucfg_dp_set_force_gro_enable() - Set force gro enable + * ucfg_dp_set_tc_based_dyn_gro() - Set tc based dynamic gro * @psoc: psoc handle * @value : value to be set * * Return: None */ -void ucfg_dp_set_force_gro_enable(struct wlan_objmgr_psoc *psoc, bool value); +void ucfg_dp_set_tc_based_dyn_gro(struct wlan_objmgr_psoc *psoc, bool value); /** * ucfg_dp_runtime_disable_rx_thread() - Disable rx thread @@ -1149,4 +1146,13 @@ void ucfg_dp_runtime_disable_rx_thread(struct wlan_objmgr_vdev *vdev, * Return: true if NAPI enabled */ bool ucfg_dp_get_napi_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_set_tc_ingress_prio() - Set tc ingress priority + * @psoc: psoc handle mapped to DP context + * @value: value to be set + * + * Return: None + */ +void ucfg_dp_set_tc_ingress_prio(struct wlan_objmgr_psoc *psoc, uint32_t value); #endif /* _WLAN_DP_UCFG_API_H_ */ diff --git a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c index 42bbb2a989..93be7ba6e9 100644 --- a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c +++ b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c @@ -91,6 +91,7 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc, dp_nud_init_tracking(dp_intf); dp_mic_init_work(dp_intf); qdf_atomic_init(&dp_ctx->num_latency_critical_clients); + qdf_atomic_init(&dp_intf->gro_disallowed); return QDF_STATUS_SUCCESS; } @@ -678,8 +679,7 @@ bool ucfg_dp_is_ol_enabled(struct wlan_objmgr_psoc *psoc) #ifdef RECEIVE_OFFLOAD void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, - bool is_wifi3_0_target, - bool is_concurrency) + bool disable) { struct wlan_dp_psoc_context *dp_ctx; @@ -689,23 +689,7 @@ void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, return; } - if (is_wifi3_0_target) { - /* - * Donot disable rx offload on concurrency for lithium and - * beryllium based targets - */ - if (is_concurrency) - qdf_atomic_set(&dp_ctx->rx_skip_qdisc_chk_conc, 1); - else - qdf_atomic_set(&dp_ctx->rx_skip_qdisc_chk_conc, 0); - - return; - } - - if (!dp_ctx->ol_enable) - return; - - if (is_concurrency) { + if (disable) { if (DP_BUS_BW_CFG(dp_ctx->dp_cfg.enable_tcp_delack)) { struct wlan_rx_tp_data rx_tp_data; @@ -2048,7 +2032,7 @@ void ucfg_dp_set_rx_aggregation_val(struct wlan_objmgr_psoc *psoc, qdf_atomic_set(&dp_ctx->dp_agg_param.rx_aggregation, !!value); } -void ucfg_dp_set_force_gro_enable(struct wlan_objmgr_psoc *psoc, bool value) +void ucfg_dp_set_tc_based_dyn_gro(struct wlan_objmgr_psoc *psoc, bool value) { struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); @@ -2056,7 +2040,7 @@ void ucfg_dp_set_force_gro_enable(struct wlan_objmgr_psoc *psoc, bool value) dp_err("DP ctx is NULL"); return; } - dp_ctx->dp_agg_param.force_gro_enable = value; + dp_ctx->dp_agg_param.tc_based_dyn_gro = value; } void ucfg_dp_runtime_disable_rx_thread(struct wlan_objmgr_vdev *vdev, @@ -2081,3 +2065,14 @@ bool ucfg_dp_get_napi_enabled(struct wlan_objmgr_psoc *psoc) } return dp_ctx->napi_enable; } + +void ucfg_dp_set_tc_ingress_prio(struct wlan_objmgr_psoc *psoc, uint32_t value) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return; + } + dp_ctx->dp_agg_param.tc_ingress_prio = value; +} diff --git a/components/target_if/dp/src/target_if_dp_comp.c b/components/target_if/dp/src/target_if_dp_comp.c index de535a806b..de9e0ddf62 100644 --- a/components/target_if/dp/src/target_if_dp_comp.c +++ b/components/target_if/dp/src/target_if_dp_comp.c @@ -320,6 +320,7 @@ target_if_dp_send_dhcp_ind(uint16_t vdev_id, struct wmi_unified *wmi_handle; struct wlan_objmgr_psoc *psoc; wmi_peer_set_param_cmd_fixed_param peer_set_param_fp = {0}; + QDF_STATUS status; psoc = wlan_objmgr_get_psoc_by_id(0, WLAN_PSOC_TARGET_IF_ID); if (!psoc) { @@ -345,8 +346,11 @@ target_if_dp_send_dhcp_ind(uint16_t vdev_id, WMI_CHAR_ARRAY_TO_MAC_ADDR(dhcp_ind->peer_mac_addr.bytes, &peer_set_param_fp.peer_macaddr); - return wmi_unified_process_dhcp_ind(wmi_handle, - &peer_set_param_fp); + status = wmi_unified_process_dhcp_ind(wmi_handle, + &peer_set_param_fp); + wlan_objmgr_psoc_release_ref(psoc, WLAN_PSOC_TARGET_IF_ID); + + return status; } void target_if_dp_register_tx_ops(struct wlan_dp_psoc_sb_ops *sb_ops) diff --git a/os_if/dp/inc/os_if_dp.h b/os_if/dp/inc/os_if_dp.h index 21f80a513d..8b590e80de 100644 --- a/os_if/dp/inc/os_if_dp.h +++ b/os_if/dp/inc/os_if_dp.h @@ -26,6 +26,20 @@ #include "wlan_dp_public_struct.h" #include +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +/** + * enum qdisc_filter_status - QDISC filter status + * @QDISC_FILTER_RTNL_LOCK_FAIL: rtnl lock acquire failed + * @QDISC_FILTER_PRIO_MATCH: qdisc filter with priority match + * @QDISC_FILTER_PRIO_MISMATCH: no filter match with configured priority + */ +enum qdisc_filter_status { + QDISC_FILTER_RTNL_LOCK_FAIL, + QDISC_FILTER_PRIO_MATCH, + QDISC_FILTER_PRIO_MISMATCH, +}; +#endif + /** * osif_dp_classify_pkt() - classify packet * @skb - sk buff diff --git a/os_if/dp/src/os_if_dp_txrx.c b/os_if/dp/src/os_if_dp_txrx.c index d8629860e4..0cfabfb051 100644 --- a/os_if/dp/src/os_if_dp_txrx.c +++ b/os_if/dp/src/os_if_dp_txrx.c @@ -299,36 +299,94 @@ static void osif_dp_qdf_lro_flush(void *data) #endif #ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static enum qdisc_filter_status +__osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block, + uint32_t prio) +{ + struct tcf_chain *chain; + struct tcf_proto *tp; + struct tcf_proto *tp_next; + enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH; + + if (!rtnl_trylock()) + return QDISC_FILTER_RTNL_LOCK_FAIL; + + mutex_lock(&block->lock); + list_for_each_entry(chain, &block->chain_list, list) { + mutex_lock(&chain->filter_chain_lock); + tp = tcf_chain_dereference(chain->filter_chain, chain); + while (tp) { + tp_next = rcu_dereference_protected(tp->next, 1); + if (tp->prio == (prio << 16)) { + ret = QDISC_FILTER_PRIO_MATCH; + break; + } + tp = tp_next; + } + mutex_unlock(&chain->filter_chain_lock); + + if (ret == QDISC_FILTER_PRIO_MATCH) + break; + } + mutex_unlock(&block->lock); + rtnl_unlock(); + + return ret; +} +#else +static enum qdisc_filter_status +__osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block, + uint32_t prio) +{ + struct tcf_chain *chain; + struct tcf_proto *tp; + enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH; + + if (!rtnl_trylock()) + return QDISC_FILTER_RTNL_LOCK_FAIL; + + list_for_each_entry(chain, &block->chain_list, list) { + for (tp = rtnl_dereference(chain->filter_chain); tp; + tp = rtnl_dereference(tp->next)) { + if (tp->prio == (prio << 16)) + ret = QDISC_FILTER_PRIO_MATCH; + } + } + rtnl_unlock(); + + return ret; +} +#endif + /** - * osif_dp_is_chain_list_non_empty_for_clsact_qdisc() - Check if chain_list in - * ingress block is non-empty for a clsact qdisc. + * osif_check_for_prio_filter_in_clsact_qdisc() - Check if priority 3 filter + * is configured in the ingress clsact qdisc * @qdisc: pointer to clsact qdisc * - * Return: true if chain_list is not empty else false + * Return: qdisc filter status */ -static bool -osif_dp_is_chain_list_non_empty_for_clsact_qdisc(struct Qdisc *qdisc) +static enum qdisc_filter_status +osif_check_for_prio_filter_in_clsact_qdisc(struct Qdisc *qdisc, uint32_t prio) { const struct Qdisc_class_ops *cops; struct tcf_block *ingress_block; cops = qdisc->ops->cl_ops; if (qdf_unlikely(!cops || !cops->tcf_block)) - return false; + return QDISC_FILTER_PRIO_MISMATCH; ingress_block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL); if (qdf_unlikely(!ingress_block)) - return false; + return QDISC_FILTER_PRIO_MISMATCH; - if (list_empty(&ingress_block->chain_list)) - return false; - else - return true; + return __osif_check_for_prio_filter_in_clsact_qdisc(ingress_block, + prio); } /** - * osif_dp_rx_check_qdisc_for_configured() - Check if any ingress qdisc configured - * for given adapter + * osif_dp_rx_check_qdisc_for_configured() - Check if any ingress qdisc + * configured for given adapter * @dp_intf: pointer to DP interface context * @rx_ctx_id: Rx context id * @@ -338,11 +396,13 @@ osif_dp_is_chain_list_non_empty_for_clsact_qdisc(struct Qdisc *qdisc) * Return: None */ static QDF_STATUS -osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint8_t rx_ctx_id) +osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint32_t prio) { struct netdev_queue *ingress_q; struct Qdisc *ingress_qdisc; struct net_device *dev = (struct net_device *)ndev; + bool disable_gro = false; + enum qdisc_filter_status status; if (!dev->ingress_queue) goto reset_wl; @@ -357,14 +417,27 @@ osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint8_t rx_ctx_id) if (qdf_unlikely(!ingress_qdisc)) goto reset; - if (!(qdf_str_eq(ingress_qdisc->ops->id, "ingress") || - (qdf_str_eq(ingress_qdisc->ops->id, "clsact") && - osif_dp_is_chain_list_non_empty_for_clsact_qdisc(ingress_qdisc)))) - goto reset; + if (qdf_str_eq(ingress_qdisc->ops->id, "ingress")) { + disable_gro = true; + } else if (qdf_str_eq(ingress_qdisc->ops->id, "clsact")) { + status = osif_check_for_prio_filter_in_clsact_qdisc( + ingress_qdisc, + prio); - rcu_read_unlock(); + if (status == QDISC_FILTER_RTNL_LOCK_FAIL) { + rcu_read_unlock(); + return QDF_STATUS_E_AGAIN; + } else if (status == QDISC_FILTER_PRIO_MISMATCH) { + goto reset; + } - return 0; + disable_gro = true; + } + + if (disable_gro) { + rcu_read_unlock(); + return QDF_STATUS_SUCCESS; + } reset: rcu_read_unlock(); @@ -375,7 +448,7 @@ reset_wl: #else static QDF_STATUS -osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint8_t rx_ctx_id) +osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint32_t prio) { return QDF_STATUS_E_NOSUPPORT; }