@@ -464,11 +464,12 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key,
}
static int
-send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
+__send_key_to_dongle(const char *c0, struct brcmf_if *ifp, struct brcmf_wsec_key *key)
{
int err;
struct brcmf_wsec_key_le key_le;
+ pr_info("[%s -> %s] ifp:%p brcmf_ifname(ifp):%s\n", c0, __func__, ifp, brcmf_ifname(ifp));
convert_key_from_CPU(key, &key_le);
brcmf_netdev_wait_pend8021x(ifp);
@@ -480,6 +481,7 @@ send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
brcmf_err("wsec_key error (%d)\n", err);
return err;
}
+#define send_key_to_dongle(ifp, key) __send_key_to_dongle(__func__, ifp, key)
static s32
brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
@@ -2610,6 +2612,8 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
int rssi;
u32 i;
+ brcmf_netdev_wait_pend8021x(ifp);
+
brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
if (!check_vif_up(ifp->vif))
return -EIO;
@@ -38,7 +38,52 @@
#include "pcie.h"
#include "common.h"
-#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
+#include <linux/sched.h>
+
+static size_t print_time(u64 ts, char *buf)
+{
+ unsigned long rem_nsec;
+
+ rem_nsec = do_div(ts, 1000000000);
+
+ if (!buf)
+ return snprintf(NULL, 0, "[%5lu.000000]", (unsigned long)ts);
+
+ return sprintf(buf, "[%5lu.%06lu]",
+ (unsigned long)ts, rem_nsec / 1000);
+}
+
+/* Free the driver packet. Free the tag if present */
+void __brcmu_pkt_buf_free_skb(const char *c0, struct brcmf_if *ifp, struct sk_buff *skb)
+{
+ if (!skb)
+ return;
+
+ if (ifp) {
+ struct pend_skb *e;
+
+ mutex_lock(&ifp->pend_8021x_mutex);
+ list_for_each_entry(e, &ifp->pend_8021x_skbs, list) {
+ if (e->skb == skb) {
+ pr_info("[%s -> %s] [ifp:%p] ***BUG*** skb:%p skb->dev:%p skb->dev->name:%s\n", c0, __func__, ifp, e->skb, e->skb->dev, e->skb->dev ? e->skb->dev->name : "---");
+ pr_info("[%s -> %s] [ifp:%p] Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", c0, __func__, ifp,
+ e->data[0x00], e->data[0x01], e->data[0x02], e->data[0x03], e->data[0x04], e->data[0x05], e->data[0x06], e->data[0x07], e->data[0x08], e->data[0x09], e->data[0x0a], e->data[0x0b], e->data[0x0c], e->data[0x0d]);
+ pr_info("[%s -> %s] [ifp:%p] Current data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", c0, __func__, ifp,
+ skb->data[0x00], skb->data[0x01], skb->data[0x02], skb->data[0x03], skb->data[0x04], skb->data[0x05], skb->data[0x06], skb->data[0x07], skb->data[0x08], skb->data[0x09], skb->data[0x0a], skb->data[0x0b], skb->data[0x0c], skb->data[0x0d]);
+ WARN_ON(1);
+ break;
+ }
+ }
+ mutex_unlock(&ifp->pend_8021x_mutex);
+ } else if (strcmp(c0, "brcmf_msgbuf_query_dcmd")) {
+ pr_info("[%s -> %s] [ifp:%p] Freeing skb:%p skb->dev:%p skb->dev->name:%s\n", c0, __func__, ifp, skb, skb->dev, skb->dev ? skb->dev->name : "---");
+ }
+
+ WARN_ON(skb->next);
+ dev_kfree_skb_any(skb);
+}
+
+#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(10)
#define BRCMF_BSSIDX_INVALID -1
@@ -247,8 +292,19 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}
- if (eh->h_proto == htons(ETH_P_PAE))
+ if (eh->h_proto == htons(ETH_P_PAE)) {
+ struct pend_skb *e;
+
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ e->skb = skb;
+ memcpy(e->data, skb->data, 14);
+ e->start_time = local_clock();
+
atomic_inc(&ifp->pend_8021x_cnt);
+ mutex_lock(&ifp->pend_8021x_mutex);
+ list_add_tail(&e->list, &ifp->pend_8021x_skbs);
+ mutex_unlock(&ifp->pend_8021x_mutex);
+ }
ret = brcmf_fws_process_skb(ifp, skb);
@@ -333,7 +389,7 @@ static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
if (ret || !(*ifp) || !(*ifp)->ndev) {
if (ret != -ENODATA && *ifp)
(*ifp)->stats.rx_errors++;
- brcmu_pkt_buf_free_skb(skb);
+ __brcmu_pkt_buf_free_skb(__func__, *ifp, skb);
return -ENODATA;
}
@@ -378,7 +434,7 @@ void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
brcmu_pkt_buf_free_skb(skb);
}
-void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
+void __brcmf_txfinalize(const char *c0, struct brcmf_if *ifp, struct sk_buff *txp, bool success)
{
struct ethhdr *eh;
u16 type;
@@ -387,7 +443,30 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
type = ntohs(eh->h_proto);
if (type == ETH_P_PAE) {
+ struct pend_skb *e, *tmp;
+
atomic_dec(&ifp->pend_8021x_cnt);
+ mutex_lock(&ifp->pend_8021x_mutex);
+ list_for_each_entry_safe(e, tmp, &ifp->pend_8021x_skbs, list) {
+ if (e->skb == txp) {
+ if (e->timedout) {
+ char start[32], commit[32];
+
+ print_time(e->start_time, start);
+ print_time(e->commit_time, commit);
+
+ pr_info("[%s -> %s] Finally finalizing skb:%p skb->dev:%p skb->dev->name:%s (start_time:%s; commit_time:%s)\n",
+ c0, __func__,
+ e->skb, e->skb->dev, e->skb->dev ? e->skb->dev->name : "---",
+ start, commit);
+ }
+
+ list_del(&e->list);
+ kfree(e);
+ break;
+ }
+ }
+ mutex_unlock(&ifp->pend_8021x_mutex);
if (waitqueue_active(&ifp->pend_8021x_wait))
wake_up(&ifp->pend_8021x_wait);
}
@@ -476,6 +555,8 @@ static int brcmf_netdev_open(struct net_device *ndev)
}
atomic_set(&ifp->pend_8021x_cnt, 0);
+ INIT_LIST_HEAD(&ifp->pend_8021x_skbs);
+ mutex_init(&ifp->pend_8021x_mutex);
/* Get current TOE mode from dongle */
if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
@@ -1169,7 +1250,20 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
!brcmf_get_pend_8021x_cnt(ifp),
MAX_WAIT_FOR_8021X_TX);
- WARN_ON(!err);
+ //WARN_ON(!err);
+ if (!err)
+ pr_info("[%s] ***TIMEOUT WARNING*** ifp:%p brcmf_ifname(ifp):%s brcmf_get_pend_8021x_cnt(ifp):%d\n", __func__, ifp, brcmf_ifname(ifp), brcmf_get_pend_8021x_cnt(ifp));
+ if (!list_empty(&ifp->pend_8021x_skbs)) {
+ struct pend_skb *e;
+
+ mutex_lock(&ifp->pend_8021x_mutex);
+ pr_info("[%s] List of pending 802.1x skbs:\n", __func__);
+ list_for_each_entry(e, &ifp->pend_8021x_skbs, list) {
+ e->timedout = true;
+ pr_info("[%s] skb:%p skb->dev:%p skb->dev->name:%s\n", __func__, e->skb, e->skb->dev, e->skb->dev ? e->skb->dev->name : "---");
+ }
+ mutex_unlock(&ifp->pend_8021x_mutex);
+ }
return !err;
}
@@ -50,6 +50,9 @@
#define NDOL_MAX_ENTRIES 8
+void __brcmu_pkt_buf_free_skb(const char *c0, struct brcmf_if *ifp, struct sk_buff *skb);
+#define brcmu_pkt_buf_free_skb(skb) __brcmu_pkt_buf_free_skb(__func__, ifp, skb)
+
/**
* struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
*
@@ -169,6 +172,15 @@ enum brcmf_netif_stop_reason {
BRCMF_NETIF_STOP_REASON_DISCONNECTED = BIT(2)
};
+struct pend_skb {
+ struct sk_buff *skb;
+ u8 data[14];
+ u64 start_time;
+ u64 commit_time;
+ bool timedout;
+ struct list_head list;
+};
+
/**
* struct brcmf_if - interface control information.
*
@@ -203,6 +215,9 @@ struct brcmf_if {
u8 netif_stop;
spinlock_t netif_stop_lock;
atomic_t pend_8021x_cnt;
+ struct list_head pend_8021x_skbs;
+ struct mutex pend_8021x_mutex;
+ bool pend_8021x_ready;
wait_queue_head_t pend_8021x_wait;
struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
u8 ipv6addr_idx;
@@ -219,7 +234,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
enum brcmf_netif_stop_reason reason, bool state);
-void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+void __brcmf_txfinalize(const char *c0, struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+#define brcmf_txfinalize(ifp, txp, success) __brcmf_txfinalize(__func__, ifp, txp, success)
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
void brcmf_c_set_joinpref_default(struct brcmf_if *ifp);
@@ -249,6 +249,8 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
skb = skb_dequeue(&ring->skblist);
while (skb) {
+ struct brcmf_if *ifp = NULL;
+
brcmu_pkt_buf_free_skb(skb);
skb = skb_dequeue(&ring->skblist);
}
@@ -38,6 +38,8 @@
#include "proto.h"
#include "common.h"
+#include <linux/sched.h>
+
/**
* DOC: Firmware Signalling
*
@@ -590,6 +592,8 @@ static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
for (prec = 0; prec < q->num_prec; prec++) {
skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
while (skb) {
+ struct brcmf_if *ifp = NULL;
+
brcmu_pkt_buf_free_skb(skb);
skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
}
@@ -697,6 +701,8 @@ static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
skb = h->items[i].pkt;
if (fn == NULL || fn(skb, &ifidx)) {
+ struct brcmf_if *ifp = NULL;
+
/* suppress packets freed from psq */
if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
brcmu_pkt_buf_free_skb(skb);
@@ -845,6 +851,8 @@ static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
for (prec = 0; prec < txq->num_prec; prec++) {
skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
while (skb) {
+ struct brcmf_if *ifp = NULL;
+
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
hi = &fws->hanger.items[hslot];
WARN_ON(skb != hi->pkt);
@@ -971,8 +979,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
brcmf_fws_unlock(fws);
err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
brcmf_fws_lock(fws);
- if (err)
+ if (err) {
+ struct brcmf_if *ifp = NULL;
+
brcmu_pkt_buf_free_skb(skb);
+ }
return true;
}
return false;
@@ -2056,6 +2067,22 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
(void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
goto rollback;
}
+ {
+ struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX));
+
+ if (ifp) {
+ struct pend_skb *e;
+
+ mutex_lock(&ifp->pend_8021x_mutex);
+ list_for_each_entry(e, &ifp->pend_8021x_skbs, list) {
+ if (e->skb == skb) {
+ e->commit_time = local_clock();
+ break;
+ }
+ }
+ mutex_unlock(&ifp->pend_8021x_mutex);
+ }
+ }
fws->stats.pkt2bus++;
fws->stats.send_pkts[fifo]++;
@@ -2454,6 +2481,7 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
{
+ struct brcmf_if *ifp = NULL;
u32 hslot;
if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
@@ -34,6 +34,8 @@
#include "bus.h"
#include "tracepoint.h"
+#include <linux/sched.h>
+
#define MSGBUF_IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
@@ -392,6 +394,8 @@ brcmf_msgbuf_release_array(struct device *dev,
count = 0;
do {
if (array[count].allocated.counter) {
+ struct brcmf_if *ifp = NULL;
+
pktid = &array[count];
dma_unmap_single(dev, pktid->physaddr,
pktid->skb->len - pktid->data_offset,
@@ -483,6 +487,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
{
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
struct sk_buff *skb = NULL;
+ struct brcmf_if *ifp = NULL;
int timeout;
int err;
@@ -747,6 +752,22 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)
brcmf_commonring_write_complete(commonring);
count = 0;
}
+ {
+ struct brcmf_if *ifp = brcmf_get_ifp(msgbuf->drvr, tx_msghdr->msg.ifidx);
+
+ if (ifp) {
+ struct pend_skb *e;
+
+ mutex_lock(&ifp->pend_8021x_mutex);
+ list_for_each_entry(e, &ifp->pend_8021x_skbs, list) {
+ if (e->skb == skb) {
+ e->commit_time = local_clock();
+ break;
+ }
+ }
+ mutex_unlock(&ifp->pend_8021x_mutex);
+ }
+ }
}
if (count)
brcmf_commonring_write_complete(commonring);
@@ -498,6 +498,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
{
struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
struct brcmf_usbdev_info *devinfo = req->devinfo;
+ struct brcmf_if *ifp = NULL;
struct sk_buff *skb;
brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
@@ -548,6 +549,8 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
if (ret) {
+ struct brcmf_if *ifp = NULL;
+
brcmf_usb_del_fromq(devinfo, req);
brcmu_pkt_buf_free_skb(req->skb);
req->skb = NULL;
@@ -49,7 +49,7 @@ void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
WARN_ON(skb->next);
dev_kfree_skb_any(skb);
}
-EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
+//EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
/*
* osl multiple-precedence packet queue
@@ -126,7 +126,7 @@ struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec,
/* packet primitives */
struct sk_buff *brcmu_pkt_buf_get_skb(uint len);
-void brcmu_pkt_buf_free_skb(struct sk_buff *skb);
+//void brcmu_pkt_buf_free_skb(struct sk_buff *skb);
/* Empty the queue at particular precedence level */
/* callback function fn(pkt, arg) returns true if pkt belongs to if */