|
@@ -1575,21 +1575,14 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
+static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
struct sk_buff *p)
|
|
|
{
|
|
|
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
|
|
|
struct brcmf_fws_mac_descriptor *entry = skcb->mac;
|
|
|
- int rc = 0;
|
|
|
- bool first_time;
|
|
|
- int hslot = BRCMF_FWS_HANGER_MAXITEMS;
|
|
|
- u8 free_ctr;
|
|
|
u8 flags;
|
|
|
|
|
|
- first_time = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
|
|
|
-
|
|
|
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 (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
|
|
@@ -1600,80 +1593,36 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
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
|
|
|
- * by the hanger push. This assures the packet has a BDC
|
|
|
- * header upon return.
|
|
|
- */
|
|
|
- hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
|
|
|
- free_ctr = entry->seq[fifo];
|
|
|
- brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
|
|
|
- brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr);
|
|
|
- rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
|
|
|
- if (rc)
|
|
|
- brcmf_err("hanger push failed: rc=%d\n", rc);
|
|
|
- }
|
|
|
-
|
|
|
- if (rc == 0)
|
|
|
- brcmf_fws_hdrpush(fws, p);
|
|
|
-
|
|
|
- return rc;
|
|
|
+ brcmf_fws_hdrpush(fws, p);
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
|
|
|
- struct sk_buff *skb, int fifo)
|
|
|
+static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
|
|
|
+ struct sk_buff *skb, int fifo)
|
|
|
{
|
|
|
- /*
|
|
|
- put the packet back to the head of queue
|
|
|
-
|
|
|
- - suppressed packet goes back to suppress sub-queue
|
|
|
- - pull out the header, if new or delayed packet
|
|
|
-
|
|
|
- Note: hslot is used only when header removal is done.
|
|
|
- */
|
|
|
struct brcmf_fws_mac_descriptor *entry;
|
|
|
- enum brcmf_fws_skb_state state;
|
|
|
struct sk_buff *pktout;
|
|
|
+ int qidx, hslot;
|
|
|
int rc = 0;
|
|
|
- int hslot;
|
|
|
|
|
|
- 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) {
|
|
|
- /* wl-header is saved for suppressed packets */
|
|
|
- pktout = brcmu_pktq_penq_head(&entry->psq, 2 * fifo + 1,
|
|
|
- skb);
|
|
|
- if (pktout == NULL) {
|
|
|
- brcmf_err("suppress queue full\n");
|
|
|
- rc = -ENOSPC;
|
|
|
- }
|
|
|
- } else {
|
|
|
- /* delay-q packets are going to delay-q */
|
|
|
- pktout = brcmu_pktq_penq_head(&entry->psq,
|
|
|
- 2 * fifo, skb);
|
|
|
- if (pktout == NULL) {
|
|
|
- brcmf_err("delay queue full\n");
|
|
|
- rc = -ENOSPC;
|
|
|
- }
|
|
|
-
|
|
|
- /* free the hanger slot */
|
|
|
- brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &pktout,
|
|
|
- true);
|
|
|
-
|
|
|
- /* decrement sequence count */
|
|
|
- entry->seq[fifo]--;
|
|
|
+ if (entry->occupied) {
|
|
|
+ qidx = 2 * fifo;
|
|
|
+ if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
|
|
|
+ qidx++;
|
|
|
+
|
|
|
+ pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
|
|
|
+ if (pktout == NULL) {
|
|
|
+ brcmf_err("%s queue %d full\n", entry->name, qidx);
|
|
|
+ rc = -ENOSPC;
|
|
|
}
|
|
|
} else {
|
|
|
- brcmf_err("no mac entry linked\n");
|
|
|
+ brcmf_err("%s entry removed\n", entry->name);
|
|
|
rc = -ENOENT;
|
|
|
}
|
|
|
|
|
|
if (rc) {
|
|
|
fws->stats.rollback_failed++;
|
|
|
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
|
|
|
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
|
|
|
hslot, 0);
|
|
|
} else {
|
|
@@ -1720,15 +1669,10 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
if (IS_ERR(entry))
|
|
|
return PTR_ERR(entry);
|
|
|
|
|
|
- rc = brcmf_fws_precommit_skb(fws, fifo, skb);
|
|
|
- if (rc < 0) {
|
|
|
- fws->stats.generic_error++;
|
|
|
- goto rollback;
|
|
|
- }
|
|
|
-
|
|
|
- brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags,
|
|
|
- skcb->htod);
|
|
|
+ brcmf_fws_precommit_skb(fws, fifo, skb);
|
|
|
rc = brcmf_bus_txdata(bus, skb);
|
|
|
+ brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
|
|
|
+ skcb->if_flags, skcb->htod, rc);
|
|
|
if (rc < 0) {
|
|
|
brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
|
|
|
goto rollback;
|
|
@@ -1737,7 +1681,6 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
|
|
|
entry->transit_count++;
|
|
|
if (entry->suppressed)
|
|
|
entry->suppr_transit_count++;
|
|
|
- entry->seq[fifo]++;
|
|
|
fws->stats.pkt2bus++;
|
|
|
fws->stats.send_pkts[fifo]++;
|
|
|
if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
|
|
@@ -1750,6 +1693,24 @@ rollback:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
|
|
|
+ int fifo)
|
|
|
+{
|
|
|
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
|
|
|
+ int rc, hslot;
|
|
|
+
|
|
|
+ hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
|
|
|
+ brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
|
|
|
+ brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
|
|
|
+ brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
|
|
|
+ rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
|
|
|
+ if (!rc)
|
|
|
+ skcb->mac->seq[fifo]++;
|
|
|
+ else
|
|
|
+ fws->stats.generic_error++;
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
|
|
|
{
|
|
|
struct brcmf_pub *drvr = ifp->drvr;
|
|
@@ -1778,22 +1739,27 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
|
|
|
|
|
|
/* set control buffer information */
|
|
|
skcb->if_flags = 0;
|
|
|
- skcb->mac = brcmf_fws_macdesc_find(fws, ifp, eh->h_dest);
|
|
|
skcb->state = BRCMF_FWS_SKBSTATE_NEW;
|
|
|
brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
|
|
|
if (!multicast)
|
|
|
fifo = brcmf_fws_prio2fifo[skb->priority];
|
|
|
|
|
|
- brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
|
|
|
- eh->h_dest, multicast, fifo);
|
|
|
-
|
|
|
brcmf_fws_lock(drvr, flags);
|
|
|
- brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
|
|
|
if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
|
|
|
fws->borrow_defer_timestamp = jiffies +
|
|
|
BRCMF_FWS_BORROW_DEFER_PERIOD;
|
|
|
+
|
|
|
+ skcb->mac = brcmf_fws_macdesc_find(fws, ifp, eh->h_dest);
|
|
|
+ brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
|
|
|
+ eh->h_dest, multicast, fifo);
|
|
|
+ if (!brcmf_fws_assign_htod(fws, skb, fifo)) {
|
|
|
+ brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
|
|
|
+ brcmf_fws_schedule_deq(fws);
|
|
|
+ } else {
|
|
|
+ brcmf_err("drop skb: no hanger slot\n");
|
|
|
+ brcmu_pkt_buf_free_skb(skb);
|
|
|
+ }
|
|
|
brcmf_fws_unlock(drvr, flags);
|
|
|
- brcmf_fws_schedule_deq(fws);
|
|
|
return 0;
|
|
|
}
|
|
|
|