|
@@ -192,24 +192,21 @@ struct brcmf_skbuff_cb {
|
|
|
/*
|
|
|
* sk_buff control if flags
|
|
|
*
|
|
|
- * b[12] - packet sent upon credit request.
|
|
|
- * b[11] - packet sent upon packet request.
|
|
|
+ * b[11] - packet sent upon firmware request.
|
|
|
* b[10] - packet only contains signalling data.
|
|
|
* b[9] - packet is a tx packet.
|
|
|
- * b[8] - packet uses FIFO credit (non-pspoll).
|
|
|
+ * b[8] - packet used requested credit
|
|
|
* 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
|
|
|
#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT 10
|
|
|
#define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK 0x0200
|
|
|
#define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT 9
|
|
|
-#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK 0x0100
|
|
|
-#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_SHIFT 8
|
|
|
+#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_MASK 0x0100
|
|
|
+#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_SHIFT 8
|
|
|
#define BRCMF_SKB_IF_FLAGS_IF_AP_MASK 0x0080
|
|
|
#define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT 7
|
|
|
#define BRCMF_SKB_IF_FLAGS_INDEX_MASK 0x000f
|
|
@@ -311,12 +308,15 @@ enum brcmf_fws_fifo {
|
|
|
* firmware suppress the packet as device is already in PS mode.
|
|
|
* @BRCMF_FWS_TXSTATUS_FW_TOSSED:
|
|
|
* firmware tossed the packet.
|
|
|
+ * @BRCMF_FWS_TXSTATUS_HOST_TOSSED:
|
|
|
+ * host tossed the packet.
|
|
|
*/
|
|
|
enum brcmf_fws_txstatus {
|
|
|
BRCMF_FWS_TXSTATUS_DISCARD,
|
|
|
BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
|
|
|
BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
|
|
|
- BRCMF_FWS_TXSTATUS_FW_TOSSED
|
|
|
+ BRCMF_FWS_TXSTATUS_FW_TOSSED,
|
|
|
+ BRCMF_FWS_TXSTATUS_HOST_TOSSED
|
|
|
};
|
|
|
|
|
|
enum brcmf_fws_fcmode {
|
|
@@ -639,6 +639,7 @@ static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
|
|
|
desc->occupied = 1;
|
|
|
desc->state = BRCMF_FWS_STATE_OPEN;
|
|
|
desc->requested_credit = 0;
|
|
|
+ desc->requested_packet = 0;
|
|
|
/* depending on use may need ifp->bssidx instead */
|
|
|
desc->interface_id = ifidx;
|
|
|
desc->ac_bitmap = 0xff; /* update this when handling APSD */
|
|
@@ -654,6 +655,7 @@ void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc)
|
|
|
desc->occupied = 0;
|
|
|
desc->state = BRCMF_FWS_STATE_CLOSE;
|
|
|
desc->requested_credit = 0;
|
|
|
+ desc->requested_packet = 0;
|
|
|
}
|
|
|
|
|
|
static struct brcmf_fws_mac_descriptor *
|
|
@@ -1050,35 +1052,35 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
|
|
|
return BRCMF_FWS_RET_OK_SCHEDULE;
|
|
|
}
|
|
|
|
|
|
-static int brcmf_fws_macdesc_use_credit(struct brcmf_fws_mac_descriptor *entry,
|
|
|
- struct sk_buff *skb)
|
|
|
+static void
|
|
|
+brcmf_fws_macdesc_use_req_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;
|
|
|
- }
|
|
|
+ if (entry->requested_credit > 0) {
|
|
|
+ entry->requested_credit--;
|
|
|
+ brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
|
|
|
+ brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
|
|
|
+ if (entry->state != BRCMF_FWS_STATE_CLOSE)
|
|
|
+ brcmf_err("requested credit set while mac not closed!\n");
|
|
|
+ } else if (entry->requested_packet > 0) {
|
|
|
+ entry->requested_packet--;
|
|
|
+ brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
|
|
|
+ brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
|
|
|
+ if (entry->state != BRCMF_FWS_STATE_CLOSE)
|
|
|
+ brcmf_err("requested packet set while mac not closed!\n");
|
|
|
} else {
|
|
|
- WARN_ON(entry->requested_credit);
|
|
|
- WARN_ON(entry->requested_packet);
|
|
|
+ brcmf_skb_if_flags_set_field(skb, REQUESTED, 0);
|
|
|
+ brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
|
|
|
}
|
|
|
- brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
|
|
|
- return use_credit;
|
|
|
+}
|
|
|
+
|
|
|
+static void brcmf_fws_macdesc_return_req_credit(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
|
|
|
+
|
|
|
+ if ((brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) &&
|
|
|
+ (entry->state == BRCMF_FWS_STATE_CLOSE))
|
|
|
+ entry->requested_credit++;
|
|
|
}
|
|
|
|
|
|
static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
|
|
@@ -1124,25 +1126,6 @@ static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
|
|
|
queue_work(fws->fws_wq, &fws->fws_dequeue_work);
|
|
|
}
|
|
|
|
|
|
-static void brcmf_fws_skb_pickup_credit(struct brcmf_fws_info *fws, int fifo,
|
|
|
- struct sk_buff *p)
|
|
|
-{
|
|
|
- struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(p)->mac;
|
|
|
-
|
|
|
- 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, REQ_CREDIT) &&
|
|
|
- entry->state == BRCMF_FWS_STATE_CLOSE)
|
|
|
- /*
|
|
|
- * if this packet did not count against FIFO credit, it
|
|
|
- * could have taken a requested_credit from the destination
|
|
|
- * entry (for pspoll etc.)
|
|
|
- */
|
|
|
- entry->requested_credit++;
|
|
|
-
|
|
|
- brcmf_fws_schedule_deq(fws);
|
|
|
-}
|
|
|
-
|
|
|
static int brcmf_fws_enq(struct brcmf_fws_info *fws,
|
|
|
enum brcmf_fws_skb_state state, int fifo,
|
|
|
struct sk_buff *p)
|
|
@@ -1224,7 +1207,7 @@ static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
|
|
|
if (p == NULL)
|
|
|
continue;
|
|
|
|
|
|
- brcmf_fws_macdesc_use_credit(entry, p);
|
|
|
+ brcmf_fws_macdesc_use_req_credit(entry, p);
|
|
|
|
|
|
/* move dequeue position to ensure fair round-robin */
|
|
|
fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
|
|
@@ -1313,7 +1296,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
|
|
|
} else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
|
|
|
fws->stats.txs_supp_ps++;
|
|
|
remove_from_hanger = false;
|
|
|
- } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
|
|
|
+ } else if ((flags == BRCMF_FWS_TXSTATUS_FW_TOSSED) ||
|
|
|
+ (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED))
|
|
|
fws->stats.txs_tossed++;
|
|
|
else
|
|
|
brcmf_err("unexpected txstatus\n");
|
|
@@ -1340,9 +1324,13 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
|
|
|
|
|
|
/* pick up the implicit credit from this packet */
|
|
|
fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
|
|
|
- if (fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT ||
|
|
|
- !(brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK))
|
|
|
- brcmf_fws_skb_pickup_credit(fws, fifo, skb);
|
|
|
+ if ((fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT) ||
|
|
|
+ (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
|
|
|
+ (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)) {
|
|
|
+ brcmf_fws_return_credits(fws, fifo, 1);
|
|
|
+ brcmf_fws_schedule_deq(fws);
|
|
|
+ }
|
|
|
+ brcmf_fws_macdesc_return_req_credit(skb);
|
|
|
|
|
|
if (!remove_from_hanger)
|
|
|
ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
|
|
@@ -1588,7 +1576,7 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
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)) {
|
|
|
+ if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
|
|
|
/*
|
|
|
* Indicate that this packet is being sent in response to an
|
|
|
* explicit request from the firmware side.
|
|
@@ -1636,6 +1624,7 @@ brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
|
|
|
|
|
|
state = brcmf_skbcb(skb)->state;
|
|
|
entry = brcmf_skbcb(skb)->mac;
|
|
|
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
|
|
|
|
|
|
if (entry != NULL) {
|
|
|
if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
|
|
@@ -1647,8 +1636,6 @@ brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
|
|
|
rc = -ENOSPC;
|
|
|
}
|
|
|
} else {
|
|
|
- hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
|
|
|
-
|
|
|
/* delay-q packets are going to delay-q */
|
|
|
pktout = brcmu_pktq_penq_head(&entry->psq,
|
|
|
2 * fifo, skb);
|
|
@@ -1670,11 +1657,13 @@ brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
|
|
|
}
|
|
|
|
|
|
if (rc) {
|
|
|
- brcmf_fws_bustxfail(fws, skb);
|
|
|
fws->stats.rollback_failed++;
|
|
|
+ brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
|
|
|
+ hslot, 0);
|
|
|
} else {
|
|
|
fws->stats.rollback_success++;
|
|
|
- brcmf_fws_skb_pickup_credit(fws, fifo, skb);
|
|
|
+ brcmf_fws_return_credits(fws, fifo, 1);
|
|
|
+ brcmf_fws_macdesc_return_req_credit(skb);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1708,26 +1697,28 @@ static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
|
|
|
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
|
|
|
int *credit = &fws->fifo_credit[fifo];
|
|
|
|
|
|
- if (!brcmf_fws_macdesc_use_credit(entry, skb))
|
|
|
- return 0;
|
|
|
-
|
|
|
if (fifo != BRCMF_FWS_FIFO_AC_BE)
|
|
|
fws->borrow_defer_timestamp = jiffies +
|
|
|
BRCMF_FWS_BORROW_DEFER_PERIOD;
|
|
|
|
|
|
if (!(*credit)) {
|
|
|
/* Try to borrow a credit from other queue */
|
|
|
- if (fifo == BRCMF_FWS_FIFO_AC_BE &&
|
|
|
- brcmf_fws_borrow_credit(fws) == 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- brcmf_dbg(DATA, "exit: ac=%d, credits depleted\n", fifo);
|
|
|
- return -ENAVAIL;
|
|
|
+ if (fifo != BRCMF_FWS_FIFO_AC_BE ||
|
|
|
+ (brcmf_fws_borrow_credit(fws) != 0)) {
|
|
|
+ brcmf_dbg(DATA, "ac=%d, credits depleted\n", fifo);
|
|
|
+ return -ENAVAIL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ (*credit)--;
|
|
|
+ if (!(*credit))
|
|
|
+ fws->fifo_credit_map &= ~(1 << fifo);
|
|
|
}
|
|
|
- (*credit)--;
|
|
|
- if (!(*credit))
|
|
|
- fws->fifo_credit_map &= ~(1 << fifo);
|
|
|
- brcmf_dbg(DATA, "exit: ac=%d, credits=%d\n", fifo, *credit);
|
|
|
+
|
|
|
+ brcmf_fws_macdesc_use_req_credit(entry, skb);
|
|
|
+
|
|
|
+ brcmf_dbg(DATA, "ac=%d, credits=%02d:%02d:%02d:%02d\n", fifo,
|
|
|
+ fws->fifo_credit[0], fws->fifo_credit[1],
|
|
|
+ fws->fifo_credit[2], fws->fifo_credit[3]);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1764,8 +1755,8 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
entry->seq[fifo]++;
|
|
|
fws->stats.pkt2bus++;
|
|
|
fws->stats.send_pkts[fifo]++;
|
|
|
- if (brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
|
|
|
- fws->stats.fifo_credits_sent[fifo]++;
|
|
|
+ if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
|
|
|
+ fws->stats.requested_sent[fifo]++;
|
|
|
|
|
|
return rc;
|
|
|
|
|
@@ -1888,10 +1879,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
|
|
|
skb = brcmf_fws_deq(fws, fifo);
|
|
|
if (!skb)
|
|
|
break;
|
|
|
- if (brcmf_skbcb(skb)->if_flags &
|
|
|
- BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
|
|
|
- fws->fifo_credit[fifo]--;
|
|
|
-
|
|
|
+ fws->fifo_credit[fifo]--;
|
|
|
if (brcmf_fws_commit_skb(fws, fifo, skb))
|
|
|
break;
|
|
|
if (fws->bus_flow_blocked)
|
|
@@ -2023,20 +2011,15 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
|
|
|
void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
|
|
|
{
|
|
|
ulong flags;
|
|
|
- int fifo;
|
|
|
+ u32 hslot;
|
|
|
|
|
|
if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
|
|
|
brcmu_pkt_buf_free_skb(skb);
|
|
|
return;
|
|
|
}
|
|
|
brcmf_fws_lock(fws->drvr, flags);
|
|
|
- brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED,
|
|
|
- brcmf_skb_htod_tag_get_field(skb, HSLOT), 0);
|
|
|
- /* the packet never reached firmware so reclaim credit */
|
|
|
- if (fws->fcmode == BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
|
|
|
- fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
|
|
|
- brcmf_fws_skb_pickup_credit(fws, fifo, skb);
|
|
|
- }
|
|
|
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
|
|
|
+ brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0);
|
|
|
brcmf_fws_unlock(fws->drvr, flags);
|
|
|
}
|
|
|
|