/*
* sk_buff control if flags
*
- * b[11] - packet sent upon firmware request.
+ * b[12] - packet sent upon credit request.
+ * b[11] - packet sent upon packet request.
* b[10] - packet only contains signalling data.
* b[9] - packet is a tx packet.
* b[8] - packet uses FIFO credit (non-pspoll).
* b[7] - interface in AP mode.
* b[3:0] - interface index.
*/
+#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_MASK 0x1000
+#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_SHIFT 12
#define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK 0x0800
#define BRCMF_SKB_IF_FLAGS_REQUESTED_SHIFT 11
#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_MASK 0x0400
return BRCMF_FWS_RET_OK_SCHEDULE;
}
+static int brcmf_fws_macdesc_use_credit(struct brcmf_fws_mac_descriptor *entry,
+ struct sk_buff *skb)
+{
+ int use_credit = 1;
+
+ if (entry->state == BRCMF_FWS_STATE_CLOSE) {
+ if (entry->requested_credit > 0) {
+ /*
+ * if the packet was pulled out while destination is in
+ * closed state but had a non-zero packets requested,
+ * then this should not count against the FIFO credit.
+ * That is due to the fact that the firmware will
+ * most likely hold onto this packet until a suitable
+ * time later to push it to the appropriate AC FIFO.
+ */
+ entry->requested_credit--;
+ brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
+ use_credit = 0;
+ } else if (entry->requested_packet > 0) {
+ entry->requested_packet--;
+ brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
+ use_credit = 0;
+ }
+ } else {
+ WARN_ON(entry->requested_credit);
+ WARN_ON(entry->requested_packet);
+ }
+ brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
+ return use_credit;
+}
+
static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
u8 fifo, u8 credits)
{
if (brcmf_skbcb(p)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
brcmf_fws_return_credits(fws, fifo, 1);
- else if (!brcmf_skb_if_flags_get_field(p, REQUESTED))
+ else if (brcmf_skb_if_flags_get_field(p, REQ_CREDIT) &&
+ entry->state == BRCMF_FWS_STATE_CLOSE)
/*
* if this packet did not count against FIFO credit, it
- * must have taken a requested_credit from the destination
+ * could have taken a requested_credit from the destination
* entry (for pspoll etc.)
*/
entry->requested_credit++;
struct brcmf_fws_mac_descriptor *table;
struct brcmf_fws_mac_descriptor *entry;
struct sk_buff *p;
- int use_credit = 1;
int num_nodes;
int node_pos;
int prec_out;
if (p == NULL)
continue;
- /* did the packet come from suppress sub-queue? */
- if (entry->requested_credit > 0) {
- entry->requested_credit--;
- /*
- * if the packet was pulled out while destination is in
- * closed state but had a non-zero packets requested,
- * then this should not count against the FIFO credit.
- * That is due to the fact that the firmware will
- * most likely hold onto this packet until a suitable
- * time later to push it to the appropriate AC FIFO.
- */
- if (entry->state == BRCMF_FWS_STATE_CLOSE)
- use_credit = 0;
- } else if (entry->requested_packet > 0) {
- entry->requested_packet--;
- brcmf_skb_if_flags_set_field(p, REQUESTED, 1);
- if (entry->state == BRCMF_FWS_STATE_CLOSE)
- use_credit = 0;
- }
- brcmf_skb_if_flags_set_field(p, CREDITCHECK, use_credit);
+ brcmf_fws_macdesc_use_credit(entry, p);
/* move dequeue position to ensure fair round-robin */
fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
/* decrement sequence count */
entry->seq[fifo]--;
}
- /*
- if this packet did not count against FIFO credit, it must have
- taken a requested_credit from the firmware (for pspoll etc.)
- */
- if (!(brcmf_skbcb(skb)->if_flags &
- BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK))
- entry->requested_credit++;
} else {
brcmf_err("no mac entry linked\n");
rc = -ENOENT;
fail:
if (rc) {
- brcmf_txfinalize(fws->drvr, skb, false);
+ brcmf_fws_bustxfail(fws, skb);
fws->stats.rollback_failed++;
- } else
+ } else {
fws->stats.rollback_success++;
+ brcmf_fws_skb_pickup_credit(fws, fifo, skb);
+ }
}
static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
{
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
int *credit = &fws->fifo_credit[fifo];
- int use_credit = 1;
brcmf_dbg(TRACE, "enter: ac=%d, credits=%d\n", fifo, *credit);
- if (entry->requested_credit > 0) {
- /*
- * if the packet was pulled out while destination is in
- * closed state but had a non-zero packets requested,
- * then this should not count against the FIFO credit.
- * That is due to the fact that the firmware will
- * most likely hold onto this packet until a suitable
- * time later to push it to the appropriate AC FIFO.
- */
- entry->requested_credit--;
- if (entry->state == BRCMF_FWS_STATE_CLOSE)
- use_credit = 0;
- } else if (entry->requested_packet > 0) {
- entry->requested_packet--;
- brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
- if (entry->state == BRCMF_FWS_STATE_CLOSE)
- use_credit = 0;
- }
- brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
- if (!use_credit) {
+ if (!brcmf_fws_macdesc_use_credit(entry, skb)) {
brcmf_dbg(TRACE, "exit: no creditcheck set\n");
return 0;
}
drvr->fws->fifo_delay_map |= 1 << fifo;
brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
} else {
- if (brcmf_fws_commit_skb(fws, fifo, skb))
- if (!multicast)
- brcmf_fws_skb_pickup_credit(fws, fifo, skb);
+ brcmf_fws_commit_skb(fws, fifo, skb);
}
brcmf_fws_unlock(drvr, flags);
return 0;
struct sk_buff *skb;
ulong flags;
int fifo;
- int credit;
fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
fifo--) {
brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
fws->fifo_credit[fifo]);
- for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
+ while (fws->fifo_credit[fifo]) {
skb = brcmf_fws_deq(fws, fifo);
- if (!skb || brcmf_fws_commit_skb(fws, fifo, skb))
+ if (!skb)
break;
if (brcmf_skbcb(skb)->if_flags &
BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
- credit++;
+ fws->fifo_credit[fifo]--;
+
+ if (brcmf_fws_commit_skb(fws, fifo, skb))
+ break;
if (fws->bus_flow_blocked)
break;
}
if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
- (credit == fws->fifo_credit[fifo]) &&
+ (fws->fifo_credit[fifo] == 0) &&
(!fws->bus_flow_blocked)) {
- fws->fifo_credit[fifo] -= credit;
while (brcmf_fws_borrow_credit(fws) == 0) {
skb = brcmf_fws_deq(fws, fifo);
if (!skb) {
brcmf_fws_return_credits(fws, fifo, 1);
break;
}
- if (brcmf_fws_commit_skb(fws, fifo, skb)) {
- brcmf_fws_return_credits(fws, fifo, 1);
- break;
- }
+ brcmf_fws_commit_skb(fws, fifo, skb);
if (fws->bus_flow_blocked)
break;
}
- } else {
- fws->fifo_credit[fifo] -= credit;
}
}
brcmf_fws_unlock(fws->drvr, flags);