summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/dp/htt/htt_rx.c5
-rw-r--r--core/dp/txrx/ol_txrx.c79
-rw-r--r--core/dp/txrx/ol_txrx_types.h2
-rw-r--r--core/hdd/inc/wlan_hdd_lro.h4
-rw-r--r--core/hdd/src/wlan_hdd_lro.c337
5 files changed, 148 insertions, 279 deletions
diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c
index b3bae10b0a6a..1d131e40cb80 100644
--- a/core/dp/htt/htt_rx.c
+++ b/core/dp/htt/htt_rx.c
@@ -1994,14 +1994,16 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
qdf_nbuf_t msdu, next, prev = NULL;
uint8_t *rx_ind_data;
uint32_t *msg_word;
+ uint32_t rx_ctx_id;
unsigned int msdu_count = 0;
uint8_t offload_ind, frag_ind;
- struct htt_host_rx_desc_base *rx_desc;
uint8_t peer_id;
+ struct htt_host_rx_desc_base *rx_desc;
HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0);
rx_ind_data = qdf_nbuf_data(rx_ind_msg);
+ rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(rx_ind_msg);
msg_word = (uint32_t *) rx_ind_data;
peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(
*(u_int32_t *)rx_ind_data);
@@ -2059,6 +2061,7 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
QDF_NBUF_CB_DP_TRACE_PRINT(msdu) = false;
qdf_dp_trace_set_track(msdu, QDF_RX);
QDF_NBUF_CB_TX_PACKET_TRACK(msdu) = QDF_NBUF_TX_PKT_DATA_TRACK;
+ QDF_NBUF_CB_RX_CTX_ID(msdu) = rx_ctx_id;
ol_rx_log_packet(pdev, peer_id, msdu);
DPTRACE(qdf_dp_trace(msdu,
QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD,
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index 9c781637813c..60a806839ac4 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -70,6 +70,7 @@
#include <ol_tx_queue.h>
#include <ol_tx_sched.h> /* ol_tx_sched_attach, etc. */
#include <ol_txrx.h>
+#include <ol_txrx_types.h>
#include <cdp_txrx_flow_ctrl_legacy.h>
#include <cdp_txrx_ipa.h>
#include "wma.h"
@@ -4639,7 +4640,7 @@ void ol_txrx_lro_flush_handler(void *context,
void *rxpkt,
uint16_t staid)
{
- ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)context;
+ ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (qdf_unlikely(!pdev)) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
@@ -4649,7 +4650,7 @@ void ol_txrx_lro_flush_handler(void *context,
}
if (pdev->lro_info.lro_flush_cb)
- pdev->lro_info.lro_flush_cb(pdev->lro_info.lro_data);
+ pdev->lro_info.lro_flush_cb(context);
else
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: lro_flush_cb NULL", __func__);
@@ -4668,13 +4669,13 @@ void ol_txrx_lro_flush(void *data)
{
p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
struct cds_ol_rx_pkt *pkt;
- ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)data;
+ ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (qdf_unlikely(!sched_ctx))
return;
if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) {
- ol_txrx_lro_flush_handler((void *)pdev, NULL, 0);
+ ol_txrx_lro_flush_handler(data, NULL, 0);
} else {
pkt = cds_alloc_ol_rx_pkt(sched_ctx);
if (qdf_unlikely(!pkt)) {
@@ -4685,7 +4686,7 @@ void ol_txrx_lro_flush(void *data)
pkt->callback =
(cds_ol_rx_thread_cb) ol_txrx_lro_flush_handler;
- pkt->context = pdev;
+ pkt->context = data;
pkt->Rxpkt = NULL;
pkt->staId = 0;
cds_indicate_rxpkt(sched_ctx, pkt);
@@ -4694,51 +4695,77 @@ void ol_txrx_lro_flush(void *data)
/**
* ol_register_lro_flush_cb() - register the LRO flush callback
- * @handler: callback function
- * @data: opaque data pointer to be passed back
+ * @lro_flush_cb: flush callback function
+ * @lro_init_cb: Allocate and initialize LRO data structure.
*
* Store the LRO flush callback provided and in turn
* register OL's LRO flush handler with CE
*
* Return: none
*/
-void ol_register_lro_flush_cb(void (handler)(void *), void *data)
+void ol_register_lro_flush_cb(void (lro_flush_cb)(void *),
+ void *(lro_init_cb)(void))
{
- struct hif_opaque_softc *hif_device =
- (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF);
+ struct hif_opaque_softc *hif_device;
struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
- if (pdev != NULL) {
- pdev->lro_info.lro_flush_cb = handler;
- pdev->lro_info.lro_data = data;
- } else
+ if (pdev == NULL) {
TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: pdev NULL!", __func__);
+ TXRX_ASSERT2(0);
+ goto out;
+ }
+ if (pdev->lro_info.lro_flush_cb != NULL) {
+ TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+ "%s: LRO already initialised\n", __func__);
+ if (pdev->lro_info.lro_flush_cb != lro_flush_cb) {
+ TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+ "lro_flush_cb is differ to previously registered callback\n")
+ TXRX_ASSERT2(0);
+ goto out;
+ }
+ qdf_atomic_inc(&pdev->lro_info.lro_dev_cnt);
+ goto out;
+ }
+ pdev->lro_info.lro_flush_cb = lro_flush_cb;
+ hif_device = (struct hif_opaque_softc *)
+ cds_get_context(QDF_MODULE_ID_HIF);
- hif_lro_flush_cb_register(hif_device, ol_txrx_lro_flush, pdev);
+ hif_lro_flush_cb_register(hif_device, ol_txrx_lro_flush, lro_init_cb);
+ qdf_atomic_inc(&pdev->lro_info.lro_dev_cnt);
+
+out:
+ return;
}
/**
- * ol_deregister_lro_flush_cb() - deregister the LRO flush
- * callback
+ * ol_deregister_lro_flush_cb() - deregister the LRO flush callback
+ * @lro_deinit_cb: callback function for deregistration.
*
* Remove the LRO flush callback provided and in turn
* deregister OL's LRO flush handler with CE
*
* Return: none
*/
-void ol_deregister_lro_flush_cb(void)
+void ol_deregister_lro_flush_cb(void (lro_deinit_cb)(void *))
{
- struct hif_opaque_softc *hif_device =
- (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF);
+ struct hif_opaque_softc *hif_device;
struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
- hif_lro_flush_cb_deregister(hif_device);
-
- if (pdev != NULL) {
- pdev->lro_info.lro_flush_cb = NULL;
- pdev->lro_info.lro_data = NULL;
- } else
+ if (pdev == NULL) {
TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: pdev NULL!", __func__);
+ return;
+ }
+ if (qdf_atomic_dec_and_test(&pdev->lro_info.lro_dev_cnt) == 0) {
+ TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+ "%s: Other LRO enabled modules still exist, do not unregister the lro_flush_cb\n", __func__);
+ return;
+ }
+ hif_device =
+ (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF);
+
+ hif_lro_flush_cb_deregister(hif_device, lro_deinit_cb);
+
+ pdev->lro_info.lro_flush_cb = NULL;
}
#endif /* FEATURE_LRO */
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index 898fb983660c..cc0dd07387e5 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -948,8 +948,8 @@ struct ol_txrx_pdev_t {
ol_tx_pause_callback_fp pause_cb;
struct {
- void *lro_data;
void (*lro_flush_cb)(void *);
+ qdf_atomic_t lro_dev_cnt;
} lro_info;
struct ol_txrx_peer_t *self_peer;
};
diff --git a/core/hdd/inc/wlan_hdd_lro.h b/core/hdd/inc/wlan_hdd_lro.h
index 0eaecdba83e9..4706526f111b 100644
--- a/core/hdd/inc/wlan_hdd_lro.h
+++ b/core/hdd/inc/wlan_hdd_lro.h
@@ -72,7 +72,6 @@ struct hdd_lro_desc_entry {
struct hdd_lro_desc_pool {
struct hdd_lro_desc_entry *lro_desc_array;
struct list_head lro_free_list_head;
- qdf_spinlock_t lro_pool_lock;
};
/**
@@ -93,7 +92,6 @@ struct hdd_lro_desc_table {
*/
struct hdd_lro_desc_info {
struct hdd_lro_desc_table *lro_hash_table;
- qdf_spinlock_t lro_hash_lock;
struct hdd_lro_desc_pool lro_desc_pool;
};
@@ -151,8 +149,6 @@ struct hdd_lro_stats {
struct hdd_lro_s {
struct net_lro_mgr *lro_mgr;
struct hdd_lro_desc_info lro_desc_info;
- qdf_spinlock_t lro_mgr_arr_access_lock;
- struct hdd_lro_stats lro_stats;
};
int hdd_lro_init(hdd_context_t *hdd_ctx);
diff --git a/core/hdd/src/wlan_hdd_lro.c b/core/hdd/src/wlan_hdd_lro.c
index 1f4a8f0256a2..586e0b717135 100644
--- a/core/hdd/src/wlan_hdd_lro.c
+++ b/core/hdd/src/wlan_hdd_lro.c
@@ -53,14 +53,6 @@
(LRO_DESC | LRO_ELIGIBILITY_CHECKED | LRO_TCP_ACK_NUM | \
LRO_TCP_DATA_CSUM | LRO_TCP_SEQ_NUM | LRO_TCP_WIN)
-#define LRO_HIST_UPDATE(lro_desc, adapter) \
- do { \
- uint8_t bucket = lro_desc->pkt_aggr_cnt >> 3; \
- if (unlikely(bucket > HDD_LRO_BUCKET_MAX)) \
- bucket = HDD_LRO_BUCKET_MAX; \
- adapter->lro_info.lro_stats.pkt_aggr_hist[bucket]++; \
- } while (0);
-
/**
* hdd_lro_get_skb_header() - LRO callback function
* @skb: network buffer
@@ -110,7 +102,6 @@ static void hdd_lro_desc_pool_init(struct hdd_lro_desc_pool *lro_desc_pool,
list_add_tail(&lro_desc_pool->lro_desc_array[i].lro_node,
&lro_desc_pool->lro_free_list_head);
}
- qdf_spinlock_create(&lro_desc_pool->lro_pool_lock);
}
/**
@@ -137,41 +128,6 @@ static void hdd_lro_desc_info_init(struct hdd_lro_s *hdd_info)
lro_hash_table[i].lro_desc_list);
}
- qdf_spinlock_create(&hdd_info->lro_desc_info.lro_hash_lock);
- qdf_spinlock_create(&hdd_info->lro_mgr_arr_access_lock);
-}
-
-/**
- * hdd_lro_desc_pool_deinit() - Free the LRO descriptor list
- * @hdd_info: HDD LRO data structure
- *
- * Free the pool of LRO descriptors
- *
- * Return: none
- */
-static void hdd_lro_desc_pool_deinit(struct hdd_lro_desc_pool *lro_desc_pool)
-{
- INIT_LIST_HEAD(&lro_desc_pool->lro_free_list_head);
- qdf_spinlock_destroy(&lro_desc_pool->lro_pool_lock);
-}
-
-/**
- * hdd_lro_desc_info_deinit() - Deinitialize the LRO descriptors
- *
- * @hdd_info: HDD LRO data structure
- *
- * Deinitialize the free pool of LRO descriptors and the entries
- * of the hash table
- *
- * Return: none
- */
-static void hdd_lro_desc_info_deinit(struct hdd_lro_s *hdd_info)
-{
- struct hdd_lro_desc_info *desc_info = &hdd_info->lro_desc_info;
-
- hdd_lro_desc_pool_deinit(&desc_info->lro_desc_pool);
- qdf_spinlock_destroy(&desc_info->lro_hash_lock);
- qdf_spinlock_destroy(&hdd_info->lro_mgr_arr_access_lock);
}
/**
@@ -214,7 +170,7 @@ static inline bool hdd_lro_tcp_flow_match(struct net_lro_desc *lro_desc,
*
* Return: 0 - success, < 0 - failure
*/
-static int hdd_lro_desc_find(hdd_adapter_t *adapter,
+static int hdd_lro_desc_find(struct hdd_lro_s *lro_info,
struct sk_buff *skb, struct iphdr *iph, struct tcphdr *tcph,
struct net_lro_desc **lro_desc)
{
@@ -223,7 +179,7 @@ static int hdd_lro_desc_find(hdd_adapter_t *adapter,
struct list_head *ptr;
struct hdd_lro_desc_entry *entry;
struct hdd_lro_desc_pool *free_pool;
- struct hdd_lro_desc_info *desc_info = &adapter->lro_info.lro_desc_info;
+ struct hdd_lro_desc_info *desc_info = &lro_info->lro_desc_info;
*lro_desc = NULL;
i = QDF_NBUF_CB_RX_FLOW_ID_TOEPLITZ(skb) & LRO_DESC_TABLE_SZ_MASK;
@@ -236,7 +192,6 @@ static int hdd_lro_desc_find(hdd_adapter_t *adapter,
return -EINVAL;
}
- qdf_spin_lock_bh(&desc_info->lro_hash_lock);
/* Check if this flow exists in the descriptor list */
list_for_each(ptr, &lro_hash_table->lro_desc_list) {
struct net_lro_desc *tmp_lro_desc = NULL;
@@ -245,27 +200,22 @@ static int hdd_lro_desc_find(hdd_adapter_t *adapter,
if (tmp_lro_desc->active) {
if (hdd_lro_tcp_flow_match(tmp_lro_desc, iph, tcph)) {
*lro_desc = entry->lro_desc;
- qdf_spin_unlock_bh(&desc_info->lro_hash_lock);
return 0;
}
}
}
- qdf_spin_unlock_bh(&desc_info->lro_hash_lock);
/* no existing flow found, a new LRO desc needs to be allocated */
- free_pool = &adapter->lro_info.lro_desc_info.lro_desc_pool;
- qdf_spin_lock_bh(&free_pool->lro_pool_lock);
+ free_pool = &lro_info->lro_desc_info.lro_desc_pool;
entry = list_first_entry_or_null(
&free_pool->lro_free_list_head,
struct hdd_lro_desc_entry, lro_node);
if (NULL == entry) {
hdd_err("Could not allocate LRO desc!");
- qdf_spin_unlock_bh(&free_pool->lro_pool_lock);
return -ENOMEM;
}
list_del_init(&entry->lro_node);
- qdf_spin_unlock_bh(&free_pool->lro_pool_lock);
if (NULL == entry->lro_desc) {
hdd_err("entry->lro_desc is NULL!");
@@ -278,10 +228,8 @@ static int hdd_lro_desc_find(hdd_adapter_t *adapter,
* lro_desc->active should be 0 and lro_desc->tcp_rcv_tsval
* should be 0 for newly allocated lro descriptors
*/
- qdf_spin_lock_bh(&desc_info->lro_hash_lock);
list_add_tail(&entry->lro_node,
&lro_hash_table->lro_desc_list);
- qdf_spin_unlock_bh(&desc_info->lro_hash_lock);
*lro_desc = entry->lro_desc;
return 0;
@@ -327,7 +275,7 @@ static struct net_lro_desc *hdd_lro_get_desc(struct net_lro_mgr *lro_mgr,
* Return: true - LRO eligible frame, false - frame is not LRO
* eligible
*/
-static bool hdd_lro_eligible(hdd_adapter_t *adapter, struct sk_buff *skb,
+static bool hdd_lro_eligible(struct hdd_lro_s *lro_info, struct sk_buff *skb,
struct iphdr *iph, struct tcphdr *tcph, struct net_lro_desc **desc)
{
struct net_lro_desc *lro_desc = NULL;
@@ -338,7 +286,7 @@ static bool hdd_lro_eligible(hdd_adapter_t *adapter, struct sk_buff *skb,
if (!hw_lro_eligible)
return false;
- if (0 != hdd_lro_desc_find(adapter, skb, iph, tcph, desc)) {
+ if (0 != hdd_lro_desc_find(lro_info, skb, iph, tcph, desc)) {
hdd_err("finding the LRO desc failed");
return false;
}
@@ -384,11 +332,12 @@ static bool hdd_lro_eligible(hdd_adapter_t *adapter, struct sk_buff *skb,
* Return: none
*/
static void hdd_lro_desc_free(struct net_lro_desc *desc,
- hdd_adapter_t *adapter)
+ struct hdd_lro_s *lro_info)
{
struct hdd_lro_desc_entry *entry;
- struct net_lro_desc *arr_base = adapter->lro_info.lro_mgr->lro_arr;
- struct hdd_lro_desc_info *desc_info = &adapter->lro_info.lro_desc_info;
+ struct net_lro_mgr *lro_mgr = lro_info->lro_mgr;
+ struct net_lro_desc *arr_base = lro_mgr->lro_arr;
+ struct hdd_lro_desc_info *desc_info = &lro_info->lro_desc_info;
int i = desc - arr_base;
if (i >= LRO_DESC_POOL_SZ) {
@@ -398,14 +347,10 @@ static void hdd_lro_desc_free(struct net_lro_desc *desc,
entry = &desc_info->lro_desc_pool.lro_desc_array[i];
- qdf_spin_lock_bh(&desc_info->lro_hash_lock);
list_del_init(&entry->lro_node);
- qdf_spin_unlock_bh(&desc_info->lro_hash_lock);
- qdf_spin_lock_bh(&desc_info->lro_desc_pool.lro_pool_lock);
list_add_tail(&entry->lro_node, &desc_info->
lro_desc_pool.lro_free_list_head);
- qdf_spin_unlock_bh(&desc_info->lro_desc_pool.lro_pool_lock);
}
/**
@@ -422,7 +367,7 @@ static void hdd_lro_desc_free(struct net_lro_desc *desc,
*/
static void hdd_lro_flush_pkt(struct net_lro_mgr *lro_mgr,
struct iphdr *iph, struct tcphdr *tcph,
- hdd_adapter_t *adapter)
+ struct hdd_lro_s *lro_info)
{
struct net_lro_desc *lro_desc;
@@ -430,9 +375,7 @@ static void hdd_lro_flush_pkt(struct net_lro_mgr *lro_mgr,
if (lro_desc) {
/* statistics */
- LRO_HIST_UPDATE(lro_desc, adapter);
-
- hdd_lro_desc_free(lro_desc, adapter);
+ hdd_lro_desc_free(lro_desc, lro_info);
lro_flush_desc(lro_mgr, lro_desc);
}
}
@@ -448,51 +391,15 @@ static void hdd_lro_flush_pkt(struct net_lro_mgr *lro_mgr,
*/
static void hdd_lro_flush(void *data)
{
- hdd_adapter_t *adapter = (hdd_adapter_t *)data;
- struct hdd_lro_s *hdd_lro;
- struct hdd_context_s *ctx;
- QDF_STATUS status;
- hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
+ struct hdd_lro_s *hdd_lro = data;
+ struct net_lro_mgr *lro_mgr = hdd_lro->lro_mgr;
int i;
- /*
- * There is a more comprehensive solution that refactors
- * lro_mgr in the adapter into multiple instances, that
- * will replace this solution. The following is an interim
- * fix.
- */
-
- /* Loop over all adapters and flush them all */
- ctx = (struct hdd_context_s *)cds_get_context(QDF_MODULE_ID_HDD);
- if (unlikely(ctx == NULL)) {
- hdd_err("%s: cannot get hdd_ctx. Flushing failed", __func__);
- return;
- }
-
- status = hdd_get_front_adapter(ctx, &adapter_node);
- while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
- adapter = adapter_node->pAdapter;
- hdd_lro = &adapter->lro_info;
- if (adapter->dev == NULL) {
- hdd_err("vdev interface going down");
- } else if (adapter->dev->features & NETIF_F_LRO) {
- qdf_spin_lock_bh(&hdd_lro->lro_mgr_arr_access_lock);
- for (i = 0; i < hdd_lro->lro_mgr->max_desc; i++) {
- if (hdd_lro->lro_mgr->lro_arr[i].active) {
- hdd_lro_desc_free(
- &hdd_lro->lro_mgr->lro_arr[i],
- (void *)adapter);
- lro_flush_desc(
- hdd_lro->lro_mgr,
- &hdd_lro->lro_mgr->lro_arr[i]);
- LRO_HIST_UPDATE((&hdd_lro->lro_mgr->lro_arr[i]),
- adapter);
- }
- }
- qdf_spin_unlock_bh(&hdd_lro->lro_mgr_arr_access_lock);
+ for (i = 0; i < lro_mgr->max_desc; i++) {
+ if (lro_mgr->lro_arr[i].active) {
+ hdd_lro_desc_free(&lro_mgr->lro_arr[i], hdd_lro);
+ lro_flush_desc(lro_mgr, &lro_mgr->lro_arr[i]);
}
- status = hdd_get_next_adapter(ctx, adapter_node, &next);
- adapter_node = next;
}
}
@@ -541,53 +448,39 @@ int hdd_lro_init(hdd_context_t *hdd_ctx)
return 0;
}
-/**
- * hdd_lro_enable() - enable LRO
- * @hdd_ctx: HDD context
- * @adapter: HDD adapter
- *
- * This function enables LRO in the network device attached to
- * the HDD adapter. It also allocates the HDD LRO instance for
- * that network device
- *
- * Return: 0 - success, < 0 - failure
- */
-int hdd_lro_enable(hdd_context_t *hdd_ctx,
- hdd_adapter_t *adapter)
+static void *hdd_init_lro_mgr(void)
{
struct hdd_lro_s *hdd_lro;
- size_t lro_mgr_sz, desc_arr_sz, desc_pool_sz, hash_table_sz;
+ hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+ size_t lro_info_sz, lro_mgr_sz, desc_arr_sz, desc_pool_sz;
+ size_t hash_table_sz;
uint8_t *lro_mem_ptr;
- if (!hdd_ctx->config->lro_enable ||
- QDF_STA_MODE != adapter->device_mode) {
- hdd_info("LRO Disabled");
- return 0;
+ if (NULL == hdd_ctx) {
+ hdd_err("hdd_ctx is NULL");
+ return NULL;
}
-
- hdd_info("LRO Enabled");
-
- hdd_lro = &adapter->lro_info;
- qdf_mem_zero((void *)hdd_lro, sizeof(struct hdd_lro_s));
-
/*
* Allocate all the LRO data structures at once and then carve
* them up as needed
*/
+ lro_info_sz = sizeof(struct hdd_lro_s);
lro_mgr_sz = sizeof(struct net_lro_mgr);
desc_arr_sz = (LRO_DESC_POOL_SZ * sizeof(struct net_lro_desc));
desc_pool_sz = (LRO_DESC_POOL_SZ * sizeof(struct hdd_lro_desc_entry));
hash_table_sz = (sizeof(struct hdd_lro_desc_table) * LRO_DESC_TABLE_SZ);
- lro_mem_ptr = qdf_mem_malloc(lro_mgr_sz + desc_arr_sz + desc_pool_sz +
- hash_table_sz);
+ lro_mem_ptr = qdf_mem_malloc(lro_info_sz + lro_mgr_sz + desc_arr_sz +
+ desc_pool_sz + hash_table_sz);
if (NULL == lro_mem_ptr) {
hdd_err("Unable to allocate memory for LRO");
hdd_ctx->config->lro_enable = 0;
- return -ENOMEM;
+ return NULL;
}
+ hdd_lro = (struct hdd_lro_s *)lro_mem_ptr;
+ lro_mem_ptr += lro_info_sz;
/* LRO manager */
hdd_lro->lro_mgr = (struct net_lro_mgr *)lro_mem_ptr;
lro_mem_ptr += lro_mgr_sz;
@@ -606,9 +499,8 @@ int hdd_lro_enable(hdd_context_t *hdd_ctx,
(struct hdd_lro_desc_table *)lro_mem_ptr;
/* Initialize the LRO descriptors */
- hdd_lro_desc_info_init(hdd_lro);
+ hdd_lro_desc_info_init(hdd_lro);
- hdd_lro->lro_mgr->dev = adapter->dev;
if (hdd_ctx->enableRxThread)
hdd_lro->lro_mgr->features = LRO_F_NI;
@@ -621,14 +513,46 @@ int hdd_lro_enable(hdd_context_t *hdd_ctx,
hdd_lro->lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
hdd_lro->lro_mgr->max_desc = LRO_DESC_POOL_SZ;
- adapter->dev->features |= NETIF_F_LRO;
+ return hdd_lro;
+}
+
+/**
+ * hdd_lro_enable() - enable LRO
+ * @hdd_ctx: HDD context
+ * @adapter: HDD adapter
+ *
+ * This function enables LRO in the network device attached to
+ * the HDD adapter. It also allocates the HDD LRO instance for
+ * that network device
+ *
+ * Return: 0 - success, < 0 - failure
+ */
+int hdd_lro_enable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
+{
+
+ if (!hdd_ctx->config->lro_enable ||
+ QDF_STA_MODE != adapter->device_mode) {
+ hdd_info("LRO Disabled");
+ return 0;
+ }
/* Register the flush callback */
- ol_register_lro_flush_cb(hdd_lro_flush, adapter);
+ ol_register_lro_flush_cb(hdd_lro_flush, hdd_init_lro_mgr);
+ adapter->dev->features |= NETIF_F_LRO;
+
+ hdd_info("LRO Enabled");
return 0;
}
+void hdd_deinit_lro_mgr(void *lro_info)
+{
+ if (lro_info) {
+ hdd_err("LRO instance %p is being freed", lro_info);
+ qdf_mem_free(lro_info);
+ }
+}
+
/**
* hdd_lro_disable() - disable LRO
* @hdd_ctx: HDD context
@@ -646,17 +570,8 @@ void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
return;
/* Deregister the flush callback */
- ol_deregister_lro_flush_cb();
-
- if (adapter->lro_info.lro_mgr) {
- hdd_lro_desc_info_deinit(&adapter->lro_info);
- qdf_mem_free(adapter->lro_info.lro_mgr);
- adapter->lro_info.lro_mgr = NULL;
- adapter->lro_info.lro_desc_info.
- lro_desc_pool.lro_desc_array = NULL;
- adapter->lro_info.lro_desc_info.
- lro_hash_table = NULL;
- }
+ ol_deregister_lro_flush_cb(hdd_deinit_lro_mgr);
+
return;
}
@@ -681,12 +596,26 @@ enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx,
struct iphdr *iph;
struct tcphdr *tcph;
struct net_lro_desc *lro_desc = NULL;
- struct hdd_lro_s *hdd_lro = &adapter->lro_info;
+ struct hdd_lro_s *lro_info;
+ struct hif_opaque_softc *hif_hdl =
+ (struct hif_opaque_softc *)cds_get_context(
+ QDF_MODULE_ID_HIF);
+ if (hif_hdl == NULL) {
+ hdd_err("hif_hdl is NULL");
+ return status;
+ }
+
+ lro_info = hif_get_lro_info(QDF_NBUF_CB_RX_CTX_ID(skb),
+ hif_hdl);
+ if (lro_info == NULL) {
+ hdd_err("LRO mgr is NULL, vdev could be going down");
+ return status;
+ }
+
iph = (struct iphdr *)skb->data;
tcph = (struct tcphdr *)(skb->data + QDF_NBUF_CB_RX_TCP_OFFSET(skb));
- qdf_spin_lock_bh(
- &hdd_lro->lro_mgr_arr_access_lock);
- if (hdd_lro_eligible(adapter, skb, iph, tcph, &lro_desc)) {
+ lro_info->lro_mgr->dev = adapter->dev;
+ if (hdd_lro_eligible(lro_info, skb, iph, tcph, &lro_desc)) {
struct net_lro_info hdd_lro_info;
hdd_lro_info.valid_fields = LRO_VALID_FIELDS;
@@ -699,53 +628,23 @@ enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx,
hdd_lro_info.tcp_seq_num = QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb);
hdd_lro_info.tcp_win = QDF_NBUF_CB_RX_TCP_WIN(skb);
- lro_receive_skb_ext(adapter->lro_info.lro_mgr, skb,
+ lro_receive_skb_ext(lro_info->lro_mgr, skb,
(void *)adapter, &hdd_lro_info);
if (!hdd_lro_info.lro_desc->active) {
- hdd_lro_desc_free(lro_desc, adapter);
+ hdd_lro_desc_free(lro_desc, lro_info);
}
status = HDD_LRO_RX;
- adapter->lro_info.lro_stats.lro_eligible_tcp++;
} else {
- hdd_lro_flush_pkt(adapter->lro_info.lro_mgr,
- iph, tcph, adapter);
- adapter->lro_info.lro_stats.lro_ineligible_tcp++;
+ hdd_lro_flush_pkt(lro_info->lro_mgr,
+ iph, tcph, lro_info);
}
- qdf_spin_unlock_bh(
- &hdd_lro->lro_mgr_arr_access_lock);
}
return status;
}
/**
- * hdd_lro_bucket_to_string() - return string conversion of
- * bucket
- * @bucket: bucket
- *
- * This utility function helps log string conversion of bucket
- * enum
- *
- * Return: string conversion of the LRO bucket, if match found;
- * "Invalid" otherwise.
- */
-static const char *hdd_lro_bucket_to_string(enum hdd_lro_pkt_aggr_bucket bucket)
-{
- switch (bucket) {
- CASE_RETURN_STRING(HDD_LRO_BUCKET_0_7);
- CASE_RETURN_STRING(HDD_LRO_BUCKET_8_15);
- CASE_RETURN_STRING(HDD_LRO_BUCKET_16_23);
- CASE_RETURN_STRING(HDD_LRO_BUCKET_24_31);
- CASE_RETURN_STRING(HDD_LRO_BUCKET_32_39);
- CASE_RETURN_STRING(HDD_LRO_BUCKET_40_47);
- CASE_RETURN_STRING(HDD_LRO_BUCKET_48_OR_MORE);
- default:
- return "Invalid";
- }
-}
-
-/**
* wlan_hdd_display_lro_stats() - display LRO statistics
* @hdd_ctx: hdd context
*
@@ -753,61 +652,5 @@ static const char *hdd_lro_bucket_to_string(enum hdd_lro_pkt_aggr_bucket bucket)
*/
void hdd_lro_display_stats(hdd_context_t *hdd_ctx)
{
-
- hdd_adapter_t *adapter = NULL;
- hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
- QDF_STATUS status;
- int i;
-
- if (!hdd_ctx->config->lro_enable) {
- hdd_err("LRO Disabled");
- return;
- }
-
- status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
- while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
- struct hdd_lro_stats *stats;
- hdd_err("\nLRO statistics:");
-
- adapter = adapter_node->pAdapter;
- if (!adapter) {
- status = hdd_get_next_adapter(hdd_ctx,
- adapter_node, &next);
- adapter_node = next;
- continue;
- }
-
- stats = &adapter->lro_info.lro_stats;
- hdd_err("Session_id %d device mode %d",
- adapter->sessionId, adapter->device_mode);
-
- if (NL80211_IFTYPE_STATION != adapter->wdev.iftype) {
- hdd_err("No LRO on interface type %d",
- adapter->wdev.iftype);
- status = hdd_get_next_adapter(hdd_ctx,
- adapter_node, &next);
- adapter_node = next;
- continue;
- }
-
- for (i = 0; i <= HDD_LRO_BUCKET_MAX; i++) {
- if (stats && stats->pkt_aggr_hist)
- hdd_err("bucket %s: %d packets",
- hdd_lro_bucket_to_string(i),
- stats->pkt_aggr_hist[i]);
- }
-
- hdd_err("LRO eligible TCP packets %d\n"
- "LRO ineligible TCP packets %d",
- stats->lro_eligible_tcp, stats->lro_ineligible_tcp);
-
- if (adapter->lro_info.lro_mgr)
- hdd_err("LRO manager aggr %lu flushed %lu no desc %lu",
- adapter->lro_info.lro_mgr->stats.aggregated,
- adapter->lro_info.lro_mgr->stats.flushed,
- adapter->lro_info.lro_mgr->stats.no_desc);
-
- status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
- adapter_node = next;
- }
+ hdd_err("LRO stats is broken, will fix it");
}