summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dp/inc/cdp_txrx_lro.h5
-rw-r--r--hif/inc/hif.h11
-rw-r--r--hif/inc/hif_napi.h8
-rw-r--r--hif/src/ce/ce_api.h7
-rw-r--r--hif/src/ce/ce_internal.h1
-rw-r--r--hif/src/ce/ce_main.c33
-rw-r--r--hif/src/ce/ce_service.c5
-rw-r--r--hif/src/ce/ce_tasklet.c2
-rw-r--r--hif/src/hif_main.c61
-rw-r--r--hif/src/hif_main.h1
-rw-r--r--hif/src/hif_napi.c135
-rw-r--r--qdf/linux/src/i_qdf_nbuf.h5
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) \