From 2146da30ddd50e9229c3ef4105dc3fdf7146c507 Mon Sep 17 00:00:00 2001 From: Manjunathappa Prakash Date: Thu, 13 Oct 2016 14:47:47 -0700 Subject: [PATCH] qcacmn: Add changes for per NAPI or per Rx CE LRO manager Make changes for per per Rx context LRO manager, this addresses all parallel Rx concurrency issues. There by removes all the contention. Change-Id: I90604ffdf7b7fd930eee636426a4c7fc9b92c7d7 CRs-Fixed: 1079320 --- dp/inc/cdp_txrx_lro.h | 5 +- hif/inc/hif.h | 11 ++- hif/inc/hif_napi.h | 8 +++ hif/src/ce/ce_api.h | 7 +- hif/src/ce/ce_internal.h | 1 + hif/src/ce/ce_main.c | 33 ++++++++- hif/src/ce/ce_service.c | 5 +- hif/src/ce/ce_tasklet.c | 2 + hif/src/hif_main.c | 61 +++++++++++++++-- hif/src/hif_main.h | 1 + hif/src/hif_napi.c | 135 ++++++++++++++++++++++++++++++++++--- qdf/linux/src/i_qdf_nbuf.h | 5 +- 12 files changed, 251 insertions(+), 23 deletions(-) diff --git a/dp/inc/cdp_txrx_lro.h b/dp/inc/cdp_txrx_lro.h index 155d9a7f31a8..46ca71961f27 100644 --- a/dp/inc/cdp_txrx_lro.h +++ b/dp/inc/cdp_txrx_lro.h @@ -32,7 +32,8 @@ #ifndef _CDP_TXRX_LRO_H_ #define _CDP_TXRX_LRO_H_ -void ol_register_lro_flush_cb(void (handler)(void *), void *data); -void ol_deregister_lro_flush_cb(void); +void ol_register_lro_flush_cb(void (lro_flush_cb)(void *), + void *(lro_init_cb)(void)); +void ol_deregister_lro_flush_cb(void (lro_deinit_cb)(void *)); #endif /* _CDP_TXRX_LRO_H_ */ diff --git a/hif/inc/hif.h b/hif/inc/hif.h index 62490907c616..6bd63762a4c4 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -182,6 +182,10 @@ struct qca_napi_info { uint8_t id; int irq; struct qca_napi_stat stats[NR_CPUS]; + /* will only be present for data rx CE's */ + void (*lro_flush_cb)(void *); + void *lro_ctx; + qdf_spinlock_t lro_unloading_lock; }; /** @@ -696,8 +700,10 @@ void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx); void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision, const char **target_name); void hif_lro_flush_cb_register(struct hif_opaque_softc *scn, - void (handler)(void *), void *data); -void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn); + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)); +void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn, + void (lro_deinit_cb)(void *)); bool hif_needs_bmi(struct hif_opaque_softc *scn); enum qdf_bus_type hif_get_bus_type(struct hif_opaque_softc *hif_hdl); struct hif_target_info *hif_get_target_info_handle(struct hif_opaque_softc * @@ -734,6 +740,7 @@ int hif_bus_reset_resume(struct hif_opaque_softc *scn); void hif_set_attribute(struct hif_opaque_softc *osc, uint8_t hif_attrib); +void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl); #ifdef WLAN_SUSPEND_RESUME_TEST typedef void (*hif_fake_resume_callback)(uint32_t val); void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx, diff --git a/hif/inc/hif_napi.h b/hif/inc/hif_napi.h index 69255d36ebf9..b81895d86299 100644 --- a/hif/inc/hif_napi.h +++ b/hif/inc/hif_napi.h @@ -77,13 +77,21 @@ enum qca_napi_event { NAPI_EVT_USR_NORMAL }; + /** * Macros to map ids -returned by ...create()- to pipes and vice versa */ #define NAPI_ID2PIPE(i) ((i)-1) #define NAPI_PIPE2ID(p) ((p)+1) +int hif_napi_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)); +void hif_napi_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)); + +void *hif_napi_get_lro_info(struct hif_opaque_softc *hif_hdl, int napi_id); #ifdef FEATURE_NAPI /** diff --git a/hif/src/ce/ce_api.h b/hif/src/ce/ce_api.h index d11354163f0f..46766d700cc0 100644 --- a/hif/src/ce/ce_api.h +++ b/hif/src/ce/ce_api.h @@ -479,10 +479,13 @@ static inline void ce_pkt_error_count_incr( } bool ce_check_rx_pending(struct CE_state *CE_state); +void *hif_ce_get_lro_ctx(struct hif_opaque_softc *hif_hdl, int ctx_id); #if defined(FEATURE_LRO) int ce_lro_flush_cb_register(struct hif_opaque_softc *scn, - void (handler)(void *), void *data); -int ce_lro_flush_cb_deregister(struct hif_opaque_softc *scn); + void (handler)(void *), + void *(lro_init_handler)(void)); +int ce_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)); #endif struct ce_ops *ce_services_srng(void); struct ce_ops *ce_services_legacy(void); diff --git a/hif/src/ce/ce_internal.h b/hif/src/ce/ce_internal.h index f90b3f6a5ae1..d990a2a5b9e8 100644 --- a/hif/src/ce/ce_internal.h +++ b/hif/src/ce/ce_internal.h @@ -150,6 +150,7 @@ struct CE_state { bool htt_rx_data; void (*lro_flush_cb)(void *); void *lro_data; + qdf_spinlock_t lro_unloading_lock; }; /* Descriptor rings must be aligned to this boundary */ diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index 91ad5bb33f63..1b6af1afc5d6 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -756,6 +756,7 @@ struct CE_handle *ce_init(struct hif_softc *scn, CE_state->ctrl_addr = ctrl_addr; CE_state->state = CE_RUNNING; CE_state->attr_flags = attr->flags; + qdf_spinlock_create(&CE_state->lro_unloading_lock); } CE_state->scn = scn; @@ -2497,6 +2498,18 @@ u32 shadow_dst_wr_ind_addr(struct hif_softc *scn, u32 ctrl_addr) #endif #if defined(FEATURE_LRO) +void *hif_ce_get_lro_ctx(struct hif_opaque_softc *hif_hdl, int ctx_id) +{ + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + + QDF_ASSERT(scn != NULL); + + ce_state = scn->ce_id_to_state[ctx_id]; + + return ce_state->lro_data; +} + /** * ce_lro_flush_cb_register() - register the LRO flush * callback @@ -2509,12 +2522,14 @@ u32 shadow_dst_wr_ind_addr(struct hif_softc *scn, u32 ctrl_addr) * Return: Number of instances the callback is registered for */ int ce_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, - void (handler)(void *), void *data) + void (handler)(void *), + void *(lro_init_handler)(void)) { int rc = 0; int i; struct CE_state *ce_state; struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + void *data = NULL; QDF_ASSERT(scn != NULL); @@ -2522,6 +2537,12 @@ int ce_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, for (i = 0; i < scn->ce_count; i++) { ce_state = scn->ce_id_to_state[i]; if ((ce_state != NULL) && (ce_state->htt_rx_data)) { + data = lro_init_handler(); + if (data == NULL) { + HIF_ERROR("%s: Failed to init LRO for CE %d", + __func__, i); + continue; + } ce_state->lro_flush_cb = handler; ce_state->lro_data = data; rc++; @@ -2542,7 +2563,8 @@ int ce_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, * * Return: Number of instances the callback is de-registered */ -int ce_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl) +int ce_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)) { int rc = 0; int i; @@ -2554,8 +2576,15 @@ int ce_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl) for (i = 0; i < scn->ce_count; i++) { ce_state = scn->ce_id_to_state[i]; if ((ce_state != NULL) && (ce_state->htt_rx_data)) { + qdf_spin_lock_bh( + &ce_state->lro_unloading_lock); ce_state->lro_flush_cb = NULL; + lro_deinit_cb(ce_state->lro_data); ce_state->lro_data = NULL; + qdf_spin_unlock_bh( + &ce_state->lro_unloading_lock); + qdf_spinlock_destroy( + &ce_state->lro_unloading_lock); rc++; } } diff --git a/hif/src/ce/ce_service.c b/hif/src/ce/ce_service.c index 61d603152de3..66e293890309 100644 --- a/hif/src/ce/ce_service.c +++ b/hif/src/ce/ce_service.c @@ -1692,7 +1692,7 @@ static void ce_fastpath_rx_handle(struct CE_state *ce_state, uint32_t write_index; qdf_spin_unlock(&ce_state->ce_index_lock); - (ce_state->fastpath_handler)(ce_state->context, cmpl_msdus, num_cmpls); + (ce_state->fastpath_handler)(ce_state->context, cmpl_msdus, num_cmpls); qdf_spin_lock(&ce_state->ce_index_lock); /* Update Destination Ring Write Index */ @@ -1723,6 +1723,7 @@ static void ce_fastpath_rx_handle(struct CE_state *ce_state, static void ce_per_engine_service_fast(struct hif_softc *scn, int ce_id) { struct CE_state *ce_state = scn->ce_id_to_state[ce_id]; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); struct CE_ring_state *dest_ring = ce_state->dest_ring; struct CE_dest_desc *dest_ring_base = (struct CE_dest_desc *)dest_ring->base_addr_owner_space; @@ -1795,6 +1796,8 @@ more_data: qdf_assert_always(nbuf->data != NULL); + QDF_NBUF_CB_RX_CTX_ID(nbuf) = + hif_get_rx_ctx_id(ce_state->id, hif_hdl); cmpl_msdus[nbuf_cmpl_idx++] = nbuf; /* diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 9ec8602f821c..ef99334fc04c 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -172,11 +172,13 @@ static void ce_tasklet(unsigned long data) QDF_BUG(0); } + qdf_spin_lock_bh(&CE_state->lro_unloading_lock); ce_per_engine_service(scn, tasklet_entry->ce_id); if (CE_state->lro_flush_cb != NULL) { CE_state->lro_flush_cb(CE_state->lro_data); } + qdf_spin_unlock_bh(&CE_state->lro_unloading_lock); if (ce_check_rx_pending(CE_state)) { /* diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index 766f91048ee9..f4707d6301f9 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -49,6 +49,7 @@ #ifdef QCA_WIFI_QCA8074 #include "hal_api.h" #endif +#include "hif_napi.h" void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start) { @@ -812,20 +813,70 @@ struct hif_target_info *hif_get_target_info_handle( * Return: void */ void hif_lro_flush_cb_register(struct hif_opaque_softc *scn, - void (handler)(void *), void *data) + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)) { - ce_lro_flush_cb_register(scn, handler, data); + if (hif_napi_enabled(scn, -1)) + hif_napi_lro_flush_cb_register(scn, lro_flush_handler, + lro_init_handler); + else + ce_lro_flush_cb_register(scn, lro_flush_handler, + lro_init_handler); +} + +/** + * hif_get_lro_info - Returns LRO instance for instance ID + * @ctx_id: LRO instance ID + * @hif_hdl: HIF Context + * + * Return: Pointer to LRO instance. + */ +void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl) +{ + void *data; + + if (hif_napi_enabled(hif_hdl, -1)) + data = hif_napi_get_lro_info(hif_hdl, ctx_id); + else + data = hif_ce_get_lro_ctx(hif_hdl, ctx_id); + + return data; +} + +/** + * hif_get_rx_ctx_id - Returns LRO instance ID based on underlying LRO instance + * @ctx_id: LRO context ID + * @hif_hdl: HIF Context + * + * Return: LRO instance ID + */ +int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl) +{ + if (hif_napi_enabled(hif_hdl, -1)) + return NAPI_PIPE2ID(ctx_id); + else + return ctx_id; } /** * hif_lro_flush_cb_deregister - API to deregister for LRO Flush Callbacks - * @scn: HIF Context + * @hif_hdl: HIF Context + * @lro_deinit_cb: LRO deinit callback * * Return: void */ -void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn) +void hif_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)) { - ce_lro_flush_cb_deregister(scn); + if (hif_napi_enabled(hif_hdl, -1)) + hif_napi_lro_flush_cb_deregister(hif_hdl, lro_deinit_cb); + else + ce_lro_flush_cb_deregister(hif_hdl, lro_deinit_cb); +} +#else /* !defined(FEATURE_LRO) */ +int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl) +{ + return 0; } #endif diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index cf5c63292009..76e0c2b5693e 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -238,6 +238,7 @@ void hif_wlan_disable(struct hif_softc *scn); int hif_target_sleep_state_adjust(struct hif_softc *scn, bool sleep_ok, bool wait_for_it); +int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl); #ifdef HIF_USB void hif_usb_get_hw_info(struct hif_softc *scn); void hif_ramdump_handler(struct hif_opaque_softc *scn); diff --git a/hif/src/hif_napi.c b/hif/src/hif_napi.c index 04de9598c468..fe6c39b2b9e2 100644 --- a/hif/src/hif_napi.c +++ b/hif/src/hif_napi.c @@ -155,6 +155,7 @@ int hif_napi_create(struct hif_opaque_softc *hif_ctx, HIF_WARN("%s: bad IRQ value for CE %d: %d", __func__, i, napii->irq); + qdf_spinlock_create(&napii->lro_unloading_lock); init_dummy_netdev(&(napii->netdev)); NAPI_DEBUG("adding napi=%p to netdev=%p (poll=%p, bdgt=%d)", @@ -274,6 +275,119 @@ int hif_napi_destroy(struct hif_opaque_softc *hif_ctx, return rc; } +/** + * hif_napi_lro_flush_cb_register() - init and register flush callback for LRO + * @hif_hdl: pointer to hif context + * @lro_flush_handler: register LRO flush callback + * @lro_init_handler: Callback for initializing LRO + * + * Return: positive value on success and 0 on failure + */ +int hif_napi_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)) +{ + int rc = 0; + int i; + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + void *data = NULL; + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + QDF_ASSERT(scn != NULL); + + napid = hif_napi_get_all(hif_hdl); + if (scn != NULL) { + for (i = 0; i < scn->ce_count; i++) { + ce_state = scn->ce_id_to_state[i]; + if ((ce_state != NULL) && (ce_state->htt_rx_data)) { + data = lro_init_handler(); + if (data == NULL) { + HIF_ERROR("%s: Failed to init LRO for CE %d", + __func__, i); + continue; + } + napii = &(napid->napis[i]); + napii->lro_flush_cb = lro_flush_handler; + napii->lro_ctx = data; + HIF_ERROR("Registering LRO for ce_id %d NAPI callback for %d flush_cb %p, lro_data %p\n", + i, napii->id, napii->lro_flush_cb, + napii->lro_ctx); + rc++; + } + } + } else { + HIF_ERROR("%s: hif_state NULL!", __func__); + } + return rc; +} + +/** + * hif_napi_lro_flush_cb_deregister() - Degregister and free LRO. + * @hif: pointer to hif context + * @lro_deinit_cb: LRO deinit callback + * + * Return: NONE + */ +void hif_napi_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)) +{ + int i; + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + QDF_ASSERT(scn != NULL); + + napid = hif_napi_get_all(hif_hdl); + if (scn != NULL) { + for (i = 0; i < scn->ce_count; i++) { + ce_state = scn->ce_id_to_state[i]; + if ((ce_state != NULL) && (ce_state->htt_rx_data)) { + napii = &(napid->napis[i]); + HIF_ERROR("deRegistering LRO for ce_id %d NAPI callback for %d flush_cb %p, lro_data %p\n", + i, napii->id, napii->lro_flush_cb, + napii->lro_ctx); + qdf_spin_lock_bh(&napii->lro_unloading_lock); + napii->lro_flush_cb = NULL; + lro_deinit_cb(napii->lro_ctx); + napii->lro_ctx = NULL; + qdf_spin_unlock_bh( + &napii->lro_unloading_lock); + qdf_spinlock_destroy( + &napii->lro_unloading_lock); + } + } + } else { + HIF_ERROR("%s: hif_state NULL!", __func__); + } +} + +/** + * hif_napi_get_lro_info() - returns the address LRO data for napi_id + * @hif: pointer to hif context + * @napi_id: napi instance + * + * Description: + * Returns the address of the LRO structure + * + * Return: + * : address of the LRO structure + */ +void *hif_napi_get_lro_info(struct hif_opaque_softc *hif_hdl, int napi_id) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + napid = &(scn->napi_data); + napii = &(napid->napis[NAPI_ID2PIPE(napi_id)]); + + return napii->lro_ctx; +} + /** * * hif_napi_get_all() - returns the address of the whole HIF NAPI structure @@ -612,9 +726,12 @@ int hif_napi_poll(struct hif_opaque_softc *hif_ctx, struct napi_struct *napi, hif_record_ce_desc_event(hif, NAPI_ID2PIPE(napi_info->id), NAPI_POLL_ENTER, NULL, NULL, cpu); - if (unlikely(NULL == hif)) - QDF_ASSERT(hif != NULL); /* emit a warning if hif NULL */ - else { + qdf_spin_lock_bh(&napi_info->lro_unloading_lock); + if (unlikely(NULL == hif)) { + HIF_ERROR("%s: hif context is NULL", __func__); + QDF_ASSERT(0); /* emit a warning if hif NULL */ + goto out; + } else { rc = ce_per_engine_service(hif, NAPI_ID2PIPE(napi_info->id)); NAPI_DEBUG("%s: ce_per_engine_service processed %d msgs", __func__, rc); @@ -622,11 +739,11 @@ int hif_napi_poll(struct hif_opaque_softc *hif_ctx, struct napi_struct *napi, napi_info->stats[cpu].napi_workdone += rc; normalized = (rc / napi_info->scale); - if (NULL != hif) { - ce_state = hif->ce_id_to_state[NAPI_ID2PIPE(napi_info->id)]; - if (ce_state && ce_state->lro_flush_cb) - ce_state->lro_flush_cb(ce_state->lro_data); - } + ce_state = hif->ce_id_to_state[NAPI_ID2PIPE(napi_info->id)]; + + if (napi_info->lro_flush_cb) + napi_info->lro_flush_cb(napi_info->lro_ctx); + qdf_spin_unlock_bh(&napi_info->lro_unloading_lock); /* do not return 0, if there was some work done, * even if it is below the scale @@ -673,6 +790,8 @@ int hif_napi_poll(struct hif_opaque_softc *hif_ctx, struct napi_struct *napi, NAPI_DEBUG("%s <--[normalized=%d]", __func__, normalized); return normalized; +out: + return rc; } #ifdef HELIUMPLUS diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index cdd6111443b9..e15f657b18a9 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -137,7 +137,8 @@ struct qdf_nbuf_cb { tcp_pure_ack:1, ipv6_proto:1, ip_offset:7, - tcp_offset:7; + tcp_offset:7, + rx_ctx_id:4; uint32_t tcp_udp_chksum:16, tcp_win:16; uint32_t tcp_seq_num; @@ -214,6 +215,8 @@ struct qdf_nbuf_cb { #define QDF_NBUF_CB_RX_LRO_ELIGIBLE(skb) \ (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.lro_eligible) +#define QDF_NBUF_CB_RX_CTX_ID(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.rx_ctx_id) #define QDF_NBUF_CB_RX_TCP_PROTO(skb) \ (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_proto) #define QDF_NBUF_CB_RX_TCP_PURE_ACK(skb) \