Commit be4910ad authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville

brcmfmac: For FW signalling it is necessary to track gen bit.

Store gen bit on suppressed packet per entry and use latest
stored version for each packet which gets transmitted to fw.
Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ce17194e
...@@ -384,12 +384,10 @@ enum brcmf_fws_hanger_item_state { ...@@ -384,12 +384,10 @@ enum brcmf_fws_hanger_item_state {
* struct brcmf_fws_hanger_item - single entry for tx pending packet. * struct brcmf_fws_hanger_item - single entry for tx pending packet.
* *
* @state: entry is either free or occupied. * @state: entry is either free or occupied.
* @gen: generation.
* @pkt: packet itself. * @pkt: packet itself.
*/ */
struct brcmf_fws_hanger_item { struct brcmf_fws_hanger_item {
enum brcmf_fws_hanger_item_state state; enum brcmf_fws_hanger_item_state state;
u8 gen;
struct sk_buff *pkt; struct sk_buff *pkt;
}; };
...@@ -571,20 +569,17 @@ static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h, ...@@ -571,20 +569,17 @@ static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
if (remove_item) { if (remove_item) {
h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE; h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
h->items[slot_id].pkt = NULL; h->items[slot_id].pkt = NULL;
h->items[slot_id].gen = 0xff;
h->popped++; h->popped++;
} }
return 0; return 0;
} }
static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h, static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
u32 slot_id, u8 gen) u32 slot_id)
{ {
if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS) if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
return -ENOENT; return -ENOENT;
h->items[slot_id].gen = gen;
if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_INUSE) { if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_INUSE) {
brcmf_err("entry not in use\n"); brcmf_err("entry not in use\n");
return -EINVAL; return -EINVAL;
...@@ -594,24 +589,6 @@ static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h, ...@@ -594,24 +589,6 @@ static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
return 0; return 0;
} }
static int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
struct sk_buff *pkt, u32 slot_id,
int *gen)
{
*gen = 0xff;
if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
return -ENOENT;
if (hanger->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
brcmf_err("slot not in use\n");
return -EINVAL;
}
*gen = hanger->items[slot_id].gen;
return 0;
}
static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws, static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
bool (*fn)(struct sk_buff *, void *), bool (*fn)(struct sk_buff *, void *),
int ifidx) int ifidx)
...@@ -838,9 +815,6 @@ brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq, ...@@ -838,9 +815,6 @@ brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
if (WARN_ON(!ifp)) if (WARN_ON(!ifp))
return; return;
brcmf_dbg(TRACE,
"enter: bssidx=%d, ifidx=%d\n", ifp->bssidx, ifp->ifidx);
if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) && if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER) pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
brcmf_txflowblock_if(ifp, brcmf_txflowblock_if(ifp,
...@@ -1220,7 +1194,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, ...@@ -1220,7 +1194,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
/* this packet was suppressed */ /* this packet was suppressed */
if (!entry->suppressed || entry->generation != genbit) { if (!entry->suppressed) {
entry->suppressed = true; entry->suppressed = true;
entry->suppress_count = brcmu_pktq_mlen(&entry->psq, entry->suppress_count = brcmu_pktq_mlen(&entry->psq,
1 << (fifo * 2 + 1)); 1 << (fifo * 2 + 1));
...@@ -1242,8 +1216,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, ...@@ -1242,8 +1216,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
* Mark suppressed to avoid a double free during * Mark suppressed to avoid a double free during
* wlfc cleanup * wlfc cleanup
*/ */
brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot, brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
genbit);
entry->suppress_count++; entry->suppress_count++;
} }
...@@ -1573,15 +1546,34 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, ...@@ -1573,15 +1546,34 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p); struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
struct brcmf_fws_mac_descriptor *entry = skcb->mac; struct brcmf_fws_mac_descriptor *entry = skcb->mac;
int rc = 0; int rc = 0;
bool header_needed; bool first_time;
int hslot = BRCMF_FWS_HANGER_MAXITEMS; int hslot = BRCMF_FWS_HANGER_MAXITEMS;
u8 free_ctr; u8 free_ctr;
u8 ifidx; u8 ifidx;
u8 flags; u8 flags;
header_needed = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED; first_time = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
if (header_needed) { if (!first_time) {
rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, p);
if (rc) {
brcmf_err("hdrpull failed\n");
return rc;
}
}
brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
if (!(skcb->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)) {
/*
* Indicate that this packet is being sent in response to an
* explicit request from the firmware side.
*/
flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
}
brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
if (first_time) {
/* obtaining free slot may fail, but that will be caught /* obtaining free slot may fail, but that will be caught
* by the hanger push. This assures the packet has a BDC * by the hanger push. This assures the packet has a BDC
* header upon return. * header upon return.
...@@ -1590,40 +1582,14 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, ...@@ -1590,40 +1582,14 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
free_ctr = entry->seq[fifo]; free_ctr = entry->seq[fifo];
brcmf_skb_htod_tag_set_field(p, HSLOT, hslot); brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr); brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr);
brcmf_skb_htod_tag_set_field(p, GENERATION, 1);
entry->transit_count++; entry->transit_count++;
} }
brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
if (!(skcb->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)) {
/*
Indicate that this packet is being sent in response to an
explicit request from the firmware side.
*/
flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
}
brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
if (header_needed) {
brcmf_fws_hdrpush(fws, p); brcmf_fws_hdrpush(fws, p);
if (first_time) {
rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot); rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
if (rc) if (rc)
brcmf_err("hanger push failed: rc=%d\n", rc); brcmf_err("hanger push failed: rc=%d\n", rc);
} else {
int gen;
/* remove old header */
rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, p);
if (rc == 0) {
hslot = brcmf_skb_htod_tag_get_field(p, HSLOT);
brcmf_fws_hanger_get_genbit(&fws->hanger, p,
hslot, &gen);
brcmf_skb_htod_tag_set_field(p, GENERATION, gen);
/* push new header */
brcmf_fws_hdrpush(fws, p);
}
} }
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment