Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 05/12] brcmfmac: no fws locking outside fws module.
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Hante Meuleman, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

From: Hante Meuleman <meuleman@broadcom.com>

FWS uses locking to protect its data while being called from
various entries. On bus_txdata the lock was kept resulting in
unnecessary long locking, but also creating possibility for
deadlock. This update changes the locking to release lock when
bus_txdata is called.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |   1 -
 drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 127 ++++++++++-----------
 2 files changed, 62 insertions(+), 66 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index df94d0e..1273dfd 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -558,7 +558,6 @@ struct brcmf_pub {
 	struct brcmf_fweh_info fweh;
 
 	struct brcmf_fws_info *fws;
-	spinlock_t fws_spinlock;
 
 	struct brcmf_ampdu_rx_reorder
 		*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 15fc807..82f9140 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -422,6 +422,8 @@ struct brcmf_fws_macdesc_table {
 
 struct brcmf_fws_info {
 	struct brcmf_pub *drvr;
+	spinlock_t spinlock;
+	ulong flags;
 	struct brcmf_fws_stats stats;
 	struct brcmf_fws_hanger hanger;
 	enum brcmf_fws_fcmode fcmode;
@@ -484,6 +486,18 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
 }
 #undef BRCMF_FWS_TLV_DEF
 
+static void brcmf_fws_lock(struct brcmf_fws_info *fws)
+		__acquires(&fws->spinlock)
+{
+	spin_lock_irqsave(&fws->spinlock, fws->flags);
+}
+
+static void brcmf_fws_unlock(struct brcmf_fws_info *fws)
+		__releases(&fws->spinlock)
+{
+	spin_unlock_irqrestore(&fws->spinlock, fws->flags);
+}
+
 static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
 {
 	u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
@@ -870,8 +884,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
 		skcb->state = BRCMF_FWS_SKBSTATE_TIM;
 		bus = fws->drvr->bus_if;
 		err = brcmf_fws_hdrpush(fws, skb);
-		if (err == 0)
+		if (err == 0) {
+			brcmf_fws_unlock(fws);
 			err = brcmf_bus_txdata(bus, skb);
+			brcmf_fws_lock(fws);
+		}
 		if (err)
 			brcmu_pkt_buf_free_skb(skb);
 		return true;
@@ -906,26 +923,10 @@ static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
 	return 0;
 }
 
-/* using macro so sparse checking does not complain
- * about locking imbalance.
- */
-#define brcmf_fws_lock(drvr, flags)				\
-do {								\
-	flags = 0;						\
-	spin_lock_irqsave(&((drvr)->fws_spinlock), (flags));	\
-} while (0)
-
-/* using macro so sparse checking does not complain
- * about locking imbalance.
- */
-#define brcmf_fws_unlock(drvr, flags) \
-	spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags))
-
 static
 int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
 {
 	struct brcmf_fws_mac_descriptor *entry, *existing;
-	ulong flags;
 	u8 mac_handle;
 	u8 ifidx;
 	u8 *addr;
@@ -939,10 +940,10 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
 		if (entry->occupied) {
 			brcmf_dbg(TRACE, "deleting %s mac %pM\n",
 				  entry->name, addr);
-			brcmf_fws_lock(fws->drvr, flags);
+			brcmf_fws_lock(fws);
 			brcmf_fws_macdesc_cleanup(fws, entry, -1);
 			brcmf_fws_macdesc_deinit(entry);
-			brcmf_fws_unlock(fws->drvr, flags);
+			brcmf_fws_unlock(fws);
 		} else
 			fws->stats.mac_update_failed++;
 		return 0;
@@ -951,13 +952,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
 	existing = brcmf_fws_macdesc_lookup(fws, addr);
 	if (IS_ERR(existing)) {
 		if (!entry->occupied) {
-			brcmf_fws_lock(fws->drvr, flags);
+			brcmf_fws_lock(fws);
 			entry->mac_handle = mac_handle;
 			brcmf_fws_macdesc_init(entry, addr, ifidx);
 			brcmf_fws_macdesc_set_name(fws, entry);
 			brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
 					BRCMF_FWS_PSQ_LEN);
-			brcmf_fws_unlock(fws->drvr, flags);
+			brcmf_fws_unlock(fws);
 			brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
 		} else {
 			fws->stats.mac_update_failed++;
@@ -965,13 +966,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
 	} else {
 		if (entry != existing) {
 			brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
-			brcmf_fws_lock(fws->drvr, flags);
+			brcmf_fws_lock(fws);
 			memcpy(entry, existing,
 			       offsetof(struct brcmf_fws_mac_descriptor, psq));
 			entry->mac_handle = mac_handle;
 			brcmf_fws_macdesc_deinit(existing);
 			brcmf_fws_macdesc_set_name(fws, entry);
-			brcmf_fws_unlock(fws->drvr, flags);
+			brcmf_fws_unlock(fws);
 			brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
 				  addr);
 		} else {
@@ -987,7 +988,6 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
 					    u8 type, u8 *data)
 {
 	struct brcmf_fws_mac_descriptor *entry;
-	ulong flags;
 	u8 mac_handle;
 	int ret;
 
@@ -997,7 +997,7 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
 		fws->stats.mac_ps_update_failed++;
 		return -ESRCH;
 	}
-	brcmf_fws_lock(fws->drvr, flags);
+	brcmf_fws_lock(fws);
 	/* a state update should wipe old credits */
 	entry->requested_credit = 0;
 	entry->requested_packet = 0;
@@ -1012,7 +1012,7 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
 		brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
 		ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
 	}
-	brcmf_fws_unlock(fws->drvr, flags);
+	brcmf_fws_unlock(fws);
 	return ret;
 }
 
@@ -1020,7 +1020,6 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
 					      u8 type, u8 *data)
 {
 	struct brcmf_fws_mac_descriptor *entry;
-	ulong flags;
 	u8 ifidx;
 	int ret;
 
@@ -1039,7 +1038,7 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
 
 	brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
 		  entry->name);
-	brcmf_fws_lock(fws->drvr, flags);
+	brcmf_fws_lock(fws);
 	switch (type) {
 	case BRCMF_FWS_TYPE_INTERFACE_OPEN:
 		entry->state = BRCMF_FWS_STATE_OPEN;
@@ -1051,10 +1050,10 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
 		break;
 	default:
 		ret = -EINVAL;
-		brcmf_fws_unlock(fws->drvr, flags);
+		brcmf_fws_unlock(fws);
 		goto fail;
 	}
-	brcmf_fws_unlock(fws->drvr, flags);
+	brcmf_fws_unlock(fws);
 	return ret;
 
 fail:
@@ -1066,7 +1065,6 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
 				      u8 *data)
 {
 	struct brcmf_fws_mac_descriptor *entry;
-	ulong flags;
 
 	entry = &fws->desc.nodes[data[1] & 0x1F];
 	if (!entry->occupied) {
@@ -1080,14 +1078,14 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
 	brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
 		  brcmf_fws_get_tlv_name(type), type, entry->name,
 		  data[0], data[2]);
-	brcmf_fws_lock(fws->drvr, flags);
+	brcmf_fws_lock(fws);
 	if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
 		entry->requested_credit = data[0];
 	else
 		entry->requested_packet = data[0];
 
 	entry->ac_bitmap = data[2];
-	brcmf_fws_unlock(fws->drvr, flags);
+	brcmf_fws_unlock(fws);
 	return BRCMF_FWS_RET_OK_SCHEDULE;
 }
 
@@ -1385,7 +1383,6 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
 static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
 					     u8 *data)
 {
-	ulong flags;
 	int i;
 
 	if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
@@ -1394,19 +1391,18 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
 	}
 
 	brcmf_dbg(DATA, "enter: data %pM\n", data);
-	brcmf_fws_lock(fws->drvr, flags);
+	brcmf_fws_lock(fws);
 	for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
 		brcmf_fws_return_credits(fws, i, data[i]);
 
 	brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
 		  fws->fifo_delay_map);
-	brcmf_fws_unlock(fws->drvr, flags);
+	brcmf_fws_unlock(fws);
 	return BRCMF_FWS_RET_OK_SCHEDULE;
 }
 
 static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
 {
-	ulong lflags;
 	__le32 status_le;
 	u32 status;
 	u32 hslot;
@@ -1420,9 +1416,9 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
 	hslot = brcmf_txstatus_get_field(status, HSLOT);
 	genbit = brcmf_txstatus_get_field(status, GENERATION);
 
-	brcmf_fws_lock(fws->drvr, lflags);
+	brcmf_fws_lock(fws);
 	brcmf_fws_txs_process(fws, flags, hslot, genbit);
-	brcmf_fws_unlock(fws->drvr, lflags);
+	brcmf_fws_unlock(fws);
 	return BRCMF_FWS_RET_OK_NOSCHEDULE;
 }
 
@@ -1442,7 +1438,6 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
 {
 	struct brcmf_fws_info *fws = ifp->drvr->fws;
 	int i;
-	ulong flags;
 	u8 *credits = data;
 
 	if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
@@ -1455,7 +1450,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
 	fws->creditmap_received = true;
 
 	brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
-	brcmf_fws_lock(ifp->drvr, flags);
+	brcmf_fws_lock(fws);
 	for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
 		if (*credits)
 			fws->fifo_credit_map |= 1 << i;
@@ -1464,7 +1459,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
 		fws->fifo_credit[i] = *credits++;
 	}
 	brcmf_fws_schedule_deq(fws);
-	brcmf_fws_unlock(ifp->drvr, flags);
+	brcmf_fws_unlock(fws);
 	return 0;
 }
 
@@ -1473,12 +1468,11 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
 						void *data)
 {
 	struct brcmf_fws_info *fws = ifp->drvr->fws;
-	ulong flags;
 
-	brcmf_fws_lock(ifp->drvr, flags);
+	brcmf_fws_lock(fws);
 	if (fws)
 		fws->bcmc_credit_check = true;
-	brcmf_fws_unlock(ifp->drvr, flags);
+	brcmf_fws_unlock(fws);
 	return 0;
 }
 
@@ -1702,17 +1696,22 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
 		return PTR_ERR(entry);
 
 	brcmf_fws_precommit_skb(fws, fifo, skb);
+	entry->transit_count++;
+	if (entry->suppressed)
+		entry->suppr_transit_count++;
+	brcmf_fws_unlock(fws);
 	rc = brcmf_bus_txdata(bus, skb);
+	brcmf_fws_lock(fws);
 	brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
 		  skcb->if_flags, skcb->htod, rc);
 	if (rc < 0) {
+		entry->transit_count--;
+		if (entry->suppressed)
+			entry->suppr_transit_count--;
 		brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
 		goto rollback;
 	}
 
-	entry->transit_count++;
-	if (entry->suppressed)
-		entry->suppr_transit_count++;
 	fws->stats.pkt2bus++;
 	fws->stats.send_pkts[fifo]++;
 	if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
@@ -1749,7 +1748,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 	struct brcmf_fws_info *fws = drvr->fws;
 	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
 	struct ethhdr *eh = (struct ethhdr *)(skb->data);
-	ulong flags;
 	int fifo = BRCMF_FWS_FIFO_BCMC;
 	bool multicast = is_multicast_ether_addr(eh->h_dest);
 	bool pae = eh->h_proto == htons(ETH_P_PAE);
@@ -1770,7 +1768,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 	if (!multicast)
 		fifo = brcmf_fws_prio2fifo[skb->priority];
 
-	brcmf_fws_lock(drvr, flags);
+	brcmf_fws_lock(fws);
 	if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
 		fws->borrow_defer_timestamp = jiffies +
 					      BRCMF_FWS_BORROW_DEFER_PERIOD;
@@ -1790,7 +1788,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 		}
 		brcmu_pkt_buf_free_skb(skb);
 	}
-	brcmf_fws_unlock(drvr, flags);
+	brcmf_fws_unlock(fws);
 	return 0;
 }
 
@@ -1825,17 +1823,16 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
 void brcmf_fws_del_interface(struct brcmf_if *ifp)
 {
 	struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
-	ulong flags;
 
 	if (!entry)
 		return;
 
-	brcmf_fws_lock(ifp->drvr, flags);
+	brcmf_fws_lock(ifp->drvr->fws);
 	ifp->fws_desc = NULL;
 	brcmf_dbg(TRACE, "deleting %s\n", entry->name);
 	brcmf_fws_macdesc_deinit(entry);
 	brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
-	brcmf_fws_unlock(ifp->drvr, flags);
+	brcmf_fws_unlock(ifp->drvr->fws);
 }
 
 static void brcmf_fws_dequeue_worker(struct work_struct *worker)
@@ -1843,7 +1840,6 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 	struct brcmf_fws_info *fws;
 	struct brcmf_pub *drvr;
 	struct sk_buff *skb;
-	ulong flags;
 	int fifo;
 	u32 hslot;
 	u32 ifidx;
@@ -1852,7 +1848,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 	fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
 	drvr = fws->drvr;
 
-	brcmf_fws_lock(drvr, flags);
+	brcmf_fws_lock(fws);
 	for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
 	     fifo--) {
 		if (!brcmf_fws_fc_active(fws)) {
@@ -1865,7 +1861,9 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 								     INDEX);
 				brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
 				/* Use bus module to send data frame */
+				brcmf_fws_unlock(fws);
 				ret = brcmf_bus_txdata(drvr->bus_if, skb);
+				brcmf_fws_lock(fws);
 				if (ret < 0)
 					brcmf_txfinalize(drvr, skb, false);
 				if (fws->bus_flow_blocked)
@@ -1900,7 +1898,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 			}
 		}
 	}
-	brcmf_fws_unlock(drvr, flags);
+	brcmf_fws_unlock(fws);
 }
 
 int brcmf_fws_init(struct brcmf_pub *drvr)
@@ -1909,8 +1907,6 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 	u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
 	int rc;
 
-	spin_lock_init(&drvr->fws_spinlock);
-
 	drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
 	if (!drvr->fws) {
 		rc = -ENOMEM;
@@ -1918,6 +1914,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 	}
 
 	fws = drvr->fws;
+
+	spin_lock_init(&fws->spinlock);
+
 	/* set linkage back */
 	fws->drvr = drvr;
 	fws->fcmode = fcmode;
@@ -1986,7 +1985,6 @@ fail:
 void brcmf_fws_deinit(struct brcmf_pub *drvr)
 {
 	struct brcmf_fws_info *fws = drvr->fws;
-	ulong flags;
 
 	if (!fws)
 		return;
@@ -1995,10 +1993,10 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr)
 		destroy_workqueue(drvr->fws->fws_wq);
 
 	/* cleanup */
-	brcmf_fws_lock(drvr, flags);
+	brcmf_fws_lock(fws);
 	brcmf_fws_cleanup(fws, -1);
 	drvr->fws = NULL;
-	brcmf_fws_unlock(drvr, flags);
+	brcmf_fws_unlock(fws);
 
 	/* free top structure */
 	kfree(fws);
@@ -2014,17 +2012,16 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
 
 void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
 {
-	ulong flags;
 	u32 hslot;
 
 	if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
 		brcmu_pkt_buf_free_skb(skb);
 		return;
 	}
-	brcmf_fws_lock(fws->drvr, flags);
+	brcmf_fws_lock(fws);
 	hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
 	brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0);
-	brcmf_fws_unlock(fws->drvr, flags);
+	brcmf_fws_unlock(fws);
 }
 
 void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 11/12] brcmfmac: use configurable sdio bus header length for tx packet
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Franky Lin, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

From: Franky Lin <frankyl@broadcom.com>

Host tx glomming require an extended hardware sdio bus header to store
information for dongle. Introduce a variable in struct brcmf_sdio to replace
macro SDPCM_HDRLEN

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 30 ++++++++++++----------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 02ab5cd..1aa75d5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -461,6 +461,8 @@ struct brcmf_sdio {
 	struct brcmf_sdio_count sdcnt;
 	bool sr_enabled; /* SaveRestore enabled */
 	bool sleeping; /* SDIO bus sleeping */
+
+	u8 tx_hdrlen;		/* sdio bus header length for tx packet */
 };
 
 /* clkstate */
@@ -1025,7 +1027,6 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
 #define SDPCM_HWHDR_LEN			4
 #define SDPCM_SWHDR_LEN			8
 #define SDPCM_HDRLEN			(SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)
-#define SDPCM_RESERVE			(SDPCM_HDRLEN + BRCMF_SDALIGN)
 /* software header */
 #define SDPCM_SEQ_MASK			0x000000ff
 #define SDPCM_SEQ_WRAP			256
@@ -1838,7 +1839,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 		}
 		skb_push(pkt_next, head_pad);
 		dat_buf = (u8 *)(pkt_next->data);
-		memset(dat_buf, 0, head_pad + SDPCM_HDRLEN);
+		memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
 	}
 
 	/* Check tail padding */
@@ -1874,7 +1875,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 	else
 		hd_info.len = pkt_next->len - tail_pad;
 	hd_info.channel = chan;
-	hd_info.dat_offset = head_pad + SDPCM_HDRLEN;
+	hd_info.dat_offset = head_pad + bus->tx_hdrlen;
 	brcmf_sdio_hdpack(bus, dat_buf, &hd_info);
 
 	if (BRCMF_BYTES_ON() &&
@@ -1882,7 +1883,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 	     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
 		brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n");
 	else if (BRCMF_HDRS_ON())
-		brcmf_dbg_hex_dump(true, pkt_next, head_pad + SDPCM_HDRLEN,
+		brcmf_dbg_hex_dump(true, pkt_next, head_pad + bus->tx_hdrlen,
 				   "Tx Header:\n");
 
 	return 0;
@@ -1989,7 +1990,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 	u32 intstatus = 0;
 	int ret = 0, prec_out;
 	uint cnt = 0;
-	uint datalen;
 	u8 tx_prec_map;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -2005,7 +2005,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 			break;
 		}
 		spin_unlock_bh(&bus->txqlock);
-		datalen = pkt->len - SDPCM_HDRLEN;
 
 		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL);
 
@@ -2392,7 +2391,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	datalen = pkt->len;
 
 	/* Add space for the header */
-	skb_push(pkt, SDPCM_HDRLEN);
+	skb_push(pkt, bus->tx_hdrlen);
 	/* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
 
 	prec = prio2prec((pkt->priority & PRIOMASK));
@@ -2405,7 +2404,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	/* Priority based enq */
 	spin_lock_irqsave(&bus->txqlock, flags);
 	if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
-		skb_pull(pkt, SDPCM_HDRLEN);
+		skb_pull(pkt, bus->tx_hdrlen);
 		brcmf_err("out of bus->txq !!!\n");
 		ret = -ENOSR;
 	} else {
@@ -2566,8 +2565,8 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 	brcmf_dbg(TRACE, "Enter\n");
 
 	/* Back the pointer to make a room for bus header */
-	frame = msg - SDPCM_HDRLEN;
-	len = (msglen += SDPCM_HDRLEN);
+	frame = msg - bus->tx_hdrlen;
+	len = (msglen += bus->tx_hdrlen);
 
 	/* Add alignment padding (optional for ctl frames) */
 	doff = ((unsigned long)frame % BRCMF_SDALIGN);
@@ -2575,10 +2574,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 		frame -= doff;
 		len += doff;
 		msglen += doff;
-		memset(frame, 0, doff + SDPCM_HDRLEN);
+		memset(frame, 0, doff + bus->tx_hdrlen);
 	}
 	/* precondition: doff < BRCMF_SDALIGN */
-	doff += SDPCM_HDRLEN;
+	doff += bus->tx_hdrlen;
 
 	/* Round send length to next SDIO block */
 	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
@@ -3895,8 +3894,11 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 	bus->sdiodev->bus_if->chip = bus->ci->chip;
 	bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
 
-	/* Attach to the brcmf/OS/network interface */
-	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
+	/* default sdio bus header length for tx packet */
+	bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
+
+	/* Attach to the common layer, reserve hdr space */
+	ret = brcmf_attach(bus->tx_hdrlen, bus->sdiodev->dev);
 	if (ret != 0) {
 		brcmf_err("brcmf_attach failed\n");
 		goto fail;
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 08/12] brcmfmac: abstract tx packet processing functions
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Franky Lin, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

From: Franky Lin <frankyl@broadcom.com>

Abstract brcmf_sdio_txpkt_prep and brcmf_sdio_txpkt_postp as a preparation
of chained tx packets for host side tx glomming.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c   |  16 +-
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 237 +++++++++++++++------
 .../net/wireless/brcm80211/brcmfmac/sdio_host.h    |   2 +-
 include/linux/platform_data/brcmfmac-sdio.h        |   6 +
 4 files changed, 183 insertions(+), 78 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index e3f3c48..e13b1a6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -592,6 +592,7 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
 		      uint flags, u8 *buf, uint nbytes)
 {
 	struct sk_buff *mypkt;
+	struct sk_buff_head pktq;
 	int err;
 
 	mypkt = brcmu_pkt_buf_get_skb(nbytes);
@@ -602,7 +603,10 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
 	}
 
 	memcpy(mypkt->data, buf, nbytes);
-	err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
+	__skb_queue_head_init(&pktq);
+	__skb_queue_tail(&pktq, mypkt);
+	err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, &pktq);
+	__skb_dequeue_tail(&pktq);
 
 	brcmu_pkt_buf_free_skb(mypkt);
 	return err;
@@ -611,22 +615,18 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
 
 int
 brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-		      uint flags, struct sk_buff *pkt)
+		      uint flags, struct sk_buff_head *pktq)
 {
 	uint width;
 	int err = 0;
-	struct sk_buff_head pkt_list;
 
 	brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
-		  fn, addr, pkt->len);
+		  fn, addr, pktq->qlen);
 
 	width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
 	brcmf_sdio_addrprep(sdiodev, width, &addr);
 
-	skb_queue_head_init(&pkt_list);
-	skb_queue_tail(&pkt_list, pkt);
-	err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, &pkt_list);
-	skb_dequeue_tail(&pkt_list);
+	err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, pktq);
 
 	return err;
 }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index db31312..aa4caca 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -510,7 +510,6 @@ struct brcmf_sdio {
 
 #ifdef DEBUG
 static int qcount[NUMPRIO];
-static int tx_packets[NUMPRIO];
 #endif				/* DEBUG */
 
 #define DEFAULT_SDIO_DRIVE_STRENGTH	6	/* in milliamps */
@@ -1759,85 +1758,185 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
 	return;
 }
 
+/* flag marking a dummy skb added for DMA alignment requirement */
+#define DUMMY_SKB_FLAG		0x10000
+/* bit mask of data length chopped from the previous packet */
+#define DUMMY_SKB_CHOP_LEN_MASK	0xffff
+/**
+ * brcmf_sdio_txpkt_prep - packet preparation for transmit
+ * @bus: brcmf_sdio structure pointer
+ * @pktq: packet list pointer
+ * @chan: virtual channel to transmit the packet
+ *
+ * Processes to be applied to the packet
+ *	- Align data buffer pointer
+ *	- Align data buffer length
+ *	- Prepare header
+ * Return: negative value if there is error
+ */
+static int
+brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
+		      uint chan)
+{
+	u16 head_pad, tail_pad, tail_chop, pkt_len;
+	u16 head_align, sg_align;
+	u32 sw_header;
+	int ntail;
+	struct sk_buff *pkt_next, *pkt_new;
+	u8 *dat_buf;
+	unsigned blksize = bus->sdiodev->func[SDIO_FUNC_2]->cur_blksize;
+
+	/* SDIO ADMA requires at least 32 bit alignment */
+	head_align = 4;
+	sg_align = 4;
+	if (bus->sdiodev->pdata) {
+		head_align = bus->sdiodev->pdata->sd_head_align > 4 ?
+			     bus->sdiodev->pdata->sd_head_align : 4;
+		sg_align = bus->sdiodev->pdata->sd_sgentry_align > 4 ?
+			   bus->sdiodev->pdata->sd_sgentry_align : 4;
+	}
+	/* sg entry alignment should be a divisor of block size */
+	WARN_ON(blksize % sg_align);
+
+	pkt_next = pktq->next;
+	dat_buf = (u8 *)(pkt_next->data);
+
+	/* Check head padding */
+	head_pad = ((unsigned long)dat_buf % head_align);
+	if (head_pad) {
+		if (skb_headroom(pkt_next) < head_pad) {
+			bus->sdiodev->bus_if->tx_realloc++;
+			head_pad = 0;
+			if (skb_cow(pkt_next, head_pad))
+				return -ENOMEM;
+		}
+		skb_push(pkt_next, head_pad);
+		dat_buf = (u8 *)(pkt_next->data);
+		memset(dat_buf, 0, head_pad + SDPCM_HDRLEN);
+	}
+
+	/* Check tail padding */
+	pkt_new = NULL;
+	tail_chop = pkt_next->len % sg_align;
+	tail_pad = sg_align - tail_chop;
+	tail_pad += blksize - (pkt_next->len + tail_pad) % blksize;
+	if (skb_tailroom(pkt_next) < tail_pad && pkt_next->len > blksize) {
+		pkt_new = brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
+		if (pkt_new == NULL)
+			return -ENOMEM;
+		memcpy(pkt_new->data,
+		       pkt_next->data + pkt_next->len - tail_chop,
+		       tail_chop);
+		*(u32 *)(pkt_new->cb) = DUMMY_SKB_FLAG + tail_chop;
+		skb_trim(pkt_next, pkt_next->len - tail_chop);
+		__skb_queue_after(pktq, pkt_next, pkt_new);
+	} else {
+		ntail = pkt_next->data_len + tail_pad -
+			(pkt_next->end - pkt_next->tail);
+		if (skb_cloned(pkt_next) || ntail > 0)
+			if (pskb_expand_head(pkt_next, 0, ntail, GFP_ATOMIC))
+				return -ENOMEM;
+		if (skb_linearize(pkt_next))
+			return -ENOMEM;
+		dat_buf = (u8 *)(pkt_next->data);
+		__skb_put(pkt_next, tail_pad);
+	}
+
+	/* Now prep the header */
+	/* 4 bytes hardware header (frame tag)
+	 * Byte 0~1: Frame length
+	 * Byte 2~3: Checksum, bit-wise inverse of frame length
+	 */
+	if (pkt_new)
+		pkt_len = pkt_next->len + tail_chop;
+	else
+		pkt_len = pkt_next->len - tail_pad;
+	*(__le16 *)dat_buf = cpu_to_le16(pkt_len);
+	*(((__le16 *)dat_buf) + 1) = cpu_to_le16(~pkt_len);
+	/* 8 bytes software header
+	 * Byte 0: Tx sequence number
+	 * Byte 1: 4 MSB Channel number
+	 * Byte 2: Reserved
+	 * Byte 3: Data offset
+	 * Byte 4~7: Reserved
+	 */
+	sw_header = bus->tx_seq;
+	sw_header |= ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK);
+	sw_header |= ((head_pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) &
+		     SDPCM_DOFFSET_MASK;
+	*(((__le32 *)dat_buf) + 1) = cpu_to_le32(sw_header);
+	*(((__le32 *)dat_buf) + 2) = 0;
+
+	if (BRCMF_BYTES_ON() &&
+	    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
+	     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
+		brcmf_dbg_hex_dump(true, pkt_next, pkt_len, "Tx Frame:\n");
+	else if (BRCMF_HDRS_ON())
+		brcmf_dbg_hex_dump(true, pkt_next, head_pad + SDPCM_HDRLEN,
+				   "Tx Header:\n");
+
+	return 0;
+}
+
+/**
+ * brcmf_sdio_txpkt_postp - packet post processing for transmit
+ * @bus: brcmf_sdio structure pointer
+ * @pktq: packet list pointer
+ *
+ * Processes to be applied to the packet
+ *	- Remove head padding
+ *	- Remove tail padding
+ */
+static void
+brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
+{
+	u8 *hdr;
+	u32 dat_offset;
+	u32 dummy_flags, chop_len;
+	struct sk_buff *pkt_next, *tmp, *pkt_prev;
+
+	skb_queue_walk_safe(pktq, pkt_next, tmp) {
+		dummy_flags = *(u32 *)(pkt_next->cb);
+		if (dummy_flags & DUMMY_SKB_FLAG) {
+			chop_len = dummy_flags & DUMMY_SKB_CHOP_LEN_MASK;
+			if (chop_len) {
+				pkt_prev = pkt_next->prev;
+				memcpy(pkt_prev->data + pkt_prev->len,
+				       pkt_next->data, chop_len);
+				skb_put(pkt_prev, chop_len);
+			}
+			__skb_unlink(pkt_next, pktq);
+			brcmu_pkt_buf_free_skb(pkt_next);
+		} else {
+			hdr = pkt_next->data + SDPCM_FRAMETAG_LEN;
+			dat_offset = le32_to_cpu(*(__le32 *)hdr);
+			dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>
+				     SDPCM_DOFFSET_SHIFT;
+			skb_pull(pkt_next, dat_offset);
+		}
+	}
+}
+
 /* Writes a HW/SW header into the packet and sends it. */
 /* Assumes: (a) header space already there, (b) caller holds lock */
 static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 			      uint chan)
 {
 	int ret;
-	u8 *frame;
-	u16 len, pad = 0;
-	u32 swheader;
 	int i;
+	struct sk_buff_head localq;
 
 	brcmf_dbg(TRACE, "Enter\n");
 
-	frame = (u8 *) (pkt->data);
-
-	/* Add alignment padding, allocate new packet if needed */
-	pad = ((unsigned long)frame % BRCMF_SDALIGN);
-	if (pad) {
-		if (skb_headroom(pkt) < pad) {
-			brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
-				  skb_headroom(pkt), pad);
-			bus->sdiodev->bus_if->tx_realloc++;
-			ret = skb_cow(pkt, BRCMF_SDALIGN);
-			if (ret)
-				goto done;
-			pad = ((unsigned long)frame % BRCMF_SDALIGN);
-		}
-		skb_push(pkt, pad);
-		frame = (u8 *) (pkt->data);
-		memset(frame, 0, pad + SDPCM_HDRLEN);
-	}
-	/* precondition: pad < BRCMF_SDALIGN */
-
-	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
-	len = (u16) (pkt->len);
-	*(__le16 *) frame = cpu_to_le16(len);
-	*(((__le16 *) frame) + 1) = cpu_to_le16(~len);
-
-	/* Software tag: channel, sequence number, data offset */
-	swheader =
-	    ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
-	    (((pad +
-	       SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
-
-	*(((__le32 *) frame) + 1) = cpu_to_le32(swheader);
-	*(((__le32 *) frame) + 2) = 0;
-
-#ifdef DEBUG
-	tx_packets[pkt->priority]++;
-#endif
-
-	brcmf_dbg_hex_dump(BRCMF_BYTES_ON() &&
-			   ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
-			    (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)),
-			   frame, len, "Tx Frame:\n");
-	brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() &&
-			     ((BRCMF_CTL_ON() &&
-			       chan == SDPCM_CONTROL_CHANNEL) ||
-			      (BRCMF_DATA_ON() &&
-			       chan != SDPCM_CONTROL_CHANNEL))) &&
-			   BRCMF_HDRS_ON(),
-			   frame, min_t(u16, len, 16), "TxHdr:\n");
-
-	/* Raise len to next SDIO block to eliminate tail command */
-	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
-		u16 pad = bus->blocksize - (len % bus->blocksize);
-		if ((pad <= bus->roundup) && (pad < bus->blocksize))
-				len += pad;
-	} else if (len % BRCMF_SDALIGN) {
-		len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
-	}
-
-	/* Some controllers have trouble with odd bytes -- round to even */
-	if (len & (ALIGNMENT - 1))
-			len = roundup(len, ALIGNMENT);
+	__skb_queue_head_init(&localq);
+	__skb_queue_tail(&localq, pkt);
+	ret = brcmf_sdio_txpkt_prep(bus, &localq, chan);
+	if (ret)
+		goto done;
 
 	sdio_claim_host(bus->sdiodev->func[1]);
 	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
-				    SDIO_FUNC_2, F2SYNC, pkt);
+				    SDIO_FUNC_2, F2SYNC, &localq);
 	bus->sdcnt.f2txdata++;
 
 	if (ret < 0) {
@@ -1868,8 +1967,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
 
 done:
-	/* restore pkt buffer pointer before calling tx complete routine */
-	skb_pull(pkt, SDPCM_HDRLEN + pad);
+	brcmf_sdio_txpkt_postp(bus, &localq);
+	__skb_dequeue_tail(&localq);
 	brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0);
 	return ret;
 }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
index 09786a5..2b5407f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
@@ -208,7 +208,7 @@ extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
  */
 extern int
 brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-		      uint flags, struct sk_buff *pkt);
+		      uint flags, struct sk_buff_head *pktq);
 extern int
 brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
 		      uint flags, u8 *buf, uint nbytes);
diff --git a/include/linux/platform_data/brcmfmac-sdio.h b/include/linux/platform_data/brcmfmac-sdio.h
index b717499..e75dcbf 100644
--- a/include/linux/platform_data/brcmfmac-sdio.h
+++ b/include/linux/platform_data/brcmfmac-sdio.h
@@ -94,6 +94,10 @@ void __init brcmfmac_init_pdata(void)
  * Set this to true if the SDIO host controller has higher align requirement
  * than 32 bytes for each scatterlist item.
  *
+ * sd_head_align: alignment requirement for start of data buffer
+ *
+ * sd_sgentry_align: length alignment requirement for each sg entry
+ *
  * power_on: This function is called by the brcmfmac when the module gets
  * loaded. This can be particularly useful for low power devices. The platform
  * spcific routine may for example decide to power up the complete device.
@@ -121,6 +125,8 @@ struct brcmfmac_sdio_platform_data {
 	unsigned int oob_irq_nr;
 	unsigned long oob_irq_flags;
 	bool broken_sg_support;
+	unsigned short sd_head_align;
+	unsigned short sd_sgentry_align;
 	void (*power_on)(void);
 	void (*power_off)(void);
 	void (*reset)(void);
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 06/12] brcmfmac: ignore IF event if firmware indicates it
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

Not every IF event from the firmware needs to result in a
related interface, netdev or wdev, on the host. This is
indicated in the event message. Handle that flag and effectively
ignore the firmware event.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h  | 2 ++
 drivers/net/wireless/brcm80211/brcmfmac/fweh.c | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 1273dfd..2eb9e64 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -194,6 +194,8 @@
 #define BRCMF_E_IF_DEL				2
 #define BRCMF_E_IF_CHANGE			3
 
+#define BRCMF_E_IF_FLAG_NOIF			1
+
 #define BRCMF_E_IF_ROLE_STA			0
 #define BRCMF_E_IF_ROLE_AP			1
 #define BRCMF_E_IF_ROLE_WDS			2
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index 83ee53a..fad77dd 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -185,6 +185,10 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
 		  ifevent->action, ifevent->ifidx, ifevent->bssidx,
 		  ifevent->flags, ifevent->role);
 
+	if (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) {
+		brcmf_dbg(EVENT, "event can be ignored\n");
+		return;
+	}
 	if (ifevent->ifidx >= BRCMF_MAX_IFS) {
 		brcmf_err("invalid interface index: %u\n",
 			  ifevent->ifidx);
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 09/12] brcmfmac: remove align from brcmf_bus structure
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Franky Lin, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

From: Franky Lin <frankyl@broadcom.com>

remove align from brcmf_bus since it is only used by sdio bus layer internally

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 .../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c |  1 -
 drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h  |  2 --
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 25 +++++++++++++++-------
 3 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index 289e386..64f4a2b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -350,7 +350,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
 
 	sdiodev->bus_if = bus_if;
 	bus_if->bus_priv.sdio = sdiodev;
-	bus_if->align = BRCMF_SDALIGN;
 	dev_set_drvdata(&func->dev, bus_if);
 	dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
 	sdiodev->dev = &sdiodev->func[1]->dev;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index 9249b6d..f7c1985 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -69,7 +69,6 @@ struct brcmf_bus_ops {
  * @maxctl: maximum size for rxctl request message.
  * @tx_realloc: number of tx packets realloced for headroom.
  * @dstats: dongle-based statistical data.
- * @align: alignment requirement for the bus.
  * @dcmd_list: bus/device specific dongle initialization commands.
  * @chip: device identifier of the dongle chip.
  * @chiprev: revision of the dongle chip.
@@ -84,7 +83,6 @@ struct brcmf_bus {
 	enum brcmf_bus_state state;
 	uint maxctl;
 	unsigned long tx_realloc;
-	u8 align;
 	u32 chip;
 	u32 chiprev;
 	struct list_head dcmd_list;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index aa4caca..2563875 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -1166,7 +1166,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 {
 	u16 dlen, totlen;
 	u8 *dptr, num = 0;
-
+	u32 align = 0;
 	u16 sublen;
 	struct sk_buff *pfirst, *pnext;
 
@@ -1181,6 +1181,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 	brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
 		  bus->glomd, skb_peek(&bus->glom));
 
+	if (bus->sdiodev->pdata)
+		align = bus->sdiodev->pdata->sd_sgentry_align;
+	if (align < 4)
+		align = 4;
+
 	/* If there's a descriptor, generate the packet chain */
 	if (bus->glomd) {
 		pfirst = pnext = NULL;
@@ -1204,9 +1209,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 				pnext = NULL;
 				break;
 			}
-			if (sublen % BRCMF_SDALIGN) {
+			if (sublen % align) {
 				brcmf_err("sublen %d not multiple of %d\n",
-					  sublen, BRCMF_SDALIGN);
+					  sublen, align);
 			}
 			totlen += sublen;
 
@@ -1219,7 +1224,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			}
 
 			/* Allocate/chain packet for next subframe */
-			pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
+			pnext = brcmu_pkt_buf_get_skb(sublen + align);
 			if (pnext == NULL) {
 				brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
 					  num, sublen);
@@ -1228,7 +1233,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			skb_queue_tail(&bus->glom, pnext);
 
 			/* Adhere to start alignment requirements */
-			pkt_align(pnext, sublen, BRCMF_SDALIGN);
+			pkt_align(pnext, sublen, align);
 		}
 
 		/* If all allocations succeeded, save packet chain
@@ -3832,7 +3837,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 	struct brcmf_sdio *bus;
 	struct brcmf_bus_dcmd *dlst;
 	u32 dngl_txglom;
-	u32 dngl_txglomalign;
+	u32 txglomalign = 0;
 	u8 idx;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -3926,9 +3931,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 			dlst->param_len = sizeof(u32);
 		} else {
 			/* otherwise, set txglomalign */
-			dngl_txglomalign = bus->sdiodev->bus_if->align;
+			if (sdiodev->pdata)
+				txglomalign = sdiodev->pdata->sd_sgentry_align;
+			/* SDIO ADMA requires at least 32 bit alignment */
+			if (txglomalign < 4)
+				txglomalign = 4;
 			dlst->name = "bus:txglomalign";
-			dlst->param = (char *)&dngl_txglomalign;
+			dlst->param = (char *)&txglomalign;
 			dlst->param_len = sizeof(u32);
 		}
 		list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list);
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 10/12] brcmfmac: streamline sdio bus header code
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Franky Lin, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

From: Franky Lin <frankyl@broadcom.com>

Streamlining sdio bus specific header related code as preparation for host
tx glomming

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 243 ++++++++++-----------
 1 file changed, 120 insertions(+), 123 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 2563875..02ab5cd 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -201,13 +201,6 @@ struct rte_console {
 #define SFC_CRC4WOOS	(1 << 2)	/* CRC error for write out of sync */
 #define SFC_ABORTALL	(1 << 3)	/* Abort all in-progress frames */
 
-/* HW frame tag */
-#define SDPCM_FRAMETAG_LEN	4	/* 2 bytes len, 2 bytes check val */
-
-/* Total length of frame header for dongle protocol */
-#define SDPCM_HDRLEN	(SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
-#define SDPCM_RESERVE	(SDPCM_HDRLEN + BRCMF_SDALIGN)
-
 /*
  * Software allocation of To SB Mailbox resources
  */
@@ -250,38 +243,6 @@ struct rte_console {
 /* Current protocol version */
 #define SDPCM_PROT_VERSION	4
 
-/* SW frame header */
-#define SDPCM_PACKET_SEQUENCE(p)	(((u8 *)p)[0] & 0xff)
-
-#define SDPCM_CHANNEL_MASK		0x00000f00
-#define SDPCM_CHANNEL_SHIFT		8
-#define SDPCM_PACKET_CHANNEL(p)		(((u8 *)p)[1] & 0x0f)
-
-#define SDPCM_NEXTLEN_OFFSET		2
-
-/* Data Offset from SOF (HW Tag, SW Tag, Pad) */
-#define SDPCM_DOFFSET_OFFSET		3	/* Data Offset */
-#define SDPCM_DOFFSET_VALUE(p)		(((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
-#define SDPCM_DOFFSET_MASK		0xff000000
-#define SDPCM_DOFFSET_SHIFT		24
-#define SDPCM_FCMASK_OFFSET		4	/* Flow control */
-#define SDPCM_FCMASK_VALUE(p)		(((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff)
-#define SDPCM_WINDOW_OFFSET		5	/* Credit based fc */
-#define SDPCM_WINDOW_VALUE(p)		(((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
-
-#define SDPCM_SWHEADER_LEN	8	/* SW header is 64 bits */
-
-/* logical channel numbers */
-#define SDPCM_CONTROL_CHANNEL	0	/* Control channel Id */
-#define SDPCM_EVENT_CHANNEL	1	/* Asyc Event Indication Channel Id */
-#define SDPCM_DATA_CHANNEL	2	/* Data Xmit/Recv Channel Id */
-#define SDPCM_GLOM_CHANNEL	3	/* For coalesced packets */
-#define SDPCM_TEST_CHANNEL	15	/* Reserved for test/debug packets */
-
-#define SDPCM_SEQUENCE_WRAP	256	/* wrap-around val for 8bit frame seq */
-
-#define SDPCM_GLOMDESC(p)	(((u8 *)p)[1] & 0x80)
-
 /*
  * Shared structure between dongle and the host.
  * The structure contains pointers to trap or assert information.
@@ -396,8 +357,8 @@ struct sdpcm_shared_le {
 	__le32 brpt_addr;
 };
 
-/* SDIO read frame info */
-struct brcmf_sdio_read {
+/* dongle SDIO bus specific header info */
+struct brcmf_sdio_hdrinfo {
 	u8 seq_num;
 	u8 channel;
 	u16 len;
@@ -431,7 +392,7 @@ struct brcmf_sdio {
 	u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
 	u8 *rxhdr;		/* Header of current rx frame (in hdrbuf) */
 	u8 rx_seq;		/* Receive sequence number (expected) */
-	struct brcmf_sdio_read cur_read;
+	struct brcmf_sdio_hdrinfo cur_read;
 				/* info of current read frame */
 	bool rxskip;		/* Skip receive (awaiting NAK ACK) */
 	bool rxpending;		/* Data frame pending in dongle */
@@ -1042,18 +1003,64 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
 	}
 }
 
-static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
-			       struct brcmf_sdio_read *rd,
-			       enum brcmf_sdio_frmtype type)
+/**
+ * brcmfmac sdio bus specific header
+ * This is the lowest layer header wrapped on the packets transmitted between
+ * host and WiFi dongle which contains information needed for SDIO core and
+ * firmware
+ *
+ * It consists of 2 parts: hw header and software header
+ * hardware header (frame tag) - 4 bytes
+ * Byte 0~1: Frame length
+ * Byte 2~3: Checksum, bit-wise inverse of frame length
+ * software header - 8 bytes
+ * Byte 0: Rx/Tx sequence number
+ * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
+ * Byte 2: Length of next data frame, reserved for Tx
+ * Byte 3: Data offset
+ * Byte 4: Flow control bits, reserved for Tx
+ * Byte 5: Maximum Sequence number allowed by firmware for Tx, N/A for Tx packet
+ * Byte 6~7: Reserved
+ */
+#define SDPCM_HWHDR_LEN			4
+#define SDPCM_SWHDR_LEN			8
+#define SDPCM_HDRLEN			(SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)
+#define SDPCM_RESERVE			(SDPCM_HDRLEN + BRCMF_SDALIGN)
+/* software header */
+#define SDPCM_SEQ_MASK			0x000000ff
+#define SDPCM_SEQ_WRAP			256
+#define SDPCM_CHANNEL_MASK		0x00000f00
+#define SDPCM_CHANNEL_SHIFT		8
+#define SDPCM_CONTROL_CHANNEL		0	/* Control */
+#define SDPCM_EVENT_CHANNEL		1	/* Asyc Event Indication */
+#define SDPCM_DATA_CHANNEL		2	/* Data Xmit/Recv */
+#define SDPCM_GLOM_CHANNEL		3	/* Coalesced packets */
+#define SDPCM_TEST_CHANNEL		15	/* Test/debug packets */
+#define SDPCM_GLOMDESC(p)		(((u8 *)p)[1] & 0x80)
+#define SDPCM_NEXTLEN_MASK		0x00ff0000
+#define SDPCM_NEXTLEN_SHIFT		16
+#define SDPCM_DOFFSET_MASK		0xff000000
+#define SDPCM_DOFFSET_SHIFT		24
+#define SDPCM_FCMASK_MASK		0x000000ff
+#define SDPCM_WINDOW_MASK		0x0000ff00
+#define SDPCM_WINDOW_SHIFT		8
+
+static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
+{
+	u32 hdrvalue;
+	hdrvalue = *(u32 *)swheader;
+	return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
+}
+
+static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
+			      struct brcmf_sdio_hdrinfo *rd,
+			      enum brcmf_sdio_frmtype type)
 {
 	u16 len, checksum;
 	u8 rx_seq, fc, tx_seq_max;
+	u32 swheader;
 
-	/*
-	 * 4 bytes hardware header (frame tag)
-	 * Byte 0~1: Frame length
-	 * Byte 2~3: Checksum, bit-wise inverse of frame length
-	 */
+	/* hw header */
 	len = get_unaligned_le16(header);
 	checksum = get_unaligned_le16(header + sizeof(u16));
 	/* All zero means no more to read */
@@ -1082,24 +1089,16 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
 	}
 	rd->len = len;
 
-	/*
-	 * 8 bytes hardware header
-	 * Byte 0: Rx sequence number
-	 * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
-	 * Byte 2: Length of next data frame
-	 * Byte 3: Data offset
-	 * Byte 4: Flow control bits
-	 * Byte 5: Maximum Sequence number allow for Tx
-	 * Byte 6~7: Reserved
-	 */
-	if (type == BRCMF_SDIO_FT_SUPER &&
-	    SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) {
+	/* software header */
+	header += SDPCM_HWHDR_LEN;
+	swheader = le32_to_cpu(*(__le32 *)header);
+	if (type == BRCMF_SDIO_FT_SUPER && SDPCM_GLOMDESC(header)) {
 		brcmf_err("Glom descriptor found in superframe head\n");
 		rd->len = 0;
 		return -EINVAL;
 	}
-	rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);
-	rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]);
+	rx_seq = (u8)(swheader & SDPCM_SEQ_MASK);
+	rd->channel = (swheader & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT;
 	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
 	    type != BRCMF_SDIO_FT_SUPER) {
 		brcmf_err("HW header length too long\n");
@@ -1119,7 +1118,7 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
 		rd->len = 0;
 		return -EINVAL;
 	}
-	rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);
+	rd->dat_offset = brcmf_sdio_getdatoffset(header);
 	if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
 		brcmf_err("seq %d: bad data offset\n", rx_seq);
 		bus->sdcnt.rx_badhdr++;
@@ -1136,14 +1135,15 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
 	/* no need to check the reset for subframe */
 	if (type == BRCMF_SDIO_FT_SUB)
 		return 0;
-	rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
+	rd->len_nxtfrm = (swheader & SDPCM_NEXTLEN_MASK) >> SDPCM_NEXTLEN_SHIFT;
 	if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
 		/* only warm for NON glom packet */
 		if (rd->channel != SDPCM_GLOM_CHANNEL)
 			brcmf_err("seq %d: next length error\n", rx_seq);
 		rd->len_nxtfrm = 0;
 	}
-	fc = SDPCM_FCMASK_VALUE(&header[SDPCM_FRAMETAG_LEN]);
+	swheader = le32_to_cpu(*(__le32 *)(header + 4));
+	fc = swheader & SDPCM_FCMASK_MASK;
 	if (bus->flowcontrol != fc) {
 		if (~bus->flowcontrol & fc)
 			bus->sdcnt.fc_xoff++;
@@ -1152,7 +1152,7 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
 		bus->sdcnt.fc_rcvd++;
 		bus->flowcontrol = fc;
 	}
-	tx_seq_max = SDPCM_WINDOW_VALUE(&header[SDPCM_FRAMETAG_LEN]);
+	tx_seq_max = (swheader & SDPCM_WINDOW_MASK) >> SDPCM_WINDOW_SHIFT;
 	if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) {
 		brcmf_err("seq %d: max tx seq number error\n", rx_seq);
 		tx_seq_max = bus->tx_seq + 2;
@@ -1162,6 +1162,28 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
 	return 0;
 }
 
+static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length)
+{
+	*(__le16 *)header = cpu_to_le16(frm_length);
+	*(((__le16 *)header) + 1) = cpu_to_le16(~frm_length);
+}
+
+static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,
+			      struct brcmf_sdio_hdrinfo *hd_info)
+{
+	u32 sw_header;
+
+	brcmf_sdio_update_hwhdr(header, hd_info->len);
+
+	sw_header = bus->tx_seq;
+	sw_header |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
+		     SDPCM_CHANNEL_MASK;
+	sw_header |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
+		     SDPCM_DOFFSET_MASK;
+	*(((__le32 *)header) + 1) = cpu_to_le32(sw_header);
+	*(((__le32 *)header) + 2) = 0;
+}
+
 static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 {
 	u16 dlen, totlen;
@@ -1173,7 +1195,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 	int errcode;
 	u8 doff, sfdoff;
 
-	struct brcmf_sdio_read rd_new;
+	struct brcmf_sdio_hdrinfo rd_new;
 
 	/* If packets, issue read(s) and send up packet chain */
 	/* Return sequence numbers consumed? */
@@ -1309,8 +1331,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 		rd_new.seq_num = rxseq;
 		rd_new.len = dlen;
 		sdio_claim_host(bus->sdiodev->func[1]);
-		errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
-					      BRCMF_SDIO_FT_SUPER);
+		errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
+					     BRCMF_SDIO_FT_SUPER);
 		sdio_release_host(bus->sdiodev->func[1]);
 		bus->cur_read.len = rd_new.len_nxtfrm << 4;
 
@@ -1328,8 +1350,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 			rd_new.len = pnext->len;
 			rd_new.seq_num = rxseq++;
 			sdio_claim_host(bus->sdiodev->func[1]);
-			errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new,
-						      BRCMF_SDIO_FT_SUB);
+			errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
+						     BRCMF_SDIO_FT_SUB);
 			sdio_release_host(bus->sdiodev->func[1]);
 			brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
 					   pnext->data, 32, "subframe:\n");
@@ -1361,7 +1383,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 		skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
 			dptr = (u8 *) (pfirst->data);
 			sublen = get_unaligned_le16(dptr);
-			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+			doff = brcmf_sdio_getdatoffset(&dptr[SDPCM_HWHDR_LEN]);
 
 			brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
 					   dptr, pfirst->len,
@@ -1539,7 +1561,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 	uint rxleft = 0;	/* Remaining number of frames allowed */
 	int ret;		/* Return code from calls */
 	uint rxcount = 0;	/* Total frames read */
-	struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
+	struct brcmf_sdio_hdrinfo *rd = &bus->cur_read, rd_new;
 	u8 head_read = 0;
 
 	brcmf_dbg(TRACE, "Enter\n");
@@ -1587,8 +1609,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 					   bus->rxhdr, SDPCM_HDRLEN,
 					   "RxHdr:\n");
 
-			if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
-						BRCMF_SDIO_FT_NORMAL)) {
+			if (brcmf_sdio_hdparse(bus, bus->rxhdr, rd,
+					       BRCMF_SDIO_FT_NORMAL)) {
 				sdio_release_host(bus->sdiodev->func[1]);
 				if (!bus->rxpending)
 					break;
@@ -1652,8 +1674,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 			memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
 			rd_new.seq_num = rd->seq_num;
 			sdio_claim_host(bus->sdiodev->func[1]);
-			if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
-						BRCMF_SDIO_FT_NORMAL)) {
+			if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
+					       BRCMF_SDIO_FT_NORMAL)) {
 				rd->len = 0;
 				brcmu_pkt_buf_free_skb(pkt);
 			}
@@ -1697,7 +1719,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 
 		/* Save superframe descriptor and allocate packet frame */
 		if (rd->channel == SDPCM_GLOM_CHANNEL) {
-			if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
+			if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_HWHDR_LEN])) {
 				brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
 					  rd->len);
 				brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
@@ -1783,13 +1805,12 @@ static int
 brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 		      uint chan)
 {
-	u16 head_pad, tail_pad, tail_chop, pkt_len;
-	u16 head_align, sg_align;
-	u32 sw_header;
+	u16 head_pad, tail_pad, tail_chop, head_align, sg_align;
 	int ntail;
 	struct sk_buff *pkt_next, *pkt_new;
 	u8 *dat_buf;
 	unsigned blksize = bus->sdiodev->func[SDIO_FUNC_2]->cur_blksize;
+	struct brcmf_sdio_hdrinfo hd_info = {0};
 
 	/* SDIO ADMA requires at least 32 bit alignment */
 	head_align = 4;
@@ -1848,34 +1869,18 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 	}
 
 	/* Now prep the header */
-	/* 4 bytes hardware header (frame tag)
-	 * Byte 0~1: Frame length
-	 * Byte 2~3: Checksum, bit-wise inverse of frame length
-	 */
 	if (pkt_new)
-		pkt_len = pkt_next->len + tail_chop;
+		hd_info.len = pkt_next->len + tail_chop;
 	else
-		pkt_len = pkt_next->len - tail_pad;
-	*(__le16 *)dat_buf = cpu_to_le16(pkt_len);
-	*(((__le16 *)dat_buf) + 1) = cpu_to_le16(~pkt_len);
-	/* 8 bytes software header
-	 * Byte 0: Tx sequence number
-	 * Byte 1: 4 MSB Channel number
-	 * Byte 2: Reserved
-	 * Byte 3: Data offset
-	 * Byte 4~7: Reserved
-	 */
-	sw_header = bus->tx_seq;
-	sw_header |= ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK);
-	sw_header |= ((head_pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) &
-		     SDPCM_DOFFSET_MASK;
-	*(((__le32 *)dat_buf) + 1) = cpu_to_le32(sw_header);
-	*(((__le32 *)dat_buf) + 2) = 0;
+		hd_info.len = pkt_next->len - tail_pad;
+	hd_info.channel = chan;
+	hd_info.dat_offset = head_pad + SDPCM_HDRLEN;
+	brcmf_sdio_hdpack(bus, dat_buf, &hd_info);
 
 	if (BRCMF_BYTES_ON() &&
 	    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
 	     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
-		brcmf_dbg_hex_dump(true, pkt_next, pkt_len, "Tx Frame:\n");
+		brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n");
 	else if (BRCMF_HDRS_ON())
 		brcmf_dbg_hex_dump(true, pkt_next, head_pad + SDPCM_HDRLEN,
 				   "Tx Header:\n");
@@ -1913,7 +1918,7 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
 			__skb_unlink(pkt_next, pktq);
 			brcmu_pkt_buf_free_skb(pkt_next);
 		} else {
-			hdr = pkt_next->data + SDPCM_FRAMETAG_LEN;
+			hdr = pkt_next->data + SDPCM_HWHDR_LEN;
 			dat_offset = le32_to_cpu(*(__le32 *)hdr);
 			dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>
 				     SDPCM_DOFFSET_SHIFT;
@@ -1969,7 +1974,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 	}
 	sdio_release_host(bus->sdiodev->func[1]);
 	if (ret == 0)
-		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 
 done:
 	brcmf_sdio_txpkt_postp(bus, &localq);
@@ -2325,7 +2330,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 			}
 
 		} else {
-			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 		}
 		sdio_release_host(bus->sdiodev->func[1]);
 		bus->ctrl_frame_stat = false;
@@ -2540,7 +2545,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 		return ret;
 	}
 
-	bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+	bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 
 	return ret;
 }
@@ -2550,13 +2555,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 {
 	u8 *frame;
 	u16 len;
-	u32 swheader;
 	uint retries = 0;
 	u8 doff = 0;
 	int ret = -1;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
+	struct brcmf_sdio_hdrinfo hd_info = {0};
 
 	brcmf_dbg(TRACE, "Enter\n");
 
@@ -2595,18 +2600,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 	brcmf_sdbrcm_bus_sleep(bus, false, false);
 	sdio_release_host(bus->sdiodev->func[1]);
 
-	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
-	*(__le16 *) frame = cpu_to_le16((u16) msglen);
-	*(((__le16 *) frame) + 1) = cpu_to_le16(~msglen);
-
-	/* Software tag: channel, sequence number, data offset */
-	swheader =
-	    ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
-	     SDPCM_CHANNEL_MASK)
-	    | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
-			     SDPCM_DOFFSET_MASK);
-	put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
-	put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+	hd_info.len = (u16)msglen;
+	hd_info.channel = SDPCM_CONTROL_CHANNEL;
+	hd_info.dat_offset = doff;
+	brcmf_sdio_hdpack(bus, frame, &hd_info);
 
 	if (!data_ok(bus)) {
 		brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
@@ -3856,7 +3853,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 	bus->txbound = BRCMF_TXBOUND;
 	bus->rxbound = BRCMF_RXBOUND;
 	bus->txminmax = BRCMF_TXMINMAX;
-	bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
+	bus->tx_seq = SDPCM_SEQ_WRAP - 1;
 
 	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
 	bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 02/12] brcmfmac: .txdata() bus callback should not call brcmf_txcomplete()
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

With firmware-signalling the packet handed to the bus specific driver
layer should not be discarded with brcmf_txcomplete() in the failure
path. Instead only an error is returned and the caller decides what
to do with the packet.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 1 -
 drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 6 +++++-
 drivers/net/wireless/brcm80211/brcmfmac/usb.c      | 1 -
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 5cbce1d..db31312 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -2297,7 +2297,6 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	spin_lock_irqsave(&bus->txqlock, flags);
 	if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
 		skb_pull(pkt, SDPCM_HDRLEN);
-		brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
 		brcmf_err("out of bus->txq !!!\n");
 		ret = -ENOSR;
 	} else {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 29b1f24..601b0d0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1745,6 +1745,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 	int fifo = BRCMF_FWS_FIFO_BCMC;
 	bool multicast = is_multicast_ether_addr(eh->h_dest);
 	bool pae = eh->h_proto == htons(ETH_P_PAE);
+	int ret;
 
 	/* determine the priority */
 	if (!skb->priority)
@@ -1759,7 +1760,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 		brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
 
 		/* Use bus module to send data frame */
-		return brcmf_bus_txdata(drvr->bus_if, skb);
+		ret = brcmf_bus_txdata(drvr->bus_if, skb);
+		if (ret < 0)
+			brcmf_txfinalize(drvr, skb, false);
+		return ret;
 	}
 
 	/* set control buffer information */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 322cadc..39e01a7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -614,7 +614,6 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
 	return 0;
 
 fail:
-	brcmf_txcomplete(dev, skb, false);
 	return ret;
 }
 
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 01/12] brcmfmac: use irq safe spinlock in brcmf_sdbrcm_txdata()
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

Firmware-signalling needs transmit to firmware to be atomic and
uses a spinlock with irq disabled. Therefor, brcmf_sdbrcm_txdata()
should not use spin_unlock_bh() as it would enable the interrupts.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h  | 6 +++++-
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 5 +++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index 080395f..9249b6d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -36,7 +36,11 @@ struct brcmf_bus_dcmd {
  *
  * @init: prepare for communication with dongle.
  * @stop: clear pending frames, disable data flow.
- * @txdata: send a data frame to the dongle (callee disposes skb).
+ * @txdata: send a data frame to the dongle. When the data
+ *	has been transferred, the common driver must be
+ *	notified using brcmf_txcomplete(). The common
+ *	driver calls this function with interrupts
+ *	disabled.
  * @txctl: transmit a control request message to dongle.
  * @rxctl: receive a control response message from dongle.
  * @gettxq: obtain a reference of bus transmit queue (optional).
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 2641119..5cbce1d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -2276,6 +2276,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 	struct brcmf_sdio *bus = sdiodev->bus;
+	ulong flags;
 
 	brcmf_dbg(TRACE, "Enter\n");
 
@@ -2293,7 +2294,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 	bus->sdcnt.fcqueued++;
 
 	/* Priority based enq */
-	spin_lock_bh(&bus->txqlock);
+	spin_lock_irqsave(&bus->txqlock, flags);
 	if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
 		skb_pull(pkt, SDPCM_HDRLEN);
 		brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
@@ -2307,7 +2308,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 		bus->txoff = true;
 		brcmf_txflowblock(bus->sdiodev->dev, true);
 	}
-	spin_unlock_bh(&bus->txqlock);
+	spin_unlock_irqrestore(&bus->txqlock, flags);
 
 #ifdef DEBUG
 	if (pktq_plen(&bus->txq, prec) > qcount[prec])
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 00/12] brcm80211: new functionality and some cleanup fixes
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Arend van Spriel

This series adds new functionality to the brcm80211 drivers listed below:

AMPDU host-reordering:
	The brcmfmac driver buffers individual A-MPDU packets
	reducing memory requirement in the wireless device.

TDLS:
	The 802.11 standards AP bypass is added to brcmfmac.

BCM4313 iPA:
	This adds support to brcmsmac for a new variant of the
	BCM4313. This was already submitted but reverted due
	to regressions for other devices.

Other changes are brcmfmac cleanup work for firmware-signalling
feature and rework in SDIO-specific driver code.

This series is intended for v3.12 and applies to the master branch
of the wireless-next repository.

Arend van Spriel (5):
  brcmfmac: use irq safe spinlock in brcmf_sdbrcm_txdata()
  brcmfmac: .txdata() bus callback should not call brcmf_txcomplete()
  brcmfmac: add AMPDU reordering functionality
  brcmfmac: ignore IF event if firmware indicates it
  brcmfmac: add support for manual TDLS operations

Franky Lin (4):
  brcmfmac: abstract tx packet processing functions
  brcmfmac: remove align from brcmf_bus structure
  brcmfmac: streamline sdio bus header code
  brcmfmac: use configurable sdio bus header length for tx packet

Hante Meuleman (2):
  brcmfmac: always use worker thread for tx data.
  brcmfmac: no fws locking outside fws module.

Piotr Haber (1):
  brcmsmac: support 4313iPA

 drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c   |  16 +-
 .../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c |   1 -
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |  31 +-
 drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h  |   8 +-
 .../net/wireless/brcm80211/brcmfmac/dhd_linux.c    | 279 ++++++++++--
 drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 481 +++++++++++++--------
 drivers/net/wireless/brcm80211/brcmfmac/fweh.c     |   4 +
 .../net/wireless/brcm80211/brcmfmac/fwil_types.h   |  21 +
 drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 228 +++++-----
 .../net/wireless/brcm80211/brcmfmac/sdio_host.h    |   2 +-
 drivers/net/wireless/brcm80211/brcmfmac/usb.c      |   1 -
 .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c  |  57 ++-
 .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c  | 399 ++++++++++-------
 .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c   | 289 ++++++++-----
 .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h   |   1 +
 include/linux/platform_data/brcmfmac-sdio.h        |   6 +
 16 files changed, 1228 insertions(+), 596 deletions(-)

-- 
1.8.1.3



^ permalink raw reply

* [PATCH 04/12] brcmfmac: always use worker thread for tx data.
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Hante Meuleman, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

From: Hante Meuleman <meuleman@broadcom.com>

When fw signalling is disabled tx is sent immediately. Using
queues and worker thread allows usb to do synchronous autopm. This
patch makes fws use queues and worker thread even if signalling is
not supported by FW or not enabled.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |  1 -
 .../net/wireless/brcm80211/brcmfmac/dhd_linux.c    | 13 +--
 drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 96 ++++++++++++----------
 3 files changed, 54 insertions(+), 56 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 3943fb8..df94d0e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -557,7 +557,6 @@ struct brcmf_pub {
 
 	struct brcmf_fweh_info fweh;
 
-	bool fw_signals;
 	struct brcmf_fws_info *fws;
 	spinlock_t fws_spinlock;
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 9bc2785..e067aec 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -278,18 +278,10 @@ void brcmf_txflowblock(struct device *dev, bool state)
 {
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
-	int i;
 
 	brcmf_dbg(TRACE, "Enter\n");
 
-	if (brcmf_fws_fc_active(drvr->fws)) {
-		brcmf_fws_bus_blocked(drvr, state);
-	} else {
-		for (i = 0; i < BRCMF_MAX_IFS; i++)
-			brcmf_txflowblock_if(drvr->iflist[i],
-					     BRCMF_NETIF_STOP_REASON_BLOCK_BUS,
-					     state);
-	}
+	brcmf_fws_bus_blocked(drvr, state);
 }
 
 static void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
@@ -534,7 +526,7 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 		skb_unlink(skb, skb_list);
 
 		/* process and remove protocol-specific header */
-		ret = brcmf_proto_hdrpull(drvr, drvr->fw_signals, &ifidx, skb);
+		ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
 		ifp = drvr->iflist[ifidx];
 
 		if (ret || !ifp || !ifp->ndev) {
@@ -1109,7 +1101,6 @@ int brcmf_bus_start(struct device *dev)
 	if (ret < 0)
 		goto fail;
 
-	drvr->fw_signals = true;
 	ret = brcmf_fws_init(drvr);
 	if (ret < 0)
 		goto fail;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 438c7b9..15fc807 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -425,6 +425,7 @@ struct brcmf_fws_info {
 	struct brcmf_fws_stats stats;
 	struct brcmf_fws_hanger hanger;
 	enum brcmf_fws_fcmode fcmode;
+	bool fw_signals;
 	bool bcmc_credit_check;
 	struct brcmf_fws_macdesc_table desc;
 	struct workqueue_struct *fws_wq;
@@ -1160,7 +1161,8 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
 static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
 {
 	/* only schedule dequeue when there are credits for delayed traffic */
-	if (fws->fifo_credit_map & fws->fifo_delay_map)
+	if ((fws->fifo_credit_map & fws->fifo_delay_map) ||
+	    (!brcmf_fws_fc_active(fws) && fws->fifo_delay_map))
 		queue_work(fws->fws_wq, &fws->fws_dequeue_work);
 }
 
@@ -1498,8 +1500,10 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
 
 	WARN_ON(signal_len > skb->len);
 
+	if (!signal_len)
+		return 0;
 	/* if flow control disabled, skip to packet data and leave */
-	if (!signal_len || !drvr->fw_signals) {
+	if (!fws->fw_signals) {
 		skb_pull(skb, signal_len);
 		return 0;
 	}
@@ -1749,7 +1753,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 	int fifo = BRCMF_FWS_FIFO_BCMC;
 	bool multicast = is_multicast_ether_addr(eh->h_dest);
 	bool pae = eh->h_proto == htons(ETH_P_PAE);
-	int ret;
 
 	brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
 	/* determine the priority */
@@ -1760,17 +1763,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 	if (pae)
 		atomic_inc(&ifp->pend_8021x_cnt);
 
-	if (!brcmf_fws_fc_active(fws)) {
-		/* If the protocol uses a data header, apply it */
-		brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
-
-		/* Use bus module to send data frame */
-		ret = brcmf_bus_txdata(drvr->bus_if, skb);
-		if (ret < 0)
-			brcmf_txfinalize(drvr, skb, false);
-		return ret;
-	}
-
 	/* set control buffer information */
 	skcb->if_flags = 0;
 	skcb->state = BRCMF_FWS_SKBSTATE_NEW;
@@ -1818,7 +1810,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
 	struct brcmf_fws_info *fws = ifp->drvr->fws;
 	struct brcmf_fws_mac_descriptor *entry;
 
-	if (!ifp->ndev || !ifp->drvr->fw_signals)
+	if (!ifp->ndev)
 		return;
 
 	entry = &fws->desc.iface[ifp->ifidx];
@@ -1849,15 +1841,38 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp)
 static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 {
 	struct brcmf_fws_info *fws;
+	struct brcmf_pub *drvr;
 	struct sk_buff *skb;
 	ulong flags;
 	int fifo;
+	u32 hslot;
+	u32 ifidx;
+	int ret;
 
 	fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
+	drvr = fws->drvr;
 
-	brcmf_fws_lock(fws->drvr, flags);
+	brcmf_fws_lock(drvr, flags);
 	for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
 	     fifo--) {
+		if (!brcmf_fws_fc_active(fws)) {
+			while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) {
+				hslot = brcmf_skb_htod_tag_get_field(skb,
+								     HSLOT);
+				brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
+							&skb, true);
+				ifidx = brcmf_skb_if_flags_get_field(skb,
+								     INDEX);
+				brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
+				/* Use bus module to send data frame */
+				ret = brcmf_bus_txdata(drvr->bus_if, skb);
+				if (ret < 0)
+					brcmf_txfinalize(drvr, skb, false);
+				if (fws->bus_flow_blocked)
+					break;
+			}
+			continue;
+		}
 		while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) &&
 		       (fifo == BRCMF_FWS_FIFO_BCMC))) {
 			skb = brcmf_fws_deq(fws, fifo);
@@ -1885,17 +1900,15 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 			}
 		}
 	}
-	brcmf_fws_unlock(fws->drvr, flags);
+	brcmf_fws_unlock(drvr, flags);
 }
 
 int brcmf_fws_init(struct brcmf_pub *drvr)
 {
+	struct brcmf_fws_info *fws;
 	u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
 	int rc;
 
-	if (!drvr->fw_signals)
-		return 0;
-
 	spin_lock_init(&drvr->fws_spinlock);
 
 	drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
@@ -1904,20 +1917,21 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 		goto fail;
 	}
 
+	fws = drvr->fws;
 	/* set linkage back */
-	drvr->fws->drvr = drvr;
-	drvr->fws->fcmode = fcmode;
+	fws->drvr = drvr;
+	fws->fcmode = fcmode;
 
-	drvr->fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
-	if (drvr->fws->fws_wq == NULL) {
+	fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
+	if (fws->fws_wq == NULL) {
 		brcmf_err("workqueue creation failed\n");
 		rc = -EBADF;
 		goto fail;
 	}
-	INIT_WORK(&drvr->fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
+	INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
 
 	/* enable firmware signalling if fcmode active */
-	if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE)
+	if (fws->fcmode != BRCMF_FWS_FCMODE_NONE)
 		tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
 		       BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
 		       BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
@@ -1937,34 +1951,33 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 		goto fail;
 	}
 
-	/* setting the iovar may fail if feature is unsupported
+	/* Setting the iovar may fail if feature is unsupported
 	 * so leave the rc as is so driver initialization can
-	 * continue.
+	 * continue. Set mode back to none indicating not enabled.
 	 */
+	fws->fw_signals = true;
 	if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) {
 		brcmf_err("failed to set bdcv2 tlv signaling\n");
-		goto fail_event;
+		fws->fcmode = BRCMF_FWS_FCMODE_NONE;
+		fws->fw_signals = false;
 	}
 
 	if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
 		brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
 
-	brcmf_fws_hanger_init(&drvr->fws->hanger);
-	brcmf_fws_macdesc_init(&drvr->fws->desc.other, NULL, 0);
-	brcmf_fws_macdesc_set_name(drvr->fws, &drvr->fws->desc.other);
-	brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
+	brcmf_fws_hanger_init(&fws->hanger);
+	brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
+	brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
+	brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
 			BRCMF_FWS_PSQ_LEN);
 
 	/* create debugfs file for statistics */
-	brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
+	brcmf_debugfs_create_fws_stats(drvr, &fws->stats);
 
 	brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
-		  drvr->fw_signals ? "enabled" : "disabled", tlv);
+		  fws->fw_signals ? "enabled" : "disabled", tlv);
 	return 0;
 
-fail_event:
-	brcmf_fweh_unregister(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT);
-	brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
 fail:
 	brcmf_fws_deinit(drvr);
 	return rc;
@@ -1978,11 +1991,6 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr)
 	if (!fws)
 		return;
 
-	/* disable firmware signalling entirely
-	 * to avoid using the workqueue.
-	 */
-	drvr->fw_signals = false;
-
 	if (drvr->fws->fws_wq)
 		destroy_workqueue(drvr->fws->fws_wq);
 
@@ -1998,7 +2006,7 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr)
 
 bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
 {
-	if (!fws)
+	if (!fws->creditmap_received)
 		return false;
 
 	return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
-- 
1.8.1.3



^ permalink raw reply related

* [PATCH 03/12] brcmfmac: add AMPDU reordering functionality
From: Arend van Spriel @ 2013-08-10 10:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1376130450-29746-1-git-send-email-arend@broadcom.com>

This feature moves the responsibility of collecting all MPDUs in an
AMPDU session in the correct order from the firmware to the host
driver. This reduces buffer requirement on the firmware side.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/dhd.h      |  27 +++
 .../net/wireless/brcm80211/brcmfmac/dhd_linux.c    | 270 +++++++++++++++++++--
 drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c |  13 +-
 3 files changed, 283 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 86cbfe2..3943fb8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -209,6 +209,8 @@
 #define BRCMF_DCMD_MEDLEN	1536
 #define BRCMF_DCMD_MAXLEN	8192
 
+#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS		256
+
 /* Pattern matching filter. Specifies an offset within received packets to
  * start matching, the pattern to match, the size of the pattern, and a bitmask
  * that indicates which bits within the pattern should be matched.
@@ -505,6 +507,25 @@ struct brcmf_dcmd {
 	uint needed;		/* bytes needed (optional) */
 };
 
+/**
+ * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
+ *
+ * @pktslots: dynamic allocated array for ordering AMPDU packets.
+ * @flow_id: AMPDU flow identifier.
+ * @cur_idx: last AMPDU index from firmware.
+ * @exp_idx: expected next AMPDU index.
+ * @max_idx: maximum amount of packets per AMPDU.
+ * @pend_pkts: number of packets currently in @pktslots.
+ */
+struct brcmf_ampdu_rx_reorder {
+	struct sk_buff **pktslots;
+	u8 flow_id;
+	u8 cur_idx;
+	u8 exp_idx;
+	u8 max_idx;
+	u8 pend_pkts;
+};
+
 /* Forward decls for struct brcmf_pub (see below) */
 struct brcmf_proto;	/* device communication protocol info */
 struct brcmf_cfg80211_dev; /* cfg80211 device info */
@@ -539,6 +560,9 @@ struct brcmf_pub {
 	bool fw_signals;
 	struct brcmf_fws_info *fws;
 	spinlock_t fws_spinlock;
+
+	struct brcmf_ampdu_rx_reorder
+		*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
 #ifdef DEBUG
 	struct dentry *dbgfs_dir;
 #endif
@@ -604,6 +628,9 @@ struct brcmf_if {
 	wait_queue_head_t pend_8021x_wait;
 };
 
+struct brcmf_skb_reorder_data {
+	u8 *reorder;
+};
 
 extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 8009901..9bc2785 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -38,6 +38,19 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 #define MAX_WAIT_FOR_8021X_TX		50	/* msecs */
 
+/* AMPDU rx reordering definitions */
+#define BRCMF_RXREORDER_FLOWID_OFFSET		0
+#define BRCMF_RXREORDER_MAXIDX_OFFSET		2
+#define BRCMF_RXREORDER_FLAGS_OFFSET		4
+#define BRCMF_RXREORDER_CURIDX_OFFSET		6
+#define BRCMF_RXREORDER_EXPIDX_OFFSET		8
+
+#define BRCMF_RXREORDER_DEL_FLOW		0x01
+#define BRCMF_RXREORDER_FLUSH_ALL		0x02
+#define BRCMF_RXREORDER_CURIDX_VALID		0x04
+#define BRCMF_RXREORDER_EXPIDX_VALID		0x08
+#define BRCMF_RXREORDER_NEW_HOLE		0x10
+
 /* Error bits */
 int brcmf_msg_level;
 module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
@@ -279,16 +292,243 @@ void brcmf_txflowblock(struct device *dev, bool state)
 	}
 }
 
+static void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+	skb->dev = ifp->ndev;
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	if (skb->pkt_type == PACKET_MULTICAST)
+		ifp->stats.multicast++;
+
+	/* Process special event packets */
+	brcmf_fweh_process_skb(ifp->drvr, skb);
+
+	if (!(ifp->ndev->flags & IFF_UP)) {
+		brcmu_pkt_buf_free_skb(skb);
+		return;
+	}
+
+	ifp->stats.rx_bytes += skb->len;
+	ifp->stats.rx_packets++;
+
+	brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
+	if (in_interrupt())
+		netif_rx(skb);
+	else
+		/* If the receive is not processed inside an ISR,
+		 * the softirqd must be woken explicitly to service
+		 * the NET_RX_SOFTIRQ.  This is handled by netif_rx_ni().
+		 */
+		netif_rx_ni(skb);
+}
+
+static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
+					 u8 start, u8 end,
+					 struct sk_buff_head *skb_list)
+{
+	/* initialize return list */
+	__skb_queue_head_init(skb_list);
+
+	if (rfi->pend_pkts == 0) {
+		brcmf_dbg(INFO, "no packets in reorder queue\n");
+		return;
+	}
+
+	do {
+		if (rfi->pktslots[start]) {
+			__skb_queue_tail(skb_list, rfi->pktslots[start]);
+			rfi->pktslots[start] = NULL;
+		}
+		start++;
+		if (start > rfi->max_idx)
+			start = 0;
+	} while (start != end);
+	rfi->pend_pkts -= skb_queue_len(skb_list);
+}
+
+static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
+					 struct sk_buff *pkt)
+{
+	u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
+	struct brcmf_ampdu_rx_reorder *rfi;
+	struct sk_buff_head reorder_list;
+	struct sk_buff *pnext;
+	u8 flags;
+	u32 buf_size;
+
+	flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
+	flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
+
+	/* validate flags and flow id */
+	if (flags == 0xFF) {
+		brcmf_err("invalid flags...so ignore this packet\n");
+		brcmf_netif_rx(ifp, pkt);
+		return;
+	}
+
+	rfi = ifp->drvr->reorder_flows[flow_id];
+	if (flags & BRCMF_RXREORDER_DEL_FLOW) {
+		brcmf_dbg(INFO, "flow-%d: delete\n",
+			  flow_id);
+
+		if (rfi == NULL) {
+			brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
+				  flow_id);
+			brcmf_netif_rx(ifp, pkt);
+			return;
+		}
+
+		brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
+					     &reorder_list);
+		/* add the last packet */
+		__skb_queue_tail(&reorder_list, pkt);
+		kfree(rfi);
+		ifp->drvr->reorder_flows[flow_id] = NULL;
+		goto netif_rx;
+	}
+	/* from here on we need a flow reorder instance */
+	if (rfi == NULL) {
+		buf_size = sizeof(*rfi);
+		max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
+
+		buf_size += (max_idx + 1) * sizeof(pkt);
+
+		/* allocate space for flow reorder info */
+		brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
+			  flow_id, max_idx);
+		rfi = kzalloc(buf_size, GFP_ATOMIC);
+		if (rfi == NULL) {
+			brcmf_err("failed to alloc buffer\n");
+			brcmf_netif_rx(ifp, pkt);
+			return;
+		}
+
+		ifp->drvr->reorder_flows[flow_id] = rfi;
+		rfi->pktslots = (struct sk_buff **)(rfi+1);
+		rfi->max_idx = max_idx;
+	}
+	if (flags & BRCMF_RXREORDER_NEW_HOLE)  {
+		if (rfi->pend_pkts) {
+			brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
+						     rfi->exp_idx,
+						     &reorder_list);
+			WARN_ON(rfi->pend_pkts);
+		} else {
+			__skb_queue_head_init(&reorder_list);
+		}
+		rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
+		rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+		rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
+		rfi->pktslots[rfi->cur_idx] = pkt;
+		rfi->pend_pkts++;
+		brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
+			  flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
+	} else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
+		cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
+		exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+
+		if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
+			/* still in the current hole */
+			/* enqueue the current on the buffer chain */
+			if (rfi->pktslots[cur_idx] != NULL) {
+				brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
+				brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
+				rfi->pktslots[cur_idx] = NULL;
+			}
+			rfi->pktslots[cur_idx] = pkt;
+			rfi->pend_pkts++;
+			rfi->cur_idx = cur_idx;
+			brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
+				  flow_id, cur_idx, exp_idx, rfi->pend_pkts);
+
+			/* can return now as there is no reorder
+			 * list to process.
+			 */
+			return;
+		}
+		if (rfi->exp_idx == cur_idx) {
+			if (rfi->pktslots[cur_idx] != NULL) {
+				brcmf_dbg(INFO, "error buffer pending..free it\n");
+				brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
+				rfi->pktslots[cur_idx] = NULL;
+			}
+			rfi->pktslots[cur_idx] = pkt;
+			rfi->pend_pkts++;
+
+			/* got the expected one. flush from current to expected
+			 * and update expected
+			 */
+			brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
+				  flow_id, cur_idx, exp_idx, rfi->pend_pkts);
+
+			rfi->cur_idx = cur_idx;
+			rfi->exp_idx = exp_idx;
+
+			brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
+						     &reorder_list);
+			brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
+				  flow_id, skb_queue_len(&reorder_list),
+				  rfi->pend_pkts);
+		} else {
+			u8 end_idx;
+
+			brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
+				  flow_id, flags, rfi->cur_idx, rfi->exp_idx,
+				  cur_idx, exp_idx);
+			if (flags & BRCMF_RXREORDER_FLUSH_ALL)
+				end_idx = rfi->exp_idx;
+			else
+				end_idx = exp_idx;
+
+			/* flush pkts first */
+			brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
+						     &reorder_list);
+
+			if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
+				__skb_queue_tail(&reorder_list, pkt);
+			} else {
+				rfi->pktslots[cur_idx] = pkt;
+				rfi->pend_pkts++;
+			}
+			rfi->exp_idx = exp_idx;
+			rfi->cur_idx = cur_idx;
+		}
+	} else {
+		/* explicity window move updating the expected index */
+		exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+
+		brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
+			  flow_id, flags, rfi->exp_idx, exp_idx);
+		if (flags & BRCMF_RXREORDER_FLUSH_ALL)
+			end_idx =  rfi->exp_idx;
+		else
+			end_idx =  exp_idx;
+
+		brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
+					     &reorder_list);
+		__skb_queue_tail(&reorder_list, pkt);
+		/* set the new expected idx */
+		rfi->exp_idx = exp_idx;
+	}
+netif_rx:
+	skb_queue_walk_safe(&reorder_list, pkt, pnext) {
+		__skb_unlink(pkt, &reorder_list);
+		brcmf_netif_rx(ifp, pkt);
+	}
+}
+
 void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 {
 	struct sk_buff *skb, *pnext;
 	struct brcmf_if *ifp;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
+	struct brcmf_skb_reorder_data *rd;
 	u8 ifidx;
 	int ret;
 
-	brcmf_dbg(DATA, "Enter\n");
+	brcmf_dbg(DATA, "Enter: %s: count=%u\n", dev_name(dev),
+		  skb_queue_len(skb_list));
 
 	skb_queue_walk_safe(skb_list, skb, pnext) {
 		skb_unlink(skb, skb_list);
@@ -304,31 +544,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 			continue;
 		}
 
-		skb->dev = ifp->ndev;
-		skb->protocol = eth_type_trans(skb, skb->dev);
-
-		if (skb->pkt_type == PACKET_MULTICAST)
-			ifp->stats.multicast++;
-
-		/* Process special event packets */
-		brcmf_fweh_process_skb(drvr, skb);
-
-		if (!(ifp->ndev->flags & IFF_UP)) {
-			brcmu_pkt_buf_free_skb(skb);
-			continue;
-		}
-
-		ifp->stats.rx_bytes += skb->len;
-		ifp->stats.rx_packets++;
-
-		if (in_interrupt())
-			netif_rx(skb);
+		rd = (struct brcmf_skb_reorder_data *)skb->cb;
+		if (rd->reorder)
+			brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
 		else
-			/* If the receive is not processed inside an ISR,
-			 * the softirqd must be woken explicitly to service the
-			 * NET_RX_SOFTIRQ. This is handled by netif_rx_ni().
-			 */
-			netif_rx_ni(skb);
+			brcmf_netif_rx(ifp, skb);
 	}
 }
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 601b0d0..438c7b9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1483,6 +1483,7 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
 int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
 		      struct sk_buff *skb)
 {
+	struct brcmf_skb_reorder_data *rd;
 	struct brcmf_fws_info *fws = drvr->fws;
 	u8 *signal_data;
 	s16 data_len;
@@ -1536,9 +1537,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
 
 		err = BRCMF_FWS_RET_OK_NOSCHEDULE;
 		switch (type) {
-		case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
 		case BRCMF_FWS_TYPE_COMP_TXSTATUS:
 			break;
+		case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
+			rd = (struct brcmf_skb_reorder_data *)skb->cb;
+			rd->reorder = data;
+			break;
 		case BRCMF_FWS_TYPE_MACDESC_ADD:
 		case BRCMF_FWS_TYPE_MACDESC_DEL:
 			brcmf_fws_macdesc_indicate(fws, type, data);
@@ -1747,6 +1751,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 	bool pae = eh->h_proto == htons(ETH_P_PAE);
 	int ret;
 
+	brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
 	/* determine the priority */
 	if (!skb->priority)
 		skb->priority = cfg80211_classify8021d(skb);
@@ -1915,7 +1920,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 	if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE)
 		tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
 		       BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
-		       BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE;
+		       BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
+		       BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE;
 
 	rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
 				 brcmf_fws_notify_credit_map);
@@ -1940,6 +1946,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 		goto fail_event;
 	}
 
+	if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
+		brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
+
 	brcmf_fws_hanger_init(&drvr->fws->hanger);
 	brcmf_fws_macdesc_init(&drvr->fws->desc.other, NULL, 0);
 	brcmf_fws_macdesc_set_name(drvr->fws, &drvr->fws->desc.other);
-- 
1.8.1.3



^ permalink raw reply related

* Re: [PATCH v3] brcmsmac: Fix WARNING caused by lack of calls to dma_mapping_error()
From: Arend van Spriel @ 2013-08-10  7:54 UTC (permalink / raw)
  To: Larry Finger
  Cc: John W. Linville, linux-wireless, Brett Rudley,
	Franky (Zhenhui) Lin, Hante Meuleman, brcm80211-dev-list, Stable
In-Reply-To: <520567B9.1000605@lwfinger.net>

On 08/10/13 00:05, Larry Finger wrote:
> On 08/09/2013 12:36 PM, John W. Linville wrote:
>> From: "John W. Linville" <linville@tuxdriver.com>
>>
>> The driver fails to check the results of DMA mapping in twp places,
>> which results in the following warning:
>>
>> [ 28.078515] ------------[ cut here ]------------
>> [ 28.078529] WARNING: at lib/dma-debug.c:937 check_unmap+0x47e/0x930()
>> [ 28.078533] bcma-pci-bridge 0000:0e:00.0: DMA-API: device driver
>> failed to check map error[device address=0x00000000b5d60d6c]
>> [size=1876 bytes] [mapped as
>> single]
>> [ 28.078536] Modules linked in: bnep bluetooth vboxpci(O)
>> vboxnetadp(O) vboxnetflt(O) vboxdrv(O) ipv6 b43 brcmsmac rtl8192cu
>> rtl8192c_common rtlwifi mac802
>> 11 brcmutil cfg80211 snd_hda_codec_conexant rng_core snd_hda_intel
>> kvm_amd snd_hda_codec ssb kvm mmc_core snd_pcm snd_seq snd_timer
>> snd_seq_device snd k8temp
>> cordic joydev serio_raw hwmon sr_mod sg pcmcia pcmcia_core soundcore
>> cdrom i2c_nforce2 i2c_core forcedeth bcma snd_page_alloc autofs4 ext4
>> jbd2 mbcache crc1
>> 6 scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh
>> ata_generic pata_amd
>> [ 28.078602] CPU: 1 PID: 2570 Comm: NetworkManager Tainted: G O
>> 3.10.0-rc7-wl+ #42
>> [ 28.078605] Hardware name: Hewlett-Packard HP Pavilion dv2700
>> Notebook PC/30D6, BIOS F.27 11/27/2008
>> [ 28.078607] 0000000000000009 ffff8800bbb03ad8 ffffffff8144f898
>> ffff8800bbb03b18
>> [ 28.078612] ffffffff8103e1eb 0000000000000002 ffff8800b719f480
>> ffff8800b7b9c010
>> [ 28.078617] ffffffff824204c0 ffffffff81754d57 0000000000000754
>> ffff8800bbb03b78
>> [ 28.078622] Call Trace:
>> [ 28.078624] <IRQ> [<ffffffff8144f898>] dump_stack+0x19/0x1b
>> [ 28.078634] [<ffffffff8103e1eb>] warn_slowpath_common+0x6b/0xa0
>> [ 28.078638] [<ffffffff8103e2c1>] warn_slowpath_fmt+0x41/0x50
>> [ 28.078650] [<ffffffff8122d7ae>] check_unmap+0x47e/0x930
>> [ 28.078655] [<ffffffff8122de4c>] debug_dma_unmap_page+0x5c/0x70
>> [ 28.078679] [<ffffffffa04a808c>] dma64_getnextrxp+0x10c/0x190 [brcmsmac]
>> [ 28.078691] [<ffffffffa04a9042>] dma_rx+0x62/0x240 [brcmsmac]
>> [ 28.078707] [<ffffffffa0479101>] brcms_c_dpc+0x211/0x9d0 [brcmsmac]
>> [ 28.078717] [<ffffffffa046d927>] ? brcms_dpc+0x27/0xf0 [brcmsmac]
>> [ 28.078731] [<ffffffffa046d947>] brcms_dpc+0x47/0xf0 [brcmsmac]
>> [ 28.078736] [<ffffffff81047dcc>] tasklet_action+0x6c/0xf0
>> --snip--
>> [ 28.078974] [<ffffffff813891bd>] SyS_sendmsg+0xd/0x20
>> [ 28.078979] [<ffffffff81455c24>] tracesys+0xdd/0xe2
>> [ 28.078982] ---[ end trace 6164d1a08148e9c8 ]---
>> [ 28.078984] Mapped at:
>> [ 28.078985] [<ffffffff8122c8fd>] debug_dma_map_page+0x9d/0x150
>> [ 28.078989] [<ffffffffa04a9322>] dma_rxfill+0x102/0x3d0 [brcmsmac]
>> [ 28.079001] [<ffffffffa047a13d>] brcms_c_init+0x87d/0x1100 [brcmsmac]
>> [ 28.079010] [<ffffffffa046d851>] brcms_init+0x21/0x30 [brcmsmac]
>> [ 28.079018] [<ffffffffa04786e0>] brcms_c_up+0x150/0x430 [brcmsmac]
>>
>> As the patch adds a new failure mechanism to dma_rxfill(). When I
>> changed the
>> comment at the start of the routine to add that information, I also
>> polished
>> the wording.
>>
>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>> Cc: Stable <stable@vger.kernel.org>
>> Cc: Brett Rudley <brudley@broadcom.com>
>> Cc: Arend van Spriel <arend@broadcom.com>
>> Cc: Franky (Zhenhui) Lin <frankyl@broadcom.com>
>> Cc: Hante Meuleman <meuleman@broadcom.com>
>> Cc: brcm80211-dev-list@broadcom.com
>> Signed-off-by: John W. Linville <linville@tuxdriver.com>
>> ---
>> Did this one get lost?
>>
>> V2 - fixed two patch errors.
>> V3 - address comments from Arend (linville)
>>
>
> For some reason, I never got the mail containing Arend's comments, and I
> forgot about it. If John's V3 fixes take care of them, then it should be
> pushed.

Weird as I resend the comments. Do you have me on a blacklist ;-)

Regards,
Arend

> Larry
>
>
>



^ permalink raw reply

* Re: [PATCH v3] brcmsmac: Fix WARNING caused by lack of calls to dma_mapping_error()
From: Arend van Spriel @ 2013-08-10  7:51 UTC (permalink / raw)
  To: John W. Linville
  Cc: linux-wireless, Larry Finger, Brett Rudley, Franky (Zhenhui) Lin,
	Hante Meuleman, brcm80211-dev-list, Stable
In-Reply-To: <1376069781-22958-1-git-send-email-linville@tuxdriver.com>

On 08/09/13 19:36, John W. Linville wrote:
> From: "John W. Linville"<linville@tuxdriver.com>
>
> The driver fails to check the results of DMA mapping in twp places,
> which results in the following warning:
>
> [   28.078515] ------------[ cut here ]------------
> [   28.078529] WARNING: at lib/dma-debug.c:937 check_unmap+0x47e/0x930()
> [   28.078533] bcma-pci-bridge 0000:0e:00.0: DMA-API: device driver failed to check map error[device address=0x00000000b5d60d6c] [size=1876 bytes] [mapped as
>   single]
> [   28.078536] Modules linked in: bnep bluetooth vboxpci(O) vboxnetadp(O) vboxnetflt(O) vboxdrv(O) ipv6 b43 brcmsmac rtl8192cu rtl8192c_common rtlwifi mac802
> 11 brcmutil cfg80211 snd_hda_codec_conexant rng_core snd_hda_intel kvm_amd snd_hda_codec ssb kvm mmc_core snd_pcm snd_seq snd_timer snd_seq_device snd k8temp
>   cordic joydev serio_raw hwmon sr_mod sg pcmcia pcmcia_core soundcore cdrom i2c_nforce2 i2c_core forcedeth bcma snd_page_alloc autofs4 ext4 jbd2 mbcache crc1
> 6 scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh ata_generic pata_amd
> [   28.078602] CPU: 1 PID: 2570 Comm: NetworkManager Tainted: G           O 3.10.0-rc7-wl+ #42
> [   28.078605] Hardware name: Hewlett-Packard HP Pavilion dv2700 Notebook PC/30D6, BIOS F.27 11/27/2008
> [   28.078607]  0000000000000009 ffff8800bbb03ad8 ffffffff8144f898 ffff8800bbb03b18
> [   28.078612]  ffffffff8103e1eb 0000000000000002 ffff8800b719f480 ffff8800b7b9c010
> [   28.078617]  ffffffff824204c0 ffffffff81754d57 0000000000000754 ffff8800bbb03b78
> [   28.078622] Call Trace:
> [   28.078624]<IRQ>   [<ffffffff8144f898>] dump_stack+0x19/0x1b
> [   28.078634]  [<ffffffff8103e1eb>] warn_slowpath_common+0x6b/0xa0
> [   28.078638]  [<ffffffff8103e2c1>] warn_slowpath_fmt+0x41/0x50
> [   28.078650]  [<ffffffff8122d7ae>] check_unmap+0x47e/0x930
> [   28.078655]  [<ffffffff8122de4c>] debug_dma_unmap_page+0x5c/0x70
> [   28.078679]  [<ffffffffa04a808c>] dma64_getnextrxp+0x10c/0x190 [brcmsmac]
> [   28.078691]  [<ffffffffa04a9042>] dma_rx+0x62/0x240 [brcmsmac]
> [   28.078707]  [<ffffffffa0479101>] brcms_c_dpc+0x211/0x9d0 [brcmsmac]
> [   28.078717]  [<ffffffffa046d927>] ? brcms_dpc+0x27/0xf0 [brcmsmac]
> [   28.078731]  [<ffffffffa046d947>] brcms_dpc+0x47/0xf0 [brcmsmac]
> [   28.078736]  [<ffffffff81047dcc>] tasklet_action+0x6c/0xf0
> --snip--
> [   28.078974]  [<ffffffff813891bd>] SyS_sendmsg+0xd/0x20
> [   28.078979]  [<ffffffff81455c24>] tracesys+0xdd/0xe2
> [   28.078982] ---[ end trace 6164d1a08148e9c8 ]---
> [   28.078984] Mapped at:
> [   28.078985]  [<ffffffff8122c8fd>] debug_dma_map_page+0x9d/0x150
> [   28.078989]  [<ffffffffa04a9322>] dma_rxfill+0x102/0x3d0 [brcmsmac]
> [   28.079001]  [<ffffffffa047a13d>] brcms_c_init+0x87d/0x1100 [brcmsmac]
> [   28.079010]  [<ffffffffa046d851>] brcms_init+0x21/0x30 [brcmsmac]
> [   28.079018]  [<ffffffffa04786e0>] brcms_c_up+0x150/0x430 [brcmsmac]
>
> As the patch adds a new failure mechanism to dma_rxfill(). When I changed the
> comment at the start of the routine to add that information, I also polished
> the wording.
>
> Signed-off-by: Larry Finger<Larry.Finger@lwfinger.net>
> Cc: Stable<stable@vger.kernel.org>
> Cc: Brett Rudley<brudley@broadcom.com>
> Cc: Arend van Spriel<arend@broadcom.com>

You can change this one into an Acked-by: (if you want).

Regards,
Arend

> Cc: Franky (Zhenhui) Lin<frankyl@broadcom.com>
> Cc: Hante Meuleman<meuleman@broadcom.com>
> Cc: brcm80211-dev-list@broadcom.com
> Signed-off-by: John W. Linville<linville@tuxdriver.com>
> ---
> Did this one get lost?
>
> V2 - fixed two patch errors.
> V3 - address comments from Arend (linville)
>
>   drivers/net/wireless/brcm80211/brcmsmac/dma.c | 15 +++++++++++----
>   1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
> index 1860c57..4fb9635 100644
> --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c
> +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
> @@ -1015,9 +1015,10 @@ static bool dma64_txidle(struct dma_info *di)
>
>   /*
>    * post receive buffers
> - *  return false is refill failed completely and ring is empty this will stall
> - *  the rx dma and user might want to call rxfill again asap. This unlikely
> - *  happens on memory-rich NIC, but often on memory-constrained dongle
> + *  Return false if refill failed completely or dma mapping failed. The ring
> + *  is empty, which will stall the rx dma and user might want to call rxfill
> + *  again asap. This is unlikely to happen on a memory-rich NIC, but often on
> + *  memory-constrained dongle.
>    */
>   bool dma_rxfill(struct dma_pub *pub)
>   {
> @@ -1078,6 +1079,8 @@ bool dma_rxfill(struct dma_pub *pub)
>
>   		pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
>   				    DMA_FROM_DEVICE);
> +		if (dma_mapping_error(di->dmadev, pa))
> +			return false;
>
>   		/* save the free packet pointer */
>   		di->rxp[rxout] = p;
> @@ -1284,7 +1287,11 @@ static void dma_txenq(struct dma_info *di, struct sk_buff *p)
>
>   	/* get physical address of buffer start */
>   	pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE);
> -
> +	/* if mapping failed, free skb */
> +	if (dma_mapping_error(di->dmadev, pa)) {
> +		brcmu_pkt_buf_free_skb(p);
> +		return;
> +	}
>   	/* With a DMA segment list, Descriptor table is filled
>   	 * using the segment list instead of looping over
>   	 * buffers in multi-chain DMA. Therefore, EOF for SGLIST



^ permalink raw reply

* Re: FUSB200 xhci issue
From: Oleksij Rempel @ 2013-08-10  6:19 UTC (permalink / raw)
  To: Alan Stern
  Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
	USB list, linux-wireless
In-Reply-To: <Pine.LNX.4.44L0.1308091529080.1405-100000@iolanthe.rowland.org>

Am 09.08.2013 21:32, schrieb Alan Stern:
> On Fri, 9 Aug 2013, Oleksij Rempel wrote:
>
>>> Is there any way to prevent the device from losing its firmware during
>>> a USB reset or suspend?
>>
>> For suspend - yes. It is possible to ignore suspend command or put the
>> SoC in low power mode - but is it probably not so easy to bring it back.
>> I would need to read more code and create some doc as side effect untill
>> i understand how it works.
>> I'm not sure how about reset command. I would need more testing and some
>> ones help. If i see it correctly, usb reset should affect only usb core
>> and usb pll.
>>
>> How can i trigger usb reset?
>
> http://marc.info/?l=linux-usb&m=121459435621262&w=2
>
> Give the program the pathname for the USB device node.  For example:
>
> 	usbreset /dev/bus/usb/001/004

Great! thx!

usb reset do not affect behaviour of firmware. At least after i remove 
all attempts to reboot FW from driver.
If adapter will got reset signal, FW will be notified about it. Then FW 
will remove reset flag and will just continue to work. After usb reset, 
lsusb show correct, update information - EP3 and EP4 was updated from 
INT to BULK.

I assume, no i need to add to the driver some kind of firmware check. 
What is the proper way to do it?

-- 
Regards,
Oleksij

^ permalink raw reply

* [PATCH] mwifiex: fix build error when CONFIG_PM is not set
From: Bing Zhao @ 2013-08-10  4:09 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Fengguang Wu, Amitkumar Karwar, Avinash Patil,
	Nishant Sarmukadam, Frank Huang, Bing Zhao

config: make ARCH=m68k allmodconfig

All error/warnings:

   drivers/net/wireless/mwifiex/cfg80211.c: In function
       'mwifiex_fill_coalesce_rule_info':
>> drivers/net/wireless/mwifiex/cfg80211.c:2493:3: error: implicit
       declaration of function 'mwifiex_is_pattern_supported'
       [-Werror=implicit-function-declaration]
   drivers/net/wireless/mwifiex/cfg80211.c: At top level:
   drivers/net/wireless/mwifiex/cfg80211.c:2537:12: warning:
       'mwifiex_cfg80211_set_coalesce' defined but not used
       [-Wunused-function]
   cc1: some warnings being treated as errors

Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
 drivers/net/wireless/mwifiex/cfg80211.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 0943e7e..fbad00a 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -2308,7 +2308,6 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
 }
 EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
 
-#ifdef CONFIG_PM
 static bool
 mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq,
 			     u8 max_byte_seq)
@@ -2339,6 +2338,7 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq,
 	return true;
 }
 
+#ifdef CONFIG_PM
 static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
 				    struct cfg80211_wowlan *wowlan)
 {
@@ -2602,8 +2602,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
 	.suspend = mwifiex_cfg80211_suspend,
 	.resume = mwifiex_cfg80211_resume,
 	.set_wakeup = mwifiex_cfg80211_set_wakeup,
-	.set_coalesce = mwifiex_cfg80211_set_coalesce,
 #endif
+	.set_coalesce = mwifiex_cfg80211_set_coalesce,
 };
 
 #ifdef CONFIG_PM
-- 
1.8.2.3


^ permalink raw reply related

* Re: [v3.10] [regression] [b43] : mac80211/minstrel: use the new rate control API
From: Felix Fietkau @ 2013-08-09 23:38 UTC (permalink / raw)
  To: Ronald; +Cc: linux-wireless
In-Reply-To: <CAF1_xX0PfHsSduF0ZGYE-skfC2Q1ZJgtqpOH5iSzJvX9HJu1mg@mail.gmail.com>

The fix for this issue has been merged upstream and is in the stable
queue (so will probably be included in 3.10.6). Another way you can get
rid of this error in your existing kernel is to enable
CONFIG_MAC80211_RC_MINSTREL_HT in your .config

- Felix

On 2013-08-09 11:28 PM, Ronald wrote:
> Excuse me, this should be a v3.10 regression.
> 
> 2013/8/9 Ronald <ronald645@gmail.com>:
>> [ Please cc me as I'm not subscribed ]
>>
>> Mentioned commit causes a regression on my box. It oopses after
>> NetworkManager comes up and tries to use the card (I think).
>>
>> The card is:
>>
>> [    1.220907] b43-phy0: Broadcom 4311 WLAN found (core revision 10)
>> [    1.230206] ata1.00: configured for UDMA/100
>> [    1.320018] b43-phy0: Found PHY: Analog 4, Type 2 (G), Revision 8
>> [    1.380120] Broadcom 43xx driver loaded [ Features: P ]
>>
>> I typed over the oops (first lines fell off, sorry):
>>
>> Workqueue: phy0 ieee80211_scan_work
>> task: ffff880000211c20 ti: ffff880034c0c000 task.ti: ffff880034c0c000
>> RIP: 0010:[<ffffffff81580382>] [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
>> RSP: 0018:ffff880034c0da88 EFLAGS: 00010286
>> RAX: ffffffff81870ac0 RBX: 0000000000000000 RCX: ffff880034c0db58
>> RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880034c67a00
>> RBP: ffff880034c0dac8 R08: ffff8800000863a0 R09: 0000000000000fff
>> R10: ffffffff81856020 R11: 0000000000000000 R12: ffff880034c67a00
>> R13: ffff880034da2740 R14: ffff880034c0db58 R15: ffff88000039f940
>> FS:  00007fd6da002700(0000) GS:ffffffff8181e000(0000) knlGS:0000000000000000
>> CS:  0010 DS: 0000 ES: 0000 CR0: 000000000005003b
>> CR2: 0000000000000048 CR3: 000000003517e000 CR4: 00000000000007f0
>> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
>> Stack:
>>  0000000000000000 ffff880034c0db28 ffff880034c0daf8 ffff88003517c330
>>  0000000000000000 ffff880034da2740 ffff880034c0db58 ffff88000039f940
>>  ffff880034c0daf8 ffffffff815653e1 ffff880034c0dbe0 ffff88003517c300
>> Call Trace:
>>  [<ffffffff815653e1>] rate_control_get_rate+0xa1/0xe0
>>  [<ffffffff815709e9>] invoke_tx_handlers+0x729/0x1360
>>  [<ffffffff8104bc3d>] ? sched_clock_local.constprop.1+0x1d/0x90
>>  [<ffffffff8104ce6e>] ? check_preempt_wakeup+0x11e/0x240
>>  [<ffffffff8157169d>] ieee80211_tx+0x7d/0x100
>>  [<ffffffff815717b1>] ieee80211_xmit+0x91/0xc0
>>  [<ffffffff8157307e>] __ieee80211_tx_skb_tid_band+0x6e/0x80
>>  [<ffffffff81577643>] ieee80211_send_probe_req+0x73/0xc0
>>  [<ffffffff8155a10f>] ieee80211_scan_state_send_probe+0x9f/0xe0
>>  [<ffffffff8155ad9c>] ieee80211_scan_work+0x1fc/0x440
>>  [<ffffffff8103c9ba>] process_one_work+0x13a/0x3b0
>>  [<ffffffff8103cfcb>] worker_thread+0x10b/0x350
>>  [<ffffffff8103cec0>] ? rescuer_thread+0x250/0x250
>>  [<ffffffff81042afa>] kthread+0xba/0xc0
>>  [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
>>  [<ffffffff8158c32a>] ret_from_fork+0x7a/0xb0
>>  [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
>> Code: 00 00 00 00 00 0f 1f 40 00 55 48 89 e5 48 83 ec 40 48 89 5d d8
>> 4c 89 65 e0 48 89 d3 4c 89 6d e8 4c 89 7d f8 49 89 fc 4c 89 75 f0 <44>
>> 0f b6 f7 4c 8b 71 18 48 89 ca 48 89 de 49 89 cd
>> RIP  [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
>>  RSP <ffff880034c0da88>
>> CR2: 0000000000000048
>> ---[ end trace 071727ab6dc6fcf3 ]---
>> Kernel panic - not syncing: Fatal exception in interrupt
>> drm_kms_helper: panic occurred, switching back to text console
> 


^ permalink raw reply

* Re: [PATCH 2/2] rtlwifi: sparse warnings: cast to restricted type
From: Larry Finger @ 2013-08-09 22:08 UTC (permalink / raw)
  To: John W. Linville; +Cc: Mark Schulte, linux-wireless
In-Reply-To: <20130809174131.GI30925@tuxdriver.com>

On 08/09/2013 12:41 PM, John W. Linville wrote:
> On Wed, Jul 31, 2013 at 12:21:45PM -0500, Larry Finger wrote:
>> On 07/31/2013 02:08 AM, Mark Schulte wrote:
>>> Adding type casts to suppress sparse warnings:
>>>   * warning: cast to restricted __le32/__le16
>>>
>>> Signed-off-by: Mark Schulte <schultetwin@gmail.com>
>>> ---
>>>   drivers/net/wireless/rtlwifi/ps.c | 16 ++++++++--------
>>>   1 file changed, 8 insertions(+), 8 deletions(-)
>>
>> I think this patch is OK, but until I get a chance to test it on a
>> big-endian machine (PowerBook G4 Titanium), please do not apply it.
>>
>> When I tried the patch, I discovered some kind of regression that
>> causes a kernel oops with an RTL8192CU device installed. This patch
>> is not the problem, but I will need to bisect the oops before I can
>> test. The machine takes a long time to build each kernel, thus it
>> will probably be a while.
>
> Any word on this?  The patch doesn't look like it should be causing
> such problems...?

I have not ywt solved the PPC crash. Unfortunately, thos processors are finicky 
and my debugging skills on that architecture are quite low. Go ahaed any apply 
this patch.

Acked-by: Larry Finger <Larry.Finger@lwfinger.net>

Larry



^ permalink raw reply

* Re: [v3.9] [regression] [b43] : mac80211/minstrel: use the new rate control API
From: Ronald @ 2013-08-09 22:05 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, nbd
In-Reply-To: <52056258.5070009@lwfinger.net>

This is with a v3.10 kernel. I also tried a v3.11 dev kernel, but that
one failed to boot due to a nouveau bug. I did a bisect of the v3.11
dev kernel. The first run (so, half way) this bug still occurred. So I
assumed the recession persisted.

I use Gentoo with NetworkManager 0.9.6.4.

I will try v3.11-rc4 as that boots again. Thanks for the suggestion.

2013/8/9 Larry Finger <Larry.Finger@lwfinger.net>:
> On 08/09/2013 04:25 PM, Ronald wrote:
>>
>> [ Please cc me as I'm not subscribed ]
>>
>> Mentioned commit causes a regression on my box. It oopses after
>> NetworkManager comes up and tries to use the card (I think).
>>
>> The card is:
>>
>> [    1.220907] b43-phy0: Broadcom 4311 WLAN found (core revision 10)
>> [    1.230206] ata1.00: configured for UDMA/100
>> [    1.320018] b43-phy0: Found PHY: Analog 4, Type 2 (G), Revision 8
>> [    1.380120] Broadcom 43xx driver loaded [ Features: P ]
>>
>> I typed over the oops (first lines fell off, sorry):
>>
>> Workqueue: phy0 ieee80211_scan_work
>> task: ffff880000211c20 ti: ffff880034c0c000 task.ti: ffff880034c0c000
>> RIP: 0010:[<ffffffff81580382>] [<ffffffff81580382>]
>> minstrel_get_rate+0x22/0x250
>> RSP: 0018:ffff880034c0da88 EFLAGS: 00010286
>> RAX: ffffffff81870ac0 RBX: 0000000000000000 RCX: ffff880034c0db58
>> RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880034c67a00
>> RBP: ffff880034c0dac8 R08: ffff8800000863a0 R09: 0000000000000fff
>> R10: ffffffff81856020 R11: 0000000000000000 R12: ffff880034c67a00
>> R13: ffff880034da2740 R14: ffff880034c0db58 R15: ffff88000039f940
>> FS:  00007fd6da002700(0000) GS:ffffffff8181e000(0000)
>> knlGS:0000000000000000
>> CS:  0010 DS: 0000 ES: 0000 CR0: 000000000005003b
>> CR2: 0000000000000048 CR3: 000000003517e000 CR4: 00000000000007f0
>> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
>> Stack:
>>   0000000000000000 ffff880034c0db28 ffff880034c0daf8 ffff88003517c330
>>   0000000000000000 ffff880034da2740 ffff880034c0db58 ffff88000039f940
>>   ffff880034c0daf8 ffffffff815653e1 ffff880034c0dbe0 ffff88003517c300
>> Call Trace:
>>   [<ffffffff815653e1>] rate_control_get_rate+0xa1/0xe0
>>   [<ffffffff815709e9>] invoke_tx_handlers+0x729/0x1360
>>   [<ffffffff8104bc3d>] ? sched_clock_local.constprop.1+0x1d/0x90
>>   [<ffffffff8104ce6e>] ? check_preempt_wakeup+0x11e/0x240
>>   [<ffffffff8157169d>] ieee80211_tx+0x7d/0x100
>>   [<ffffffff815717b1>] ieee80211_xmit+0x91/0xc0
>>   [<ffffffff8157307e>] __ieee80211_tx_skb_tid_band+0x6e/0x80
>>   [<ffffffff81577643>] ieee80211_send_probe_req+0x73/0xc0
>>   [<ffffffff8155a10f>] ieee80211_scan_state_send_probe+0x9f/0xe0
>>   [<ffffffff8155ad9c>] ieee80211_scan_work+0x1fc/0x440
>>   [<ffffffff8103c9ba>] process_one_work+0x13a/0x3b0
>>   [<ffffffff8103cfcb>] worker_thread+0x10b/0x350
>>   [<ffffffff8103cec0>] ? rescuer_thread+0x250/0x250
>>   [<ffffffff81042afa>] kthread+0xba/0xc0
>>   [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
>>   [<ffffffff8158c32a>] ret_from_fork+0x7a/0xb0
>>   [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
>> Code: 00 00 00 00 00 0f 1f 40 00 55 48 89 e5 48 83 ec 40 48 89 5d d8
>> 4c 89 65 e0 48 89 d3 4c 89 6d e8 4c 89 7d f8 49 89 fc 4c 89 75 f0 <44>
>> 0f b6 f7 4c 8b 71 18 48 89 ca 48 89 de 49 89 cd
>> RIP  [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
>>   RSP <ffff880034c0da88>
>> CR2: 0000000000000048
>> ---[ end trace 071727ab6dc6fcf3 ]---
>> Kernel panic - not syncing: Fatal exception in interrupt
>> drm_kms_helper: panic occurred, switching back to text console
>
>
> What kernel are you using? In addition, are you using NetworkManager and
> what desktop and/or distro release. I thought this problem was fixed some
> time ago.
>
> Larry
>
>

^ permalink raw reply

* Re: [PATCH v3] brcmsmac: Fix WARNING caused by lack of calls to dma_mapping_error()
From: Larry Finger @ 2013-08-09 22:05 UTC (permalink / raw)
  To: John W. Linville
  Cc: linux-wireless, Brett Rudley, Arend van Spriel,
	Franky (Zhenhui) Lin, Hante Meuleman, brcm80211-dev-list, Stable
In-Reply-To: <1376069781-22958-1-git-send-email-linville@tuxdriver.com>

On 08/09/2013 12:36 PM, John W. Linville wrote:
> From: "John W. Linville" <linville@tuxdriver.com>
>
> The driver fails to check the results of DMA mapping in twp places,
> which results in the following warning:
>
> [   28.078515] ------------[ cut here ]------------
> [   28.078529] WARNING: at lib/dma-debug.c:937 check_unmap+0x47e/0x930()
> [   28.078533] bcma-pci-bridge 0000:0e:00.0: DMA-API: device driver failed to check map error[device address=0x00000000b5d60d6c] [size=1876 bytes] [mapped as
>   single]
> [   28.078536] Modules linked in: bnep bluetooth vboxpci(O) vboxnetadp(O) vboxnetflt(O) vboxdrv(O) ipv6 b43 brcmsmac rtl8192cu rtl8192c_common rtlwifi mac802
> 11 brcmutil cfg80211 snd_hda_codec_conexant rng_core snd_hda_intel kvm_amd snd_hda_codec ssb kvm mmc_core snd_pcm snd_seq snd_timer snd_seq_device snd k8temp
>   cordic joydev serio_raw hwmon sr_mod sg pcmcia pcmcia_core soundcore cdrom i2c_nforce2 i2c_core forcedeth bcma snd_page_alloc autofs4 ext4 jbd2 mbcache crc1
> 6 scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh ata_generic pata_amd
> [   28.078602] CPU: 1 PID: 2570 Comm: NetworkManager Tainted: G           O 3.10.0-rc7-wl+ #42
> [   28.078605] Hardware name: Hewlett-Packard HP Pavilion dv2700 Notebook PC/30D6, BIOS F.27 11/27/2008
> [   28.078607]  0000000000000009 ffff8800bbb03ad8 ffffffff8144f898 ffff8800bbb03b18
> [   28.078612]  ffffffff8103e1eb 0000000000000002 ffff8800b719f480 ffff8800b7b9c010
> [   28.078617]  ffffffff824204c0 ffffffff81754d57 0000000000000754 ffff8800bbb03b78
> [   28.078622] Call Trace:
> [   28.078624]  <IRQ>  [<ffffffff8144f898>] dump_stack+0x19/0x1b
> [   28.078634]  [<ffffffff8103e1eb>] warn_slowpath_common+0x6b/0xa0
> [   28.078638]  [<ffffffff8103e2c1>] warn_slowpath_fmt+0x41/0x50
> [   28.078650]  [<ffffffff8122d7ae>] check_unmap+0x47e/0x930
> [   28.078655]  [<ffffffff8122de4c>] debug_dma_unmap_page+0x5c/0x70
> [   28.078679]  [<ffffffffa04a808c>] dma64_getnextrxp+0x10c/0x190 [brcmsmac]
> [   28.078691]  [<ffffffffa04a9042>] dma_rx+0x62/0x240 [brcmsmac]
> [   28.078707]  [<ffffffffa0479101>] brcms_c_dpc+0x211/0x9d0 [brcmsmac]
> [   28.078717]  [<ffffffffa046d927>] ? brcms_dpc+0x27/0xf0 [brcmsmac]
> [   28.078731]  [<ffffffffa046d947>] brcms_dpc+0x47/0xf0 [brcmsmac]
> [   28.078736]  [<ffffffff81047dcc>] tasklet_action+0x6c/0xf0
> --snip--
> [   28.078974]  [<ffffffff813891bd>] SyS_sendmsg+0xd/0x20
> [   28.078979]  [<ffffffff81455c24>] tracesys+0xdd/0xe2
> [   28.078982] ---[ end trace 6164d1a08148e9c8 ]---
> [   28.078984] Mapped at:
> [   28.078985]  [<ffffffff8122c8fd>] debug_dma_map_page+0x9d/0x150
> [   28.078989]  [<ffffffffa04a9322>] dma_rxfill+0x102/0x3d0 [brcmsmac]
> [   28.079001]  [<ffffffffa047a13d>] brcms_c_init+0x87d/0x1100 [brcmsmac]
> [   28.079010]  [<ffffffffa046d851>] brcms_init+0x21/0x30 [brcmsmac]
> [   28.079018]  [<ffffffffa04786e0>] brcms_c_up+0x150/0x430 [brcmsmac]
>
> As the patch adds a new failure mechanism to dma_rxfill(). When I changed the
> comment at the start of the routine to add that information, I also polished
> the wording.
>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> Cc: Stable <stable@vger.kernel.org>
> Cc: Brett Rudley <brudley@broadcom.com>
> Cc: Arend van Spriel <arend@broadcom.com>
> Cc: Franky (Zhenhui) Lin <frankyl@broadcom.com>
> Cc: Hante Meuleman <meuleman@broadcom.com>
> Cc: brcm80211-dev-list@broadcom.com
> Signed-off-by: John W. Linville <linville@tuxdriver.com>
> ---
> Did this one get lost?
>
> V2 - fixed two patch errors.
> V3 - address comments from Arend (linville)
>

For some reason, I never got the mail containing Arend's comments, and I forgot 
about it. If John's V3 fixes take care of them, then it should be pushed.

Larry



^ permalink raw reply

* Re: [v3.9] [regression] [b43] : mac80211/minstrel: use the new rate control API
From: Larry Finger @ 2013-08-09 21:42 UTC (permalink / raw)
  To: Ronald; +Cc: linux-wireless, nbd
In-Reply-To: <CAF1_xX2j6evCrjK-XXm7y2ayOtjHEPJWva-OZJdL5SsVAif=Ew@mail.gmail.com>

On 08/09/2013 04:25 PM, Ronald wrote:
> [ Please cc me as I'm not subscribed ]
>
> Mentioned commit causes a regression on my box. It oopses after
> NetworkManager comes up and tries to use the card (I think).
>
> The card is:
>
> [    1.220907] b43-phy0: Broadcom 4311 WLAN found (core revision 10)
> [    1.230206] ata1.00: configured for UDMA/100
> [    1.320018] b43-phy0: Found PHY: Analog 4, Type 2 (G), Revision 8
> [    1.380120] Broadcom 43xx driver loaded [ Features: P ]
>
> I typed over the oops (first lines fell off, sorry):
>
> Workqueue: phy0 ieee80211_scan_work
> task: ffff880000211c20 ti: ffff880034c0c000 task.ti: ffff880034c0c000
> RIP: 0010:[<ffffffff81580382>] [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
> RSP: 0018:ffff880034c0da88 EFLAGS: 00010286
> RAX: ffffffff81870ac0 RBX: 0000000000000000 RCX: ffff880034c0db58
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880034c67a00
> RBP: ffff880034c0dac8 R08: ffff8800000863a0 R09: 0000000000000fff
> R10: ffffffff81856020 R11: 0000000000000000 R12: ffff880034c67a00
> R13: ffff880034da2740 R14: ffff880034c0db58 R15: ffff88000039f940
> FS:  00007fd6da002700(0000) GS:ffffffff8181e000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 000000000005003b
> CR2: 0000000000000048 CR3: 000000003517e000 CR4: 00000000000007f0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Stack:
>   0000000000000000 ffff880034c0db28 ffff880034c0daf8 ffff88003517c330
>   0000000000000000 ffff880034da2740 ffff880034c0db58 ffff88000039f940
>   ffff880034c0daf8 ffffffff815653e1 ffff880034c0dbe0 ffff88003517c300
> Call Trace:
>   [<ffffffff815653e1>] rate_control_get_rate+0xa1/0xe0
>   [<ffffffff815709e9>] invoke_tx_handlers+0x729/0x1360
>   [<ffffffff8104bc3d>] ? sched_clock_local.constprop.1+0x1d/0x90
>   [<ffffffff8104ce6e>] ? check_preempt_wakeup+0x11e/0x240
>   [<ffffffff8157169d>] ieee80211_tx+0x7d/0x100
>   [<ffffffff815717b1>] ieee80211_xmit+0x91/0xc0
>   [<ffffffff8157307e>] __ieee80211_tx_skb_tid_band+0x6e/0x80
>   [<ffffffff81577643>] ieee80211_send_probe_req+0x73/0xc0
>   [<ffffffff8155a10f>] ieee80211_scan_state_send_probe+0x9f/0xe0
>   [<ffffffff8155ad9c>] ieee80211_scan_work+0x1fc/0x440
>   [<ffffffff8103c9ba>] process_one_work+0x13a/0x3b0
>   [<ffffffff8103cfcb>] worker_thread+0x10b/0x350
>   [<ffffffff8103cec0>] ? rescuer_thread+0x250/0x250
>   [<ffffffff81042afa>] kthread+0xba/0xc0
>   [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
>   [<ffffffff8158c32a>] ret_from_fork+0x7a/0xb0
>   [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
> Code: 00 00 00 00 00 0f 1f 40 00 55 48 89 e5 48 83 ec 40 48 89 5d d8
> 4c 89 65 e0 48 89 d3 4c 89 6d e8 4c 89 7d f8 49 89 fc 4c 89 75 f0 <44>
> 0f b6 f7 4c 8b 71 18 48 89 ca 48 89 de 49 89 cd
> RIP  [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
>   RSP <ffff880034c0da88>
> CR2: 0000000000000048
> ---[ end trace 071727ab6dc6fcf3 ]---
> Kernel panic - not syncing: Fatal exception in interrupt
> drm_kms_helper: panic occurred, switching back to text console

What kernel are you using? In addition, are you using NetworkManager and what 
desktop and/or distro release. I thought this problem was fixed some time ago.

Larry



^ permalink raw reply

* Re: [v3.10] [regression] [b43] : mac80211/minstrel: use the new rate control API
From: Ronald @ 2013-08-09 21:28 UTC (permalink / raw)
  To: linux-wireless, nbd

Excuse me, this should be a v3.10 regression.

2013/8/9 Ronald <ronald645@gmail.com>:
> [ Please cc me as I'm not subscribed ]
>
> Mentioned commit causes a regression on my box. It oopses after
> NetworkManager comes up and tries to use the card (I think).
>
> The card is:
>
> [    1.220907] b43-phy0: Broadcom 4311 WLAN found (core revision 10)
> [    1.230206] ata1.00: configured for UDMA/100
> [    1.320018] b43-phy0: Found PHY: Analog 4, Type 2 (G), Revision 8
> [    1.380120] Broadcom 43xx driver loaded [ Features: P ]
>
> I typed over the oops (first lines fell off, sorry):
>
> Workqueue: phy0 ieee80211_scan_work
> task: ffff880000211c20 ti: ffff880034c0c000 task.ti: ffff880034c0c000
> RIP: 0010:[<ffffffff81580382>] [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
> RSP: 0018:ffff880034c0da88 EFLAGS: 00010286
> RAX: ffffffff81870ac0 RBX: 0000000000000000 RCX: ffff880034c0db58
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880034c67a00
> RBP: ffff880034c0dac8 R08: ffff8800000863a0 R09: 0000000000000fff
> R10: ffffffff81856020 R11: 0000000000000000 R12: ffff880034c67a00
> R13: ffff880034da2740 R14: ffff880034c0db58 R15: ffff88000039f940
> FS:  00007fd6da002700(0000) GS:ffffffff8181e000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 000000000005003b
> CR2: 0000000000000048 CR3: 000000003517e000 CR4: 00000000000007f0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Stack:
>  0000000000000000 ffff880034c0db28 ffff880034c0daf8 ffff88003517c330
>  0000000000000000 ffff880034da2740 ffff880034c0db58 ffff88000039f940
>  ffff880034c0daf8 ffffffff815653e1 ffff880034c0dbe0 ffff88003517c300
> Call Trace:
>  [<ffffffff815653e1>] rate_control_get_rate+0xa1/0xe0
>  [<ffffffff815709e9>] invoke_tx_handlers+0x729/0x1360
>  [<ffffffff8104bc3d>] ? sched_clock_local.constprop.1+0x1d/0x90
>  [<ffffffff8104ce6e>] ? check_preempt_wakeup+0x11e/0x240
>  [<ffffffff8157169d>] ieee80211_tx+0x7d/0x100
>  [<ffffffff815717b1>] ieee80211_xmit+0x91/0xc0
>  [<ffffffff8157307e>] __ieee80211_tx_skb_tid_band+0x6e/0x80
>  [<ffffffff81577643>] ieee80211_send_probe_req+0x73/0xc0
>  [<ffffffff8155a10f>] ieee80211_scan_state_send_probe+0x9f/0xe0
>  [<ffffffff8155ad9c>] ieee80211_scan_work+0x1fc/0x440
>  [<ffffffff8103c9ba>] process_one_work+0x13a/0x3b0
>  [<ffffffff8103cfcb>] worker_thread+0x10b/0x350
>  [<ffffffff8103cec0>] ? rescuer_thread+0x250/0x250
>  [<ffffffff81042afa>] kthread+0xba/0xc0
>  [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
>  [<ffffffff8158c32a>] ret_from_fork+0x7a/0xb0
>  [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
> Code: 00 00 00 00 00 0f 1f 40 00 55 48 89 e5 48 83 ec 40 48 89 5d d8
> 4c 89 65 e0 48 89 d3 4c 89 6d e8 4c 89 7d f8 49 89 fc 4c 89 75 f0 <44>
> 0f b6 f7 4c 8b 71 18 48 89 ca 48 89 de 49 89 cd
> RIP  [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
>  RSP <ffff880034c0da88>
> CR2: 0000000000000048
> ---[ end trace 071727ab6dc6fcf3 ]---
> Kernel panic - not syncing: Fatal exception in interrupt
> drm_kms_helper: panic occurred, switching back to text console

^ permalink raw reply

* [v3.9] [regression] [b43] : mac80211/minstrel: use the new rate control API
From: Ronald @ 2013-08-09 21:25 UTC (permalink / raw)
  To: linux-wireless, nbd

[ Please cc me as I'm not subscribed ]

Mentioned commit causes a regression on my box. It oopses after
NetworkManager comes up and tries to use the card (I think).

The card is:

[    1.220907] b43-phy0: Broadcom 4311 WLAN found (core revision 10)
[    1.230206] ata1.00: configured for UDMA/100
[    1.320018] b43-phy0: Found PHY: Analog 4, Type 2 (G), Revision 8
[    1.380120] Broadcom 43xx driver loaded [ Features: P ]

I typed over the oops (first lines fell off, sorry):

Workqueue: phy0 ieee80211_scan_work
task: ffff880000211c20 ti: ffff880034c0c000 task.ti: ffff880034c0c000
RIP: 0010:[<ffffffff81580382>] [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
RSP: 0018:ffff880034c0da88 EFLAGS: 00010286
RAX: ffffffff81870ac0 RBX: 0000000000000000 RCX: ffff880034c0db58
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880034c67a00
RBP: ffff880034c0dac8 R08: ffff8800000863a0 R09: 0000000000000fff
R10: ffffffff81856020 R11: 0000000000000000 R12: ffff880034c67a00
R13: ffff880034da2740 R14: ffff880034c0db58 R15: ffff88000039f940
FS:  00007fd6da002700(0000) GS:ffffffff8181e000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 000000000005003b
CR2: 0000000000000048 CR3: 000000003517e000 CR4: 00000000000007f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Stack:
 0000000000000000 ffff880034c0db28 ffff880034c0daf8 ffff88003517c330
 0000000000000000 ffff880034da2740 ffff880034c0db58 ffff88000039f940
 ffff880034c0daf8 ffffffff815653e1 ffff880034c0dbe0 ffff88003517c300
Call Trace:
 [<ffffffff815653e1>] rate_control_get_rate+0xa1/0xe0
 [<ffffffff815709e9>] invoke_tx_handlers+0x729/0x1360
 [<ffffffff8104bc3d>] ? sched_clock_local.constprop.1+0x1d/0x90
 [<ffffffff8104ce6e>] ? check_preempt_wakeup+0x11e/0x240
 [<ffffffff8157169d>] ieee80211_tx+0x7d/0x100
 [<ffffffff815717b1>] ieee80211_xmit+0x91/0xc0
 [<ffffffff8157307e>] __ieee80211_tx_skb_tid_band+0x6e/0x80
 [<ffffffff81577643>] ieee80211_send_probe_req+0x73/0xc0
 [<ffffffff8155a10f>] ieee80211_scan_state_send_probe+0x9f/0xe0
 [<ffffffff8155ad9c>] ieee80211_scan_work+0x1fc/0x440
 [<ffffffff8103c9ba>] process_one_work+0x13a/0x3b0
 [<ffffffff8103cfcb>] worker_thread+0x10b/0x350
 [<ffffffff8103cec0>] ? rescuer_thread+0x250/0x250
 [<ffffffff81042afa>] kthread+0xba/0xc0
 [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
 [<ffffffff8158c32a>] ret_from_fork+0x7a/0xb0
 [<ffffffff81042a40>] ? __kthread_parkme+0x80/0x80
Code: 00 00 00 00 00 0f 1f 40 00 55 48 89 e5 48 83 ec 40 48 89 5d d8
4c 89 65 e0 48 89 d3 4c 89 6d e8 4c 89 7d f8 49 89 fc 4c 89 75 f0 <44>
0f b6 f7 4c 8b 71 18 48 89 ca 48 89 de 49 89 cd
RIP  [<ffffffff81580382>] minstrel_get_rate+0x22/0x250
 RSP <ffff880034c0da88>
CR2: 0000000000000048
---[ end trace 071727ab6dc6fcf3 ]---
Kernel panic - not syncing: Fatal exception in interrupt
drm_kms_helper: panic occurred, switching back to text console

^ permalink raw reply

* Re: FUSB200 xhci issue
From: Alan Stern @ 2013-08-09 19:32 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Christian Lamparter, Sarah Sharp, Seth Forshee, ath9k_htc_fw,
	USB list, linux-wireless
In-Reply-To: <52053AC4.3090509@rempel-privat.de>

On Fri, 9 Aug 2013, Oleksij Rempel wrote:

> > Is there any way to prevent the device from losing its firmware during
> > a USB reset or suspend?
> 
> For suspend - yes. It is possible to ignore suspend command or put the 
> SoC in low power mode - but is it probably not so easy to bring it back. 
> I would need to read more code and create some doc as side effect untill 
> i understand how it works.
> I'm not sure how about reset command. I would need more testing and some 
> ones help. If i see it correctly, usb reset should affect only usb core 
> and usb pll.
> 
> How can i trigger usb reset?

http://marc.info/?l=linux-usb&m=121459435621262&w=2

Give the program the pathname for the USB device node.  For example:

	usbreset /dev/bus/usb/001/004

Alan Stern


^ permalink raw reply

* Re: pull-request: mac80211-next 2013-08-06
From: John W. Linville @ 2013-08-09 19:08 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1375779392.8219.9.camel@jlt4.sipsolutions.net>

On Tue, Aug 06, 2013 at 10:56:32AM +0200, Johannes Berg wrote:
> Hi John,
> 
> And one more for mac80211-next (and I have nothing for mac80211 today).
> 
> Here I have an IBSS improvement, interworking (11u) definitions, a
> change to make the LED blinking nicer, more VHT (11ac) definitions, VHT
> radiotap TX status, channel switch support in cfg80211 and mac80211 as
> well as a small new debugfs file showing driver-buffered data for
> sleeping clients.
> 
> Let me know if there's any problem.
> 
> Thanks,
> johannes
> 
> The following changes since commit c82b5a74cc739385db6e4275fe504a0e9469bf01:
> 
>   mac80211: make active monitor injection work w/ HW queue (2013-07-16 09:58:19 +0300)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git for-john
> 
> for you to fetch changes up to 73da7d5bab79ad7e16ff44d67c3fe8b9c0b33e5b:
> 
>   mac80211: add channel switch command and beacon callbacks (2013-08-01 18:30:33 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: pull-request: iwlwifi-next 2013-08-06
From: John W. Linville @ 2013-08-09 19:07 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1375779167.8219.5.camel@jlt4.sipsolutions.net>

On Tue, Aug 06, 2013 at 10:52:47AM +0200, Johannes Berg wrote:
> Hi John,
> 
> And a few more things for the -next stream for iwlwifi. The signal
> strength reporting fix is the reason I'd originally tried to ask you to
> not pull before :-)
> 
> This time I have a signal strength reporting fix from Avri, some
> cleanups from Eliad, Eyal and myself and a new debugfs file from Matti.
> 
> Please let me know if there's any problem.
> 
> Thanks,
> johannes
> 
> The following changes since commit 147fc9be81d10e6e863323c0b54e140b42fd1ed6:
> 
>   iwlwifi: mvm: advertise support for DYNAMIC / STATIC SMPS (2013-07-31 11:05:08 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git for-john
> 
> for you to fetch changes up to ef4394b9477f9078d78ae3e8359eae094c9b19d8:
> 
>   iwlwifi: mvm: use designated initialization for some arrays (2013-08-06 10:35:04 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox