}
}
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+ bool success)
{
- u8 ifidx;
+ struct brcmf_if *ifp;
struct ethhdr *eh;
+ u8 ifidx;
u16 type;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_if *ifp;
int res;
res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);
ifp = drvr->iflist[ifidx];
if (!ifp)
- goto done;
+ return;
if (res == 0) {
eh = (struct ethhdr *)(txp->data);
}
if (!success)
ifp->stats.tx_errors++;
+}
-done:
+void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ /* await txstatus signal for firmware is active */
+ if (success && brcmf_fws_fc_active(drvr->fws))
+ return;
+
+ brcmf_txfinalize(drvr, txp, success);
brcmu_pkt_buf_free_skb(txp);
}
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
+#include <linux/module.h>
#include <linux/if_ether.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#define BRCMF_FWS_STATE_OPEN 1
#define BRCMF_FWS_STATE_CLOSE 2
-#define BRCMF_FWS_FCMODE_NONE 0
-#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT 1
-#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 2
-
#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
#define BRCMF_FWS_MAX_IFNUM 16
#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
+enum brcmf_fws_fcmode {
+ BRCMF_FWS_FCMODE_NONE,
+ BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
+ BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
+};
+
/**
* struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
*
struct brcmf_fws_hanger hanger;
struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
struct brcmf_fws_mac_descriptor other;
+ enum brcmf_fws_fcmode fcmode;
int fifo_credit[NL80211_NUM_ACS+1+1];
};
+static int fcmode;
+module_param(fcmode, int, S_IRUSR);
+MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
+
/**
* brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
*/
/* set linkage back */
drvr->fws->drvr = drvr;
+ drvr->fws->fcmode = fcmode;
/* TODO: remove upon feature delivery */
brcmf_err("%s bdcv2 tlv signaling [%x]\n",
brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
kfree(entry);
}
+
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
+{
+ if (!fws)
+ return false;
+
+ brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode);
+ return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
+}