From 72f7ef77cbf1799b142e053b9df57c17fe955620 Mon Sep 17 00:00:00 2001 From: Amit Mehta Date: Thu, 17 Mar 2022 00:39:54 -0700 Subject: [PATCH] qcacld-3.0: Add NUD Tracking APIs to DP component Add NUD tracking APIs to DP component Change-Id: Ib1dccb041b4fc50a2fc4b7eaba9eed6dfc80ea4d CRs-Fixed: 3165120 --- components/dp/core/inc/wlan_dp_main.h | 8 + components/dp/core/inc/wlan_dp_priv.h | 4 + components/dp/core/src/wlan_dp_main.c | 12 +- components/dp/core/src/wlan_dp_nud_tracking.c | 395 ++++++++++++++++++ components/dp/core/src/wlan_dp_nud_tracking.h | 145 ++++++- .../dp/dispatcher/inc/wlan_dp_public_struct.h | 39 ++ .../dp/dispatcher/inc/wlan_dp_ucfg_api.h | 64 +++ .../dp/dispatcher/src/wlan_dp_ucfg_api.c | 61 +++ os_if/dp/inc/os_if_dp.h | 15 + os_if/dp/src/os_if_dp.c | 140 +++++++ 10 files changed, 874 insertions(+), 9 deletions(-) diff --git a/components/dp/core/inc/wlan_dp_main.h b/components/dp/core/inc/wlan_dp_main.h index 9a50f021c9..6614220d82 100644 --- a/components/dp/core/inc/wlan_dp_main.h +++ b/components/dp/core/inc/wlan_dp_main.h @@ -307,6 +307,14 @@ dp_del_latency_critical_client(struct wlan_objmgr_vdev *vdev, } } +/** + * is_dp_intf_valid() - Check if interface is valid + * @dp_intf: DP interface + * + * Return: 0 if interface is valid, else error code + */ +int is_dp_intf_valid(struct wlan_dp_intf *dp_intf); + /** * dp_send_rps_ind() - send rps indication to daemon * @dp_intf: DP interface diff --git a/components/dp/core/inc/wlan_dp_priv.h b/components/dp/core/inc/wlan_dp_priv.h index 8371115dcf..885625c6a9 100644 --- a/components/dp/core/inc/wlan_dp_priv.h +++ b/components/dp/core/inc/wlan_dp_priv.h @@ -33,6 +33,7 @@ #include "qdf_periodic_work.h" #include #include "pld_common.h" +#include "wlan_dp_nud_tracking.h" #ifndef NUM_CPUS #ifdef QCA_CONFIG_SMP @@ -296,6 +297,9 @@ struct wlan_dp_intf { uint32_t mscs_counter; #endif /* WLAN_FEATURE_MSCS */ struct dp_mic_work mic_work; +#ifdef WLAN_NUD_TRACKING + struct dp_nud_tracking_info nud_tracking; +#endif }; /** diff --git a/components/dp/core/src/wlan_dp_main.c b/components/dp/core/src/wlan_dp_main.c index dc734c1401..5d4bd0a7a7 100644 --- a/components/dp/core/src/wlan_dp_main.c +++ b/components/dp/core/src/wlan_dp_main.c @@ -143,13 +143,7 @@ static int validate_interface_id(uint8_t intf_id) return 0; } -/** - * is_dp_intf_valid() - Check if interface is valid - * @dp_intf: interface context - * - * Return: 0 on success, error code on failure - */ -static int is_dp_intf_valid(struct wlan_dp_intf *dp_intf) +int is_dp_intf_valid(struct wlan_dp_intf *dp_intf) { if (!dp_intf) { dp_err("Interface is NULL"); @@ -386,6 +380,7 @@ dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) return status; } + dp_nud_ignore_tracking(dp_intf, false); dp_mic_enable_work(dp_intf); return status; @@ -406,6 +401,9 @@ dp_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) return QDF_STATUS_E_INVAL; } + dp_nud_ignore_tracking(dp_intf, true); + dp_nud_reset_tracking(dp_intf); + dp_nud_flush_work(dp_intf); dp_mic_flush_work(dp_intf); status = wlan_objmgr_vdev_component_obj_detach(vdev, diff --git a/components/dp/core/src/wlan_dp_nud_tracking.c b/components/dp/core/src/wlan_dp_nud_tracking.c index 77a674c114..fdaf668c7a 100644 --- a/components/dp/core/src/wlan_dp_nud_tracking.c +++ b/components/dp/core/src/wlan_dp_nud_tracking.c @@ -30,11 +30,406 @@ #include "wlan_dp_nud_tracking.h" #ifdef WLAN_NUD_TRACKING +/** + * dp_txrx_get_tx_ack_count() - Get Tx Ack count + * @dp_intf: Pointer to dp_intf + * + * Return: number of Tx ack count + */ +static uint32_t dp_txrx_get_tx_ack_count(struct wlan_dp_intf *dp_intf) +{ + return cdp_get_tx_ack_stats(cds_get_context(QDF_MODULE_ID_SOC), + dp_intf->intf_id); +} + +void dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr) +{ + struct wlan_dp_intf *dp_intf = dp_get_vdev_priv_obj(vdev); + + if (!dp_intf) { + dp_err("Unable to get DP Interface"); + return; + } + qdf_mem_copy(dp_intf->nud_tracking.gw_mac_addr.bytes, + gw_mac_addr.bytes, + sizeof(struct qdf_mac_addr)); + dp_intf->nud_tracking.is_gw_updated = true; +} + +void dp_nud_incr_gw_rx_pkt_cnt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr) +{ + struct dp_nud_tracking_info *nud_tracking = &dp_intf->nud_tracking; + + if (!nud_tracking->is_gw_rx_pkt_track_enabled) + return; + + if (!nud_tracking->is_gw_updated) + return; + + if (qdf_is_macaddr_equal(&nud_tracking->gw_mac_addr, + mac_addr)) + qdf_atomic_inc(&nud_tracking->tx_rx_stats.gw_rx_packets); +} + +void dp_nud_flush_work(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + + if (dp_ops->dp_is_link_adapter(dp_ops->callback_ctx, + dp_intf->intf_id)) + return; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("Flush the NUD work"); + qdf_disable_work(&dp_intf->nud_tracking.nud_event_work); + } +} + void dp_nud_deinit_tracking(struct wlan_dp_intf *dp_intf) { + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("DeInitialize the NUD tracking"); + qdf_destroy_work(NULL, &dp_intf->nud_tracking.nud_event_work); + } +} + +void dp_nud_ignore_tracking(struct wlan_dp_intf *dp_intf, bool ignoring) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) + dp_intf->nud_tracking.ignore_nud_tracking = ignoring; +} + +void dp_nud_reset_tracking(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("Reset the NUD tracking"); + + qdf_zero_macaddr(&dp_intf->nud_tracking.gw_mac_addr); + dp_intf->nud_tracking.is_gw_updated = false; + qdf_mem_zero(&dp_intf->nud_tracking.tx_rx_stats, + sizeof(struct dp_nud_tx_rx_stats)); + + dp_intf->nud_tracking.curr_state = DP_NUD_NONE; + qdf_atomic_set(&dp_intf + ->nud_tracking.tx_rx_stats.gw_rx_packets, 0); + } +} + +/** + * dp_nud_stats_info() - display wlan NUD stats info + * @dp_intf: Pointer to dp_intf + * + * Return: None + */ +static void dp_nud_stats_info(struct wlan_dp_intf *dp_intf) +{ + struct wlan_objmgr_vdev *vdev = dp_intf->vdev; + struct dp_nud_tx_rx_stats *tx_rx_stats = + &dp_intf->nud_tracking.tx_rx_stats; + struct wlan_dp_psoc_callbacks *cb = &dp_intf->dp_ctx->dp_ops; + uint32_t pause_map; + + if (!vdev) { + dp_err("vdev is NULL"); + return; + } + + if (dp_comp_vdev_get_ref(vdev)) { + dp_err("vdev ref get error"); + return; + } + + dp_info("**** NUD STATS: ****"); + dp_info("NUD Probe Tx : %d", tx_rx_stats->pre_tx_packets); + dp_info("NUD Probe Ack : %d", tx_rx_stats->pre_tx_acked); + dp_info("NUD Probe Rx : %d", tx_rx_stats->pre_rx_packets); + dp_info("NUD Failure Tx : %d", tx_rx_stats->post_tx_packets); + dp_info("NUD Failure Ack : %d", tx_rx_stats->post_tx_acked); + dp_info("NUD Failure Rx : %d", tx_rx_stats->post_rx_packets); + dp_info("NUD Gateway Rx : %d", + qdf_atomic_read(&tx_rx_stats->gw_rx_packets)); + + cb->os_if_dp_nud_stats_info(dp_intf->vdev); + + pause_map = cb->dp_get_pause_map(cb->callback_ctx, + dp_intf->intf_id); + dp_info("Current pause_map value %x", pause_map); + dp_comp_vdev_put_ref(vdev); +} + +/** + * dp_nud_capture_stats() - capture wlan NUD stats + * @dp_intf: Pointer to dp_intf + * @nud_state: NUD state for which stats to capture + * + * Return: None + */ +static void dp_nud_capture_stats(struct wlan_dp_intf *dp_intf, + uint8_t nud_state) +{ + switch (nud_state) { + case DP_NUD_INCOMPLETE: + case DP_NUD_PROBE: + dp_intf->nud_tracking.tx_rx_stats.pre_tx_packets = + dp_intf->stats.tx_packets; + dp_intf->nud_tracking.tx_rx_stats.pre_rx_packets = + dp_intf->stats.rx_packets; + dp_intf->nud_tracking.tx_rx_stats.pre_tx_acked = + dp_txrx_get_tx_ack_count(dp_intf); + break; + case DP_NUD_FAILED: + dp_intf->nud_tracking.tx_rx_stats.post_tx_packets = + dp_intf->stats.tx_packets; + dp_intf->nud_tracking.tx_rx_stats.post_rx_packets = + dp_intf->stats.rx_packets; + dp_intf->nud_tracking.tx_rx_stats.post_tx_acked = + dp_txrx_get_tx_ack_count(dp_intf); + break; + default: + break; + } +} + +/** + * dp_nud_honour_failure() - check if nud failure to be honored + * @dp_intf: Pointer to dp_intf + * + * Return: true if nud failure to be honored, else false. + */ +static bool dp_nud_honour_failure(struct wlan_dp_intf *dp_intf) +{ + uint32_t tx_transmitted; + uint32_t tx_acked; + uint32_t gw_rx_pkt; + struct dp_nud_tracking_info *nud_tracking = &dp_intf->nud_tracking; + + tx_transmitted = nud_tracking->tx_rx_stats.post_tx_packets - + nud_tracking->tx_rx_stats.pre_tx_packets; + tx_acked = nud_tracking->tx_rx_stats.post_tx_acked - + nud_tracking->tx_rx_stats.pre_tx_acked; + gw_rx_pkt = qdf_atomic_read(&nud_tracking->tx_rx_stats.gw_rx_packets); + + if (!tx_transmitted || !tx_acked || !gw_rx_pkt) { + dp_info("NUD_FAILURE_HONORED [mac:" QDF_MAC_ADDR_FMT "]", + QDF_MAC_ADDR_REF(nud_tracking->gw_mac_addr.bytes)); + dp_nud_stats_info(dp_intf); + return true; + } + dp_info("NUD_FAILURE_NOT_HONORED [mac:" QDF_MAC_ADDR_FMT "]", + QDF_MAC_ADDR_REF(nud_tracking->gw_mac_addr.bytes)); + + dp_nud_stats_info(dp_intf); + + return false; +} + +/** + * dp_nud_set_tracking() - set the NUD tracking info + * @dp_intf: Pointer to dp_intf + * @nud_state: Current NUD state to set + * @capture_enabled: GW Rx packet to be capture or not + * + * Return: None + */ +static void dp_nud_set_tracking(struct wlan_dp_intf *dp_intf, + uint8_t nud_state, + bool capture_enabled) +{ + dp_intf->nud_tracking.curr_state = nud_state; + qdf_atomic_set(&dp_intf->nud_tracking.tx_rx_stats.gw_rx_packets, 0); + dp_intf->nud_tracking.is_gw_rx_pkt_track_enabled = capture_enabled; +} + +/** + * dp_nud_failure_work() - work for nud event + * @data: Pointer to dp_intf + * + * Return: None + */ +static void dp_nud_failure_work(void *data) +{ + struct wlan_dp_intf *dp_intf = data; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->nud_tracking.curr_state != DP_NUD_FAILED) { + dp_info("Not in NUD_FAILED state"); + return; + } + + dp_ctx->dp_ops.dp_nud_failure_work(dp_ctx->dp_ops.callback_ctx, + dp_intf->intf_id); } void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf) { + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("Initialize the NUD tracking"); + + qdf_zero_macaddr(&dp_intf->nud_tracking.gw_mac_addr); + qdf_mem_zero(&dp_intf->nud_tracking.tx_rx_stats, + sizeof(struct dp_nud_tx_rx_stats)); + + dp_intf->nud_tracking.curr_state = DP_NUD_NONE; + dp_intf->nud_tracking.ignore_nud_tracking = false; + dp_intf->nud_tracking.is_gw_updated = false; + + qdf_atomic_init(&dp_intf + ->nud_tracking.tx_rx_stats.gw_rx_packets); + qdf_create_work(0, &dp_intf->nud_tracking.nud_event_work, + dp_nud_failure_work, dp_intf); + } +} + +/** + * dp_nud_process_failure_event() - processing NUD_FAILED event + * @dp_intf: Pointer to dp_intf + * + * Return: None + */ +static void dp_nud_process_failure_event(struct wlan_dp_intf *dp_intf) +{ + uint8_t curr_state; + + curr_state = dp_intf->nud_tracking.curr_state; + if (curr_state == DP_NUD_PROBE || curr_state == DP_NUD_INCOMPLETE) { + dp_nud_capture_stats(dp_intf, DP_NUD_FAILED); + if (dp_nud_honour_failure(dp_intf)) { + dp_intf->nud_tracking.curr_state = DP_NUD_FAILED; + qdf_sched_work(0, &dp_intf + ->nud_tracking.nud_event_work); + } else { + dp_info("NUD_START [0x%x]", DP_NUD_INCOMPLETE); + dp_nud_capture_stats(dp_intf, DP_NUD_INCOMPLETE); + dp_nud_set_tracking(dp_intf, DP_NUD_INCOMPLETE, true); + } + } else { + dp_info("NUD FAILED -> Current State [0x%x]", curr_state); + } +} + +/** + * dp_nud_filter_netevent() - filter netevents for STA interface + * @neighbour: Pointer to neighbour + * @gw_mac_addr: Gateway MAC address + * @nud_state: Current NUD state + * + * Return: None + */ +static void dp_nud_filter_netevent(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, + uint8_t nud_state) +{ + int status; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + if (!dp_ctx) + return; + + dp_intf = dp_get_intf_by_macaddr(dp_ctx, netdev_addr); + + if (!dp_intf) + return; + + status = is_dp_intf_valid(dp_intf); + if (status) + return; + + if (dp_intf->nud_tracking.ignore_nud_tracking) { + dp_info("NUD Tracking is Disabled"); + return; + } + + if (!dp_intf->nud_tracking.is_gw_updated) + return; + + if (dp_intf->device_mode != QDF_STA_MODE) + return; + + if (!ucfg_cm_is_vdev_active(dp_intf->vdev)) { + dp_info("Not in Connected State"); + return; + } + + if (!qdf_is_macaddr_equal(&dp_intf->nud_tracking.gw_mac_addr, + gw_mac_addr)) + return; + + if (dp_ctx->wlan_suspended) { + dp_info("wlan is suspended, ignore NUD event"); + return; + } + + switch (nud_state) { + case DP_NUD_PROBE: + case DP_NUD_INCOMPLETE: + dp_info("DP_NUD_START [0x%x]", nud_state); + dp_nud_capture_stats(dp_intf, nud_state); + dp_nud_set_tracking(dp_intf, nud_state, true); + break; + + case DP_NUD_REACHABLE: + dp_info("DP_NUD_REACHABLE [0x%x]", nud_state); + dp_nud_set_tracking(dp_intf, DP_NUD_NONE, false); + break; + + case DP_NUD_FAILED: + dp_info("DP_NUD_FAILED [0x%x]", nud_state); + /* + * This condition is to handle the scenario where NUD_FAILED + * events are received without any NUD_PROBE/INCOMPLETE event + * post roaming. Nud state is set to NONE as part of roaming. + * NUD_FAILED is not honored when the curr state is any state + * other than NUD_PROBE/INCOMPLETE so post roaming, nud state + * is moved to DP_NUD_PROBE to honor future NUD_FAILED events. + */ + if (dp_intf->nud_tracking.curr_state == DP_NUD_NONE) { + dp_nud_capture_stats(dp_intf, DP_NUD_PROBE); + dp_nud_set_tracking(dp_intf, DP_NUD_PROBE, true); + } else { + dp_nud_process_failure_event(dp_intf); + } + break; + default: + dp_info("NUD Event For Other State [0x%x]", + nud_state); + break; + } +} + +void dp_nud_netevent_cb(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, uint8_t nud_state) +{ + dp_enter(); + dp_nud_filter_netevent(netdev_addr, gw_mac_addr, nud_state); + dp_exit(); +} + +void dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf = dp_get_vdev_priv_obj(vdev); + + if (!dp_intf) { + dp_err("Unable to get DP Interface"); + return; + } + dp_nud_set_tracking(dp_intf, DP_NUD_NONE, false); } #endif diff --git a/components/dp/core/src/wlan_dp_nud_tracking.h b/components/dp/core/src/wlan_dp_nud_tracking.h index 6f4ef14ca0..47dface9a3 100644 --- a/components/dp/core/src/wlan_dp_nud_tracking.h +++ b/components/dp/core/src/wlan_dp_nud_tracking.h @@ -25,6 +25,68 @@ #ifdef WLAN_NUD_TRACKING +/** + * struct dp_nud_tx_rx_stats - Capture tx and rx count during NUD tracking + * @pre_tx_packets: Number of tx packets at NUD_PROBE event + * @pre_tx_acked: Number of tx acked at NUD_PROBE event + * @pre_rx_packets: Number of rx packets at NUD_PROBE event + * @post_tx_packets: Number of tx packets at NUD_FAILED event + * @post_tx_acked: Number of tx acked at NUD_FAILED event + * @post_rx_packets: Number of rx packets at NUD_FAILED event + * @gw_rx_packets: Number of rx packets from the registered gateway + * during the period from NUD_PROBE to NUD_FAILED + */ +struct dp_nud_tx_rx_stats { + uint32_t pre_tx_packets; + uint32_t pre_tx_acked; + uint32_t pre_rx_packets; + uint32_t post_tx_packets; + uint32_t post_tx_acked; + uint32_t post_rx_packets; + qdf_atomic_t gw_rx_packets; +}; + + /** + * struct dp_nud_tracking_info - structure to keep track for NUD information + * @curr_state: current state of NUD machine + * @ignore_nud_tracking: true if nud tracking is not required else false + * @tx_rx_stats: Number of packets during NUD tracking + * @gw_mac_addr: gateway mac address for which NUD events are tracked + * @nud_event_work: work to be scheduled during NUD_FAILED + * @is_gw_rx_pkt_track_enabled: true if rx pkt capturing is enabled for GW, + * else false + * @is_gw_updated: true if GW is updated for NUD Tracking + */ +struct dp_nud_tracking_info { + uint8_t curr_state; + bool ignore_nud_tracking; + struct dp_nud_tx_rx_stats tx_rx_stats; + struct qdf_mac_addr gw_mac_addr; + qdf_work_t nud_event_work; + bool is_gw_rx_pkt_track_enabled; + bool is_gw_updated; +}; + +/** + * dp_nud_set_gateway_addr() - set gateway mac address + * @vdev: vdev handle + * @gw_mac_addr: mac address to be set + * + * Return: none + */ +void dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr); + +/** + * dp_nud_incr_gw_rx_pkt_cnt() - Increment rx count for gateway + * @dp_intf: Pointer to DP interface + * @mac_addr: Gateway mac address + * + * Return: None + */ +void dp_nud_incr_gw_rx_pkt_cnt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr); + /** * dp_nud_init_tracking() - initialize NUD tracking * @dp_intf: Pointer to dp interface @@ -33,6 +95,14 @@ */ void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf); +/** + * dp_nud_reset_tracking() - reset NUD tracking + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_nud_reset_tracking(struct wlan_dp_intf *dp_intf); + /** * dp_nud_deinit_tracking() - deinitialize NUD tracking * @dp_intf: Pointer to dp interface @@ -41,13 +111,84 @@ void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf); */ void dp_nud_deinit_tracking(struct wlan_dp_intf *dp_intf); +/** + * dp_nud_ignore_tracking() - set/reset nud trackig status + * @dp_intf: Pointer to dp interface + * @ignoring: Ignore status to set + * + * Return: None + */ +void dp_nud_ignore_tracking(struct wlan_dp_intf *dp_intf, + bool ignoring); + +/** + * dp_nud_flush_work() - flush pending nud work + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_nud_flush_work(struct wlan_dp_intf *dp_intf); + +/** + * dp_nud_indicate_roam() - reset NUD when roaming happens + * @vdev: vdev handle + * + * Return: None + */ +void dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev); + +/** + * dp_nud_netevent_cb() - netevent callback + * @netdev_addr: netdev_addr + * @gw_mac_addr: Gateway MAC address + * @nud_state : NUD State + * + * Return: None + */ +void dp_nud_netevent_cb(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, uint8_t nud_state); #else +static inline void dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr) +{ +} + +static inline void dp_nud_incr_gw_rx_pkt_cnt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr) +{ +} + static inline void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf) { } +static inline void dp_nud_reset_tracking(struct wlan_dp_intf *dp_intf) +{ +} + static inline void dp_nud_deinit_tracking(struct wlan_dp_intf *dp_intf) { } -#endif -#endif + +static inline void dp_nud_ignore_tracking(struct wlan_dp_intf *dp_intf, + bool status) +{ +} + +static inline void +dp_nud_flush_work(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void +dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +void dp_nud_netevent_cb(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, uint8_t nud_state) +{ +} +#endif /* WLAN_NUD_TRACKING */ +#endif /* end of _WLAN_NUD_TRACKING_H_ */ diff --git a/components/dp/dispatcher/inc/wlan_dp_public_struct.h b/components/dp/dispatcher/inc/wlan_dp_public_struct.h index 8eb9bdb266..eb291afdd5 100644 --- a/components/dp/dispatcher/inc/wlan_dp_public_struct.h +++ b/components/dp/dispatcher/inc/wlan_dp_public_struct.h @@ -32,6 +32,24 @@ #include #include +#ifdef TX_MULTIQ_PER_AC +#define TX_GET_QUEUE_IDX(ac, off) (((ac) * TX_QUEUES_PER_AC) + (off)) +#define TX_QUEUES_PER_AC 4 +#else +#define TX_GET_QUEUE_IDX(ac, off) (ac) +#define TX_QUEUES_PER_AC 1 +#endif + +/** Number of Tx Queues */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || \ + defined(QCA_HL_NETDEV_FLOW_CONTROL) || \ + defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/* Only one HI_PRIO queue */ +#define NUM_TX_QUEUES (4 * TX_QUEUES_PER_AC + 1) +#else +#define NUM_TX_QUEUES (4 * TX_QUEUES_PER_AC) +#endif + /** * struct dp_mic_info - mic error info in dp * @ta_mac_addr: transmitter mac address @@ -71,6 +89,19 @@ struct dp_mic_work { qdf_spinlock_t lock; }; +enum dp_nud_state { + DP_NUD_NONE, + DP_NUD_INCOMPLETE, + DP_NUD_REACHABLE, + DP_NUD_STALE, + DP_NUD_DELAY, + DP_NUD_PROBE, + DP_NUD_FAILED, + DP_NUD_NOARP, + DP_NUD_PERMANENT, + DP_NUD_STATE_INVALID +}; + /** * typedef hdd_cb_handle - HDD Handle * @@ -253,6 +284,10 @@ union wlan_tp_data { * @wlan_dp_display_netif_queue_history: Callback to display Netif queue history * @osif_dp_process_sta_mic_error: osif callback to process STA MIC error * @osif_dp_process_sap_mic_error: osif callback to process SAP MIC error + * @dp_is_link_adapter: Callback API to check if adapter is link adapter + * @os_if_dp_nud_stats_info: osif callback to print nud stats info + * @dp_get_pause_map: Callback API to get pause map count + * @dp_nud_failure_work: Callback API to handle NUD failuire work */ struct wlan_dp_psoc_callbacks { void (*os_if_dp_gro_rx)(struct sk_buff *skb, uint8_t napi_to_use, @@ -300,6 +335,10 @@ struct wlan_dp_psoc_callbacks { struct wlan_objmgr_vdev *vdev); void (*osif_dp_process_sap_mic_error)(struct dp_mic_error_info *info, struct wlan_objmgr_vdev *vdev); + bool (*dp_is_link_adapter)(hdd_cb_handle context, uint8_t vdev_id); + void (*os_if_dp_nud_stats_info)(struct wlan_objmgr_vdev *vdev); + uint32_t (*dp_get_pause_map)(hdd_cb_handle context, uint8_t vdev_id); + void (*dp_nud_failure_work)(hdd_cb_handle context, uint8_t vdev_id); }; /** diff --git a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h index dc6d48d6e4..d76822b375 100644 --- a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h +++ b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h @@ -33,6 +33,23 @@ #include "pld_common.h" #include #include +#include "wlan_dp_objmgr.h" + +#define DP_IGNORE_NUD_FAIL 0 +#define DP_DISCONNECT_AFTER_NUD_FAIL 1 +#define DP_ROAM_AFTER_NUD_FAIL 2 +#define DP_DISCONNECT_AFTER_ROAM_FAIL 3 + +#ifdef WLAN_NUD_TRACKING +bool +ucfg_dp_is_roam_after_nud_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_dp_is_roam_after_nud_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /** * ucfg_dp_create_intf() - update DP interface MAC address @@ -363,6 +380,53 @@ void ucfg_dp_bus_bw_compute_prev_txrx_stats(struct wlan_objmgr_vdev *vdev); void ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev); +/** + * ucfg_dp_nud_set_gateway_addr() - set gateway mac address + * @vdev: vdev handle + * @gw_mac_addr: mac address to be set + * + * Return: none + */ +void ucfg_dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr); + +/** + * ucfg_dp_nud_event() - netevent callback + * @netdev_addr: netdev_addr + * @gw_mac_addr: Gateway MAC address + * @nud_state : NUD State + * + * Return: None + */ +void ucfg_dp_nud_event(struct qdf_mac_addr *netdev_mac_addr, + struct qdf_mac_addr *gw_mac_addr, + uint8_t nud_state); + +/** + * ucfg_dp_nud_reset_tracking() - reset NUD tracking + * @vdev: vdev handle + * + * Return: None + */ +void ucfg_dp_nud_reset_tracking(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_nud_tracking_enabled - Check if NUD tracking is enabled + * + * @psoc: PSOC Handle + * + * Return : NUD tracking value. + */ +uint8_t ucfg_dp_nud_tracking_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_nud_indicate_roam() - reset NUD when roaming happens + * @vdev: vdev handle + * + * Return: None + */ +void ucfg_dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev); + /** * ucfg_dp_register_hdd_callbacks() - Resiter HDD callbacks with DP component * @psoc: psoc handle diff --git a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c index 03f3cfb375..c8f0110ea8 100644 --- a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c +++ b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c @@ -30,6 +30,7 @@ #include "wlan_dp_objmgr.h" #include "wlan_dp_bus_bandwidth.h" #include "wlan_dp_periodic_sta_stats.h" +#include "wlan_dp_nud_tracking.h" void ucfg_dp_update_inf_mac(struct wlan_objmgr_psoc *psoc, struct qdf_mac_addr *cur_mac, @@ -82,6 +83,7 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc, dp_periodic_sta_stats_init(dp_intf); dp_periodic_sta_stats_mutex_create(dp_intf); + dp_nud_init_tracking(dp_intf); dp_mic_init_work(dp_intf); return QDF_STATUS_SUCCESS; @@ -107,6 +109,7 @@ ucfg_dp_destroy_intf(struct wlan_objmgr_psoc *psoc, } dp_periodic_sta_stats_mutex_destroy(dp_intf); + dp_nud_deinit_tracking(dp_intf); dp_mic_deinit_work(dp_intf); qdf_spin_lock_bh(&dp_ctx->intf_list_lock); @@ -486,6 +489,21 @@ void ucfg_dp_register_rx_mic_error_ind_handler(void *soc) cdp_register_rx_mic_error_ind_handler(soc, dp_rx_mic_error_ind); } +#ifdef WLAN_NUD_TRACKING +bool +ucfg_dp_is_roam_after_nud_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg; + + if (dp_cfg->enable_nud_tracking == DP_ROAM_AFTER_NUD_FAIL || + dp_cfg->enable_nud_tracking == DP_DISCONNECT_AFTER_ROAM_FAIL) + return true; + + return false; +} +#endif + int ucfg_dp_bbm_context_init(struct wlan_objmgr_psoc *psoc) { return dp_bbm_context_init(psoc); @@ -605,6 +623,46 @@ ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) dp_bus_bw_compute_reset_prev_txrx_stats(vdev); } +void ucfg_dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr) +{ + dp_nud_set_gateway_addr(vdev, gw_mac_addr); +} + +void ucfg_dp_nud_event(struct qdf_mac_addr *netdev_mac_addr, + struct qdf_mac_addr *gw_mac_addr, + uint8_t nud_state) +{ + dp_nud_netevent_cb(netdev_mac_addr, gw_mac_addr, nud_state); +} + +void ucfg_dp_nud_reset_tracking(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf = dp_get_vdev_priv_obj(vdev); + + if (!dp_intf) { + dp_err("Unable to get DP Interface"); + return; + } + dp_nud_reset_tracking(dp_intf); +} + +uint8_t ucfg_dp_nud_tracking_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP Context is NULL"); + return 0; + } + return dp_ctx->dp_cfg.enable_nud_tracking; +} + +void ucfg_dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev) +{ + dp_nud_indicate_roam(vdev); +} + void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, struct wlan_dp_psoc_callbacks *cb_obj) { @@ -646,4 +704,7 @@ void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, cb_obj->dp_disable_rx_ol_for_low_tput; dp_ctx->dp_ops.dp_napi_apply_throughput_policy = cb_obj->dp_napi_apply_throughput_policy; + dp_ctx->dp_ops.dp_is_link_adapter = cb_obj->dp_is_link_adapter; + dp_ctx->dp_ops.dp_get_pause_map = cb_obj->dp_get_pause_map; + dp_ctx->dp_ops.dp_nud_failure_work = cb_obj->dp_nud_failure_work; } diff --git a/os_if/dp/inc/os_if_dp.h b/os_if/dp/inc/os_if_dp.h index dcbf6912f6..a0302b020d 100644 --- a/os_if/dp/inc/os_if_dp.h +++ b/os_if/dp/inc/os_if_dp.h @@ -43,4 +43,19 @@ void osif_dp_classify_pkt(struct sk_buff *skb); void os_if_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, struct wlan_dp_psoc_callbacks *cb_obj); +/** + * osif_dp_nud_register_netevent_notifier() - Register netevent notifier + * @psoc: Pointer to psoc context + * + * Return: 0 on success, error code on failure + */ +int osif_dp_nud_register_netevent_notifier(struct wlan_objmgr_psoc *psoc); + +/** + * osif_dp_nud_unregister_netevent_notifier() - Unregister netevent notifier + * @psoc: Pointer to psoc context + * + * Return: None + */ +void osif_dp_nud_unregister_netevent_notifier(struct wlan_objmgr_psoc *psoc); #endif /* __OSIF_DP_H__ */ diff --git a/os_if/dp/src/os_if_dp.c b/os_if/dp/src/os_if_dp.c index 6ca8b50796..666cece525 100644 --- a/os_if/dp/src/os_if_dp.c +++ b/os_if/dp/src/os_if_dp.c @@ -28,6 +28,8 @@ #include "qca_vendor.h" #include "wlan_dp_ucfg_api.h" #include "osif_vdev_sync.h" +#include "osif_sync.h" +#include #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH /** @@ -250,11 +252,149 @@ osif_dp_process_sap_mic_error(struct dp_mic_error_info *info, GFP_KERNEL); } +#ifdef WLAN_NUD_TRACKING +/** + * nud_state_osif_to_dp() - convert os_if to enum + * @curr_state: Current NUD state + * + * Return: DP enum equivalent to NUD state + */ +static inline enum dp_nud_state nud_state_osif_to_dp(uint8_t curr_state) +{ + switch (curr_state) { + case NUD_NONE: + return DP_NUD_NONE; + case NUD_INCOMPLETE: + return DP_NUD_INCOMPLETE; + case NUD_REACHABLE: + return DP_NUD_REACHABLE; + case NUD_STALE: + return DP_NUD_STALE; + case NUD_DELAY: + return DP_NUD_DELAY; + case NUD_PROBE: + return DP_NUD_PROBE; + case NUD_FAILED: + return DP_NUD_FAILED; + case NUD_NOARP: + return DP_NUD_NOARP; + case NUD_PERMANENT: + return DP_NUD_PERMANENT; + default: + return DP_NUD_STATE_INVALID; + } +} + +/** + * os_if_dp_nud_stats_info() - print NUD stats info + * @vdev: vdev handle + * + * Return: None + */ +static void os_if_dp_nud_stats_info(struct wlan_objmgr_vdev *vdev) +{ + struct netdev_queue *txq; + struct net_device *net_dev; + int i = 0, errno; + + errno = osif_dp_get_net_dev_from_vdev(vdev, &net_dev); + if (errno) { + dp_err("failed to get netdev"); + return; + } + dp_info("carrier state: %d", netif_carrier_ok(net_dev)); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(net_dev, i); + dp_info("Queue: %d status: %d txq->trans_start: %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } +} + +/** + * os_if_dp_nud_netevent_cb() - netevent callback + * @nb: Pointer to notifier block + * @event: Net Event triggered + * @data: Pointer to neighbour struct + * + * Callback for netevent + * + * Return: 0 on success + */ +static int os_if_dp_nud_netevent_cb(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct neighbour *neighbor = data; + struct osif_vdev_sync *vdev_sync; + const struct net_device *netdev = neighbor->dev; + int errno; + + errno = osif_vdev_sync_op_start(neighbor->dev, &vdev_sync); + if (errno) + return errno; + + switch (event) { + case NETEVENT_NEIGH_UPDATE: + ucfg_dp_nud_event((struct qdf_mac_addr *)netdev->dev_addr, + (struct qdf_mac_addr *)&neighbor->ha[0], + nud_state_osif_to_dp(neighbor->nud_state)); + break; + default: + break; + } + + osif_vdev_sync_op_stop(vdev_sync); + + return 0; +} + +static struct notifier_block wlan_netevent_nb = { + .notifier_call = os_if_dp_nud_netevent_cb +}; + +int osif_dp_nud_register_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ + int ret = 0; + + if (ucfg_dp_nud_tracking_enabled(psoc)) { + ret = register_netevent_notifier(&wlan_netevent_nb); + if (!ret) + dp_info("Registered netevent notifier"); + } + return ret; +} + +void osif_dp_nud_unregister_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ + int ret = 0; + + if (ucfg_dp_nud_tracking_enabled(psoc)) { + ret = unregister_netevent_notifier(&wlan_netevent_nb); + if (!ret) + dp_info("Unregistered netevent notifier"); + } +} +#else +static void os_if_dp_nud_stats_info(struct wlan_objmgr_vdev *vdev) +{ +} + +int osif_dp_nud_register_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +void osif_dp_nud_unregister_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ +} +#endif void os_if_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, struct wlan_dp_psoc_callbacks *cb_obj) { cb_obj->osif_dp_send_tcp_param_update_event = osif_dp_send_tcp_param_update_event; + cb_obj->os_if_dp_nud_stats_info = os_if_dp_nud_stats_info; cb_obj->osif_dp_process_sta_mic_error = osif_dp_process_sta_mic_error; cb_obj->osif_dp_process_sap_mic_error = osif_dp_process_sap_mic_error;