Commit 456d0685 authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville

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: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3b81a680
......@@ -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;
}
static void
brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
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->occupied) {
qidx = 2 * fifo;
if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
qidx++;
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);
pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
if (pktout == NULL) {
brcmf_err("delay queue full\n");
brcmf_err("%s queue %d full\n", entry->name, qidx);
rc = -ENOSPC;
}
/* free the hanger slot */
brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &pktout,
true);
/* decrement sequence count */
entry->seq[fifo]--;
}
} 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 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
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;
brcmf_fws_unlock(drvr, flags);
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);
return 0;
}
......
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