提交 17ca5c71 编写于 作者: H Hante Meuleman 提交者: John W. Linville

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: NArend Van Spriel <arend@broadcom.com>
Reviewed-by: NFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: NPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: NDaniel (Deognyoun) Kim <dekim@broadcom.com>
Signed-off-by: NHante Meuleman <meuleman@broadcom.com>
Signed-off-by: NArend van Spriel <arend@broadcom.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 bd4f82e3
......@@ -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
};
/**
......
......@@ -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++)
......
......@@ -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;
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册