diff options
| -rw-r--r-- | dp/inc/cdp_txrx_lro.h | 5 | ||||
| -rw-r--r-- | hif/inc/hif.h | 11 | ||||
| -rw-r--r-- | hif/inc/hif_napi.h | 8 | ||||
| -rw-r--r-- | hif/src/ce/ce_api.h | 7 | ||||
| -rw-r--r-- | hif/src/ce/ce_internal.h | 1 | ||||
| -rw-r--r-- | hif/src/ce/ce_main.c | 33 | ||||
| -rw-r--r-- | hif/src/ce/ce_service.c | 5 | ||||
| -rw-r--r-- | hif/src/ce/ce_tasklet.c | 2 | ||||
| -rw-r--r-- | hif/src/hif_main.c | 61 | ||||
| -rw-r--r-- | hif/src/hif_main.h | 1 | ||||
| -rw-r--r-- | hif/src/hif_napi.c | 135 | ||||
| -rw-r--r-- | 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 08e4f9e6b51c..1267f919ff62 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -132,6 +132,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; }; /** @@ -632,8 +636,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 * @@ -668,6 +674,7 @@ void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled, int rx_bundle_cnt); int hif_bus_reset_resume(struct hif_opaque_softc *scn); +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 f6e79db601bc..38d71df00fc9 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 6098876b500e..f6d0781691ee 100644 --- a/hif/src/ce/ce_api.h +++ b/hif/src/ce/ce_api.h @@ -479,9 +479,12 @@ 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 #endif /* __COPY_ENGINE_API_H__ */ diff --git a/hif/src/ce/ce_internal.h b/hif/src/ce/ce_internal.h index 178aa9ad30e9..74edde2f2037 100644 --- a/hif/src/ce/ce_internal.h +++ b/hif/src/ce/ce_internal.h @@ -148,6 +148,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 aeabc333ff53..6d42e8fcf3b1 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -625,6 +625,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; @@ -2438,6 +2439,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 @@ -2450,12 +2463,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); @@ -2463,6 +2478,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++; @@ -2483,7 +2504,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; @@ -2495,8 +2517,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 b6927c74a543..770f72c5126a 100644 --- a/hif/src/ce/ce_service.c +++ b/hif/src/ce/ce_service.c @@ -1607,7 +1607,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 */ @@ -1638,6 +1638,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; @@ -1710,6 +1711,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 ae41910d9c5a..253dda8f7919 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -46,6 +46,7 @@ #include "hif_debug.h" #include "mp_dev.h" #include "ce_api.h" +#include "hif_napi.h" void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start) { @@ -763,20 +764,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 bf352ed31e4a..aac91095b7d3 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -222,6 +222,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 42975c3112ea..56c226dc3515 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)", @@ -275,6 +276,119 @@ int hif_napi_destroy(struct hif_opaque_softc *hif_ctx, } /** + * 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: + * <addr>: 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 * @hif: pointer to hif context @@ -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 00c9bbad968e..94b59a5201bc 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) \ |
