brcmfmac: Fix msgbuf flow control.

Msgbuf flow control was using a function to flow off and on which
was not supported without proptx enabled. Also flow control needs
to be handled per ifidx.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Hante Meuleman 2014-07-30 13:20:06 +02:00 committed by John W. Linville
parent bd4f82e3b2
commit 17ca5c7184
3 changed files with 62 additions and 8 deletions

View File

@ -121,12 +121,12 @@ struct brcmf_fws_mac_descriptor;
*
* @BRCMF_NETIF_STOP_REASON_FWS_FC:
* netif stopped due to firmware signalling flow control.
* @BRCMF_NETIF_STOP_REASON_BLOCK_BUS:
* netif stopped due to bus blocking.
* @BRCMF_NETIF_STOP_REASON_FLOW:
* netif stopped due to flowring full.
*/
enum brcmf_netif_stop_reason {
BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
BRCMF_NETIF_STOP_REASON_BLOCK_BUS = 2
BRCMF_NETIF_STOP_REASON_FLOW = 2
};
/**

View File

@ -158,6 +158,51 @@ u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
}
static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
bool blocked)
{
struct brcmf_flowring_ring *ring;
struct brcmf_bus *bus_if;
struct brcmf_pub *drvr;
struct brcmf_if *ifp;
bool currently_blocked;
int i;
u8 ifidx;
unsigned long flags;
spin_lock_irqsave(&flow->block_lock, flags);
ring = flow->rings[flowid];
ifidx = brcmf_flowring_ifidx_get(flow, flowid);
currently_blocked = false;
for (i = 0; i < flow->nrofrings; i++) {
if (flow->rings[i]) {
ring = flow->rings[i];
if ((ring->status == RING_OPEN) &&
(brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
if (ring->blocked) {
currently_blocked = true;
break;
}
}
}
}
ring->blocked = blocked;
if (currently_blocked == blocked) {
spin_unlock_irqrestore(&flow->block_lock, flags);
return;
}
bus_if = dev_get_drvdata(flow->dev);
drvr = bus_if->drvr;
ifp = drvr->iflist[ifidx];
brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
spin_unlock_irqrestore(&flow->block_lock, flags);
}
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
{
struct brcmf_flowring_ring *ring;
@ -167,6 +212,7 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
ring = flow->rings[flowid];
if (!ring)
return;
brcmf_flowring_block(flow, flowid, false);
hash_idx = ring->hash_id;
flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
memset(flow->hash[hash_idx].mac, 0, ETH_ALEN);
@ -193,9 +239,16 @@ void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
if (!ring->blocked &&
(skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
brcmf_txflowblock(flow->dev, true);
brcmf_flowring_block(flow, flowid, true);
brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
ring->blocked = 1;
/* To prevent (work around) possible race condition, check
* queue len again. It is also possible to use locking to
* protect, but that is undesirable for every enqueue and
* dequeue. This simple check will solve a possible race
* condition if it occurs.
*/
if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
brcmf_flowring_block(flow, flowid, false);
}
}
@ -213,9 +266,8 @@ struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
if (ring->blocked &&
(skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
brcmf_txflowblock(flow->dev, false);
brcmf_flowring_block(flow, flowid, false);
brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
ring->blocked = 0;
}
return skb;
@ -283,6 +335,7 @@ struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
if (flow) {
flow->dev = dev;
flow->nrofrings = nrofrings;
spin_lock_init(&flow->block_lock);
for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
flow->addr_mode[i] = ADDR_INDIRECT;
for (i = 0; i < ARRAY_SIZE(flow->hash); i++)

View File

@ -35,7 +35,7 @@ enum ring_status {
struct brcmf_flowring_ring {
u8 hash_id;
u8 blocked;
bool blocked;
enum ring_status status;
struct sk_buff_head skblist;
};
@ -44,6 +44,7 @@ struct brcmf_flowring {
struct device *dev;
struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];
struct brcmf_flowring_ring **rings;
spinlock_t block_lock;
enum proto_addr_mode addr_mode[BRCMF_MAX_IFS];
u16 nrofrings;
};