From 297b60346df8beafee954a0fd7c2d64f33f3b9bc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 11 May 2024 01:44:05 +0000
Subject: [PATCH] rtl8211F_led_control
---
kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_flowring.c | 379 ++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 310 insertions(+), 69 deletions(-)
diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_flowring.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_flowring.c
index 24d4189..976fc32 100644
--- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_flowring.c
+++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_flowring.c
@@ -1,18 +1,19 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/**
+/*
* @file Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level
*
* Flow rings are transmit traffic (=propagating towards antenna) related entities
*
*
- * Copyright (C) 1999-2019, Broadcom Corporation
- *
+ * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation
+ *
+ * Copyright (C) 1999-2017, Broadcom Corporation
+ *
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
- *
+ *
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -20,7 +21,7 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
- *
+ *
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
@@ -28,17 +29,16 @@
*
* <<Broadcom-WL-IPTag/Open:>>
*
- * $Id: dhd_flowrings.c jaganlv $
+ * $Id: dhd_flowring.c 699841 2017-05-16 16:47:06Z $
*/
-
#include <typedefs.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmdevs.h>
-#include <proto/ethernet.h>
-#include <proto/bcmevent.h>
+#include <ethernet.h>
+#include <bcmevent.h>
#include <dngl_stats.h>
#include <dhd.h>
@@ -47,11 +47,10 @@
#include <dhd_bus.h>
#include <dhd_proto.h>
#include <dhd_dbg.h>
-#include <proto/802.1d.h>
+#include <802.1d.h>
#include <pcie_core.h>
#include <bcmmsgbuf.h>
#include <dhd_pcie.h>
-
static INLINE int dhd_flow_queue_throttle(flow_queue_t *queue);
@@ -68,11 +67,7 @@
#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p)
#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x))
-#ifdef DHD_LOSSLESS_ROAMING
-const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 7 };
-#else
const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 };
-#endif
const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
/** Queue overflow throttle. Return value: TRUE if throttle needs to be applied */
@@ -96,6 +91,9 @@
ASSERT(dhdp != (dhd_pub_t*)NULL);
ASSERT(flowid < dhdp->num_flow_rings);
+ if (flowid >= dhdp->num_flow_rings) {
+ return NULL;
+ }
flow_ring_node = &(((flow_ring_node_t*)(dhdp->flow_ring_table))[flowid]);
@@ -107,10 +105,13 @@
flow_queue_t *
dhd_flow_queue(dhd_pub_t *dhdp, uint16 flowid)
{
- flow_ring_node_t * flow_ring_node;
+ flow_ring_node_t * flow_ring_node = NULL;
flow_ring_node = dhd_flow_ring_node(dhdp, flowid);
- return &flow_ring_node->queue;
+ if (flow_ring_node)
+ return &flow_ring_node->queue;
+ else
+ return NULL;
}
/* Flow ring's queue management functions */
@@ -244,7 +245,7 @@
int queue_budget, int cumm_threshold, void *cumm_ctr,
int l2cumm_threshold, void *l2cumm_ctr)
{
- flow_queue_t * queue;
+ flow_queue_t * queue = NULL;
ASSERT(dhdp != (dhd_pub_t*)NULL);
ASSERT(queue_budget > 1);
@@ -254,16 +255,59 @@
ASSERT(l2cumm_ctr != (void*)NULL);
queue = dhd_flow_queue(dhdp, flowid);
+ if (queue) {
+ DHD_FLOW_QUEUE_SET_MAX(queue, queue_budget); /* Max queue length */
- DHD_FLOW_QUEUE_SET_MAX(queue, queue_budget); /* Max queue length */
+ /* Set the queue's parent threshold and cummulative counter */
+ DHD_FLOW_QUEUE_SET_THRESHOLD(queue, cumm_threshold);
+ DHD_FLOW_QUEUE_SET_CLEN(queue, cumm_ctr);
- /* Set the queue's parent threshold and cummulative counter */
- DHD_FLOW_QUEUE_SET_THRESHOLD(queue, cumm_threshold);
- DHD_FLOW_QUEUE_SET_CLEN(queue, cumm_ctr);
+ /* Set the queue's grandparent threshold and cummulative counter */
+ DHD_FLOW_QUEUE_SET_L2THRESHOLD(queue, l2cumm_threshold);
+ DHD_FLOW_QUEUE_SET_L2CLEN(queue, l2cumm_ctr);
+ }
+}
- /* Set the queue's grandparent threshold and cummulative counter */
- DHD_FLOW_QUEUE_SET_L2THRESHOLD(queue, l2cumm_threshold);
- DHD_FLOW_QUEUE_SET_L2CLEN(queue, l2cumm_ctr);
+uint8
+dhd_num_prio_supported_per_flow_ring(dhd_pub_t *dhdp)
+{
+ uint8 prio_count = 0;
+ int i;
+ // Pick all elements one by one
+ for (i = 0; i < NUMPRIO; i++)
+ {
+ // Check if the picked element is already counted
+ int j;
+ for (j = 0; j < i; j++) {
+ if (dhdp->flow_prio_map[i] == dhdp->flow_prio_map[j]) {
+ break;
+ }
+ }
+ // If not counted earlier, then count it
+ if (i == j) {
+ prio_count++;
+ }
+ }
+
+#ifdef DHD_LOSSLESS_ROAMING
+ /* For LLR, we are using flowring with prio 7 which is not considered
+ * in prio2ac array. But in __dhd_sendpkt, it is hardcoded hardcoded
+ * prio to PRIO_8021D_NC and send to dhd_flowid_update.
+ * So add 1 to prio_count.
+ */
+ prio_count++;
+#endif /* DHD_LOSSLESS_ROAMING */
+
+ return prio_count;
+}
+
+uint8
+dhd_get_max_multi_client_flow_rings(dhd_pub_t *dhdp)
+{
+ uint8 reserved_infra_sta_flow_rings = dhd_num_prio_supported_per_flow_ring(dhdp);
+ uint8 total_tx_flow_rings = dhdp->num_flow_rings - dhdp->bus->max_cmn_rings;
+ uint8 max_multi_client_flow_rings = total_tx_flow_rings - reserved_infra_sta_flow_rings;
+ return max_multi_client_flow_rings;
}
/** Initializes data structures of multiple flow rings */
@@ -284,7 +328,7 @@
/* Construct a 16bit flowid allocator */
flowid_allocator = id16_map_init(dhdp->osh,
- num_flow_rings - FLOW_RING_COMMON, FLOWID_RESERVED);
+ num_flow_rings - dhdp->bus->max_cmn_rings, FLOWID_RESERVED);
if (flowid_allocator == NULL) {
DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__));
return BCME_NOMEM;
@@ -306,6 +350,9 @@
flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED;
flow_ring_table[idx].flowid = (uint16)idx;
flow_ring_table[idx].lock = dhd_os_spin_lock_init(dhdp->osh);
+#ifdef IDLE_TX_FLOW_MGMT
+ flow_ring_table[idx].last_active_ts = OSL_SYSUPTIME();
+#endif /* IDLE_TX_FLOW_MGMT */
if (flow_ring_table[idx].lock == NULL) {
DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__));
goto fail;
@@ -346,9 +393,13 @@
dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP;
bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+
+ dhdp->max_multi_client_flow_rings = dhd_get_max_multi_client_flow_rings(dhdp);
+ dhdp->multi_client_flow_rings = 0U;
+
#ifdef DHD_LOSSLESS_ROAMING
dhdp->dequeue_prec_map = ALLPRIO;
-#endif
+#endif // endif
/* Now populate into dhd pub */
DHD_FLOWID_LOCK(lock, flags);
dhdp->num_flow_rings = num_flow_rings;
@@ -445,6 +496,9 @@
dhdp->num_flow_rings = 0U;
bzero(dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+ dhdp->max_multi_client_flow_rings = 0U;
+ dhdp->multi_client_flow_rings = 0U;
+
lock = dhdp->flowid_lock;
dhdp->flowid_lock = NULL;
@@ -474,13 +528,20 @@
#ifdef WLTDLS
bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da)
{
- tdls_peer_node_t *cur = dhdp->peer_tbl.node;
+ unsigned long flags;
+ tdls_peer_node_t *cur = NULL;
+
+ DHD_TDLS_LOCK(&dhdp->tdls_lock, flags);
+ cur = dhdp->peer_tbl.node;
+
while (cur != NULL) {
if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+ DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags);
return TRUE;
}
cur = cur->next;
}
+ DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags);
return FALSE;
}
#endif /* WLTDLS */
@@ -495,13 +556,16 @@
if_flow_lkup_t *if_flow_lkup;
unsigned long flags;
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return FLOWID_INVALID;
+
DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
ASSERT(if_flow_lkup);
- if ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) ||
- (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_WDS)) {
+ if (DHD_IF_ROLE_GENERIC_STA(dhdp, ifindex)) {
#ifdef WLTDLS
if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) &&
is_tdls_destination(dhdp, da)) {
@@ -561,7 +625,11 @@
uint16 flowid;
unsigned long flags;
- fl_hash_node = (flow_hash_info_t *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t));
+ fl_hash_node = (flow_hash_info_t *) MALLOCZ(dhdp->osh, sizeof(flow_hash_info_t));
+ if (fl_hash_node == NULL) {
+ DHD_ERROR(("%s: flow_hash_info_t memory allocation failed \n", __FUNCTION__));
+ return FLOWID_INVALID;
+ }
memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da));
DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
@@ -571,7 +639,7 @@
if (flowid == FLOWID_INVALID) {
MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t));
- DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__));
+ DHD_ERROR_RLMT(("%s: cannot get free flowid \n", __FUNCTION__));
return FLOWID_INVALID;
}
@@ -583,9 +651,8 @@
DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
- if ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) ||
- (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_WDS)) {
- /* For STA non TDLS dest and WDS dest we allocate entry based on prio only */
+ if (DHD_IF_ROLE_GENERIC_STA(dhdp, ifindex)) {
+ /* For STA/GC non TDLS dest and WDS dest we allocate entry based on prio only */
#ifdef WLTDLS
if (dhdp->peer_tbl.tdls_peer_count &&
(is_tdls_destination(dhdp, da))) {
@@ -619,6 +686,15 @@
DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid));
+ if (fl_hash_node->flowid >= dhdp->num_flow_rings) {
+ DHD_ERROR(("%s: flowid=%d num_flow_rings=%d ifindex=%d prio=%d role=%d\n",
+ __FUNCTION__, fl_hash_node->flowid, dhdp->num_flow_rings,
+ ifindex, prio, if_flow_lkup[ifindex].role));
+ dhd_prhex("da", (uchar *)da, ETHER_ADDR_LEN, DHD_ERROR_VAL);
+ dhd_prhex("sa", (uchar *)sa, ETHER_ADDR_LEN, DHD_ERROR_VAL);
+ return FLOWID_INVALID;
+ }
+
return fl_hash_node->flowid;
} /* dhd_flowid_alloc */
@@ -633,36 +709,67 @@
unsigned long flags;
int ret;
- DHD_INFO(("%s\n", __FUNCTION__));
+ DHD_TRACE(("%s\n", __FUNCTION__));
if (!dhdp->flow_ring_table) {
return BCME_ERROR;
}
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return BCME_BADARG;
flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
id = dhd_flowid_find(dhdp, ifindex, prio, sa, da);
if (id == FLOWID_INVALID) {
-
+ bool if_role_multi_client;
if_flow_lkup_t *if_flow_lkup;
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
if (!if_flow_lkup[ifindex].status)
return BCME_ERROR;
+ /* check role for multi client case */
+ if_role_multi_client = DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex);
+
+ /* Abort Flowring creation if multi client flowrings crossed the threshold */
+#ifdef DHD_LIMIT_MULTI_CLIENT_FLOWRINGS
+ if (if_role_multi_client &&
+ (dhdp->multi_client_flow_rings >= dhdp->max_multi_client_flow_rings)) {
+ DHD_ERROR_RLMT(("%s: Max multi client flow rings reached: %d:%d\n",
+ __FUNCTION__, dhdp->multi_client_flow_rings,
+ dhdp->max_multi_client_flow_rings));
+ return BCME_ERROR;
+ }
+#endif /* DHD_LIMIT_MULTI_CLIENT_FLOWRINGS */
+
+ /* Do not create Flowring if peer is not associated */
+#if defined(PCIE_FULL_DONGLE)
+ if (if_role_multi_client && !ETHER_ISMULTI(da) &&
+ !dhd_sta_associated(dhdp, ifindex, (uint8 *)da)) {
+ DHD_ERROR_RLMT(("%s: Skip send pkt without peer addition\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+#endif /* (linux || LINUX) && PCIE_FULL_DONGLE */
id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da);
if (id == FLOWID_INVALID) {
- DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n",
+ DHD_ERROR_RLMT(("%s: alloc flowid ifindex %u status %u\n",
__FUNCTION__, ifindex, if_flow_lkup[ifindex].status));
return BCME_ERROR;
}
+ ASSERT(id < dhdp->num_flow_rings);
+
+ /* Only after flowid alloc, increment multi_client_flow_rings */
+ if (if_role_multi_client) {
+ dhdp->multi_client_flow_rings++;
+ }
+
/* register this flowid in dhd_pub */
dhd_add_flowid(dhdp, ifindex, prio, da, id);
-
- ASSERT(id < dhdp->num_flow_rings);
flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id];
@@ -674,12 +781,22 @@
flow_ring_node->flow_info.tid = prio;
flow_ring_node->flow_info.ifindex = ifindex;
flow_ring_node->active = TRUE;
- flow_ring_node->status = FLOW_RING_STATUS_PENDING;
+ flow_ring_node->status = FLOW_RING_STATUS_CREATE_PENDING;
+
+#ifdef TX_STATUS_LATENCY_STATS
+ flow_ring_node->flow_info.num_tx_status = 0;
+ flow_ring_node->flow_info.cum_tx_status_latency = 0;
+ flow_ring_node->flow_info.num_tx_pkts = 0;
+#endif /* TX_STATUS_LATENCY_STATS */
DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
/* Create and inform device about the new flow */
if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node)
!= BCME_OK) {
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+ flow_ring_node->status = FLOW_RING_STATUS_CLOSED;
+ flow_ring_node->active = FALSE;
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id));
return BCME_ERROR;
}
@@ -688,7 +805,14 @@
return BCME_OK;
} else {
/* if the Flow id was found in the hash */
- ASSERT(id < dhdp->num_flow_rings);
+
+ if (id >= dhdp->num_flow_rings) {
+ DHD_ERROR(("%s: Invalid flow id : %u, num_flow_rings : %u\n",
+ __FUNCTION__, id, dhdp->num_flow_rings));
+ *flowid = FLOWID_INVALID;
+ ASSERT(0);
+ return BCME_ERROR;
+ }
flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id];
DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
@@ -709,21 +833,74 @@
* active is made TRUE when a flow_ring_node gets allocated and is made
* FALSE when the flow ring gets removed and does not reflect the True state
* of the Flow ring.
+ * In case if IDLE_TX_FLOW_MGMT is defined, we have to handle two more flowring
+ * states. If the flow_ring_node's status is FLOW_RING_STATUS_SUSPENDED, the flowid
+ * is to be returned and from dhd_bus_txdata, the flowring would be resumed again.
+ * The status FLOW_RING_STATUS_RESUME_PENDING, is equivalent to
+ * FLOW_RING_STATUS_CREATE_PENDING.
*/
- if (flow_ring_node->status == FLOW_RING_STATUS_OPEN ||
- flow_ring_node->status == FLOW_RING_STATUS_PENDING) {
- *flowid = id;
- ret = BCME_OK;
- } else {
+ if (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING ||
+ flow_ring_node->status == FLOW_RING_STATUS_CLOSED) {
*flowid = FLOWID_INVALID;
ret = BCME_ERROR;
+ } else {
+ *flowid = id;
+ ret = BCME_OK;
}
DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
return ret;
-
} /* Flow Id found in the hash */
} /* dhd_flowid_lookup */
+
+int
+dhd_flowid_find_by_ifidx(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid)
+{
+ int hashidx = 0;
+ bool found = FALSE;
+ flow_hash_info_t *cur;
+ if_flow_lkup_t *if_flow_lkup;
+ unsigned long flags;
+
+ if (!dhdp->flow_ring_table) {
+ DHD_ERROR(("%s : dhd->flow_ring_table is NULL\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+ for (hashidx = 0; hashidx < DHD_FLOWRING_HASH_SIZE; hashidx++) {
+ cur = if_flow_lkup[ifindex].fl_hash[hashidx];
+ if (cur) {
+ if (cur->flowid == flowid) {
+ found = TRUE;
+ }
+
+ while (!found && cur) {
+ if (cur->flowid == flowid) {
+ found = TRUE;
+ break;
+ }
+ cur = cur->next;
+ }
+
+ if (found) {
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ return BCME_OK;
+ }
+ }
+ }
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+
+ return BCME_ERROR;
+}
+
+int
+dhd_flowid_debug_create(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 prio, char *sa, char *da, uint16 *flowid)
+{
+ return dhd_flowid_lookup(dhdp, ifindex, prio, sa, da, flowid);
+}
/**
* Assign existing or newly created flowid to an 802.3 packet. This flowid is later on used to
@@ -734,7 +911,7 @@
{
uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
struct ether_header *eh = (struct ether_header *)pktdata;
- uint16 flowid;
+ uint16 flowid = 0;
ASSERT(ifindex < DHD_MAX_IFS);
@@ -747,7 +924,7 @@
return BCME_ERROR;
}
- if (dhd_flowid_lookup(dhdp, ifindex, prio, eh->ether_shost, eh->ether_dhost,
+ if (dhd_flowid_lookup(dhdp, ifindex, prio, (char *)eh->ether_shost, (char *)eh->ether_dhost,
&flowid) != BCME_OK) {
return BCME_ERROR;
}
@@ -767,9 +944,16 @@
flow_hash_info_t *cur, *prev;
if_flow_lkup_t *if_flow_lkup;
unsigned long flags;
+ bool if_role_multi_client;
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return;
DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+ if_role_multi_client = DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex);
for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) {
@@ -796,6 +980,11 @@
prev->next = cur->next;
}
+ /* Decrement multi_client_flow_rings */
+ if (if_role_multi_client) {
+ dhdp->multi_client_flow_rings--;
+ }
+
/* deregister flowid from dhd_pub. */
dhd_del_flowid(dhdp, ifindex, flowid);
@@ -814,11 +1003,37 @@
} /* dhd_flowid_free */
/**
- * Delete all Flow rings associated with the given interface. Is called when e.g. the dongle
+ * Delete all Flow rings associated with the given interface. Is called when eg the dongle
* indicates that a wireless link has gone down.
*/
void
dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex)
+{
+ uint32 id;
+ flow_ring_table_t *flow_ring_table;
+
+ DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex));
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return;
+
+ if (!dhdp->flow_ring_table)
+ return;
+
+ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+ for (id = 0; id < dhdp->num_flow_rings; id++) {
+ if (flow_ring_table[id].active &&
+ (flow_ring_table[id].flow_info.ifindex == ifindex) &&
+ (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) {
+ dhd_bus_flow_ring_delete_request(dhdp->bus,
+ (void *) &flow_ring_table[id]);
+ }
+ }
+}
+
+void
+dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex)
{
uint32 id;
flow_ring_table_t *flow_ring_table;
@@ -831,12 +1046,13 @@
if (!dhdp->flow_ring_table)
return;
-
flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+
for (id = 0; id < dhdp->num_flow_rings; id++) {
if (flow_ring_table[id].active &&
- (flow_ring_table[id].flow_info.ifindex == ifindex)) {
- dhd_bus_flow_ring_delete_request(dhdp->bus,
+ (flow_ring_table[id].flow_info.ifindex == ifindex) &&
+ (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) {
+ dhd_bus_flow_ring_flush_request(dhdp->bus,
(void *) &flow_ring_table[id]);
}
}
@@ -860,11 +1076,21 @@
flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
for (id = 0; id < dhdp->num_flow_rings; id++) {
+ /*
+ * Send flowring delete request even if flowring status is
+ * FLOW_RING_STATUS_CREATE_PENDING, to handle cases where DISASSOC_IND
+ * event comes ahead of flowring create response.
+ * Otherwise the flowring will not be deleted later as there will not be any
+ * DISASSOC_IND event. With this change, when create response event comes to DHD,
+ * it will change the status to FLOW_RING_STATUS_OPEN and soon delete response
+ * event will come, upon which DHD will delete the flowring.
+ */
if (flow_ring_table[id].active &&
(flow_ring_table[id].flow_info.ifindex == ifindex) &&
(!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) &&
- (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) {
- DHD_INFO(("%s: deleting flowid %d\n",
+ ((flow_ring_table[id].status == FLOW_RING_STATUS_OPEN) ||
+ (flow_ring_table[id].status == FLOW_RING_STATUS_CREATE_PENDING))) {
+ DHD_ERROR(("%s: deleting flowid %d\n",
__FUNCTION__, flow_ring_table[id].flowid));
dhd_bus_flow_ring_delete_request(dhdp->bus,
(void *) &flow_ring_table[id]);
@@ -898,14 +1124,19 @@
if_flow_lkup[ifindex].role = role;
- if (role != WLC_E_IF_ROLE_STA) {
- /* Flowrings has to be created for WDS and DWDS when interface is created */
+ if (role == WLC_E_IF_ROLE_WDS) {
+ /**
+ * WDS role does not send WLC_E_LINK event after interface is up.
+ * So to create flowrings for WDS, make status as TRUE in WLC_E_IF itself.
+ * same is true while making the status as FALSE.
+ * TODO: Fix FW to send WLC_E_LINK for WDS role aswell. So that all the
+ * interfaces are handled uniformly.
+ */
if_flow_lkup[ifindex].status = TRUE;
DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n",
__FUNCTION__, ifindex, role));
- /* Create Mcast Flow */
}
- } else if (op == WLC_E_IF_DEL) {
+ } else if ((op == WLC_E_IF_DEL) && (role == WLC_E_IF_ROLE_WDS)) {
if_flow_lkup[ifindex].status = FALSE;
DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n",
__FUNCTION__, ifindex, role));
@@ -929,12 +1160,12 @@
DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
- if (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) {
- if (status)
- if_flow_lkup[ifindex].status = TRUE;
- else
- if_flow_lkup[ifindex].status = FALSE;
+ if (status) {
+ if_flow_lkup[ifindex].status = TRUE;
+ } else {
+ if_flow_lkup[ifindex].status = FALSE;
}
+
DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
return BCME_OK;
@@ -971,6 +1202,8 @@
else
bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+ dhdp->max_multi_client_flow_rings = dhd_get_max_multi_client_flow_rings(dhdp);
+
return BCME_OK;
}
@@ -978,8 +1211,13 @@
int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set)
{
uint8 iovbuf[24];
+ int len;
if (!set) {
- bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf));
+ memset(&iovbuf, 0, sizeof(iovbuf));
+ len = bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf));
+ if (len == 0) {
+ return BCME_BUFTOOSHORT;
+ }
if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) {
DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__));
return BCME_ERROR;
@@ -987,8 +1225,11 @@
*map = iovbuf[0];
return BCME_OK;
}
- bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf));
- if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
+ len = bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf));
+ if (len == 0) {
+ return BCME_BUFTOOSHORT;
+ }
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0) < 0) {
DHD_ERROR(("%s: failed to set fl_prio_map \n",
__FUNCTION__));
return BCME_ERROR;
--
Gitblit v1.6.2