summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-06-26 14:35:10 +0200
committerJohn W. Linville <linville@tuxdriver.com>2013-06-27 13:42:18 -0400
commit456d0685c7522c661bf5af7930317ffcb710a858 (patch)
treefc28559246844cbece0a7d0b7d587758bbee2d58 /drivers
parent3b81a6809480f3fc7d9d06562704c8df18ecec00 (diff)
brcmfmac: tag packet in the netdev transmit callback
Transmit packets needs to be tagged in order to receive a tx status feedback from the firmware. Determine the tag in the netdev transmit callback instead of determining the tag just before transfer to the device. This reduces the number of exception flows and hence makes the driver code simpler. Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c130
1 files changed, 48 insertions, 82 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index e4fd13af759..44b319292a5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -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;
}