Skip to contentSkip to conversation

ath9k: Implement rx copy-break.

PATCH New greearb at candelatech.com 6 participants 16 messages Jan 8, 2011 – Jan 10, 2011 Qualcomm Atheros ATH9K wireless driver

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

From: Ben Greear <[email protected]>

This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c

 drivers/net/wireless/ath/ath9k/recv.c |   92 ++++++++++++++++++++++-----------
 1 files changed, 61 insertions(+), 31 deletions(-)
drivers/net/wireless/ath/ath9k/recv.c +61 -31
index b2497b8..ea2f67c 100644
@@ -16,6 +16,7 @@
 
 #include "ath9k.h"
 #include "ar9003_mac.h"
+#include <linux/pci.h>
 
 #define SKB_CB_ATHBUF(__skb)	(*((struct ath_buf **)__skb->cb))
 
@@ -1623,7 +1624,7 @@ div_comb_done:
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
 	struct ath_buf *bf;
-	struct sk_buff *skb = NULL, *requeue_skb;
+	struct sk_buff *skb = NULL, *requeue_skb = NULL;
 	struct ieee80211_rx_status *rxs;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1634,7 +1635,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 	 */
 	struct ieee80211_hw *hw = NULL;
 	struct ieee80211_hdr *hdr;
-	int retval;
+	int retval, len;
+	bool use_copybreak = true;
 	bool decrypt_error = false;
 	struct ath_rx_status rs;
 	enum ath9k_rx_qtype qtype;
@@ -1702,42 +1704,70 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
 			rxs->mactime += 0x100000000ULL;
 
-		/* Ensure we always have an skb to requeue once we are done
-		 * processing the current buffer's skb */
-		requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
-
-		/* If there is no memory we ignore the current RX'd frame,
-		 * tell hardware it can give us a new frame using the old
-		 * skb and put it at the tail of the sc->rx.rxbuf list for
-		 * processing. */
-		if (!requeue_skb)
-			goto requeue;
-
-		/* Unmap the frame */
-		dma_unmap_single(sc->dev, bf->bf_buf_addr,
-				 common->rx_bufsize,
-				 dma_type);
+		len = rs.rs_datalen + ah->caps.rx_status_len;
+		if (use_copybreak) {
+			skb = netdev_alloc_skb(NULL, len);
+			if (!skb) {
+				skb = bf->bf_mpdu;
+				use_copybreak = false;
+				goto non_copybreak;
+			}
+		} else {
+non_copybreak:
+			/* Ensure we always have an skb to requeue once we are
+			 * done processing the current buffer's skb */
+			requeue_skb = ath_rxbuf_alloc(common,
+						      common->rx_bufsize,
+						      GFP_ATOMIC);
+
+			/* If there is no memory we ignore the current RX'd
+			 * frame, tell hardware it can give us a new frame
+			 * using the old skb and put it at the tail of the
+			 * sc->rx.rxbuf list for processing. */
+			if (!requeue_skb)
+				goto requeue;
+
+			/* Unmap the frame */
+			dma_unmap_single(sc->dev, bf->bf_buf_addr,
+					 common->rx_bufsize,
+					 dma_type);
+		}
 
-		skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len);
+		skb_put(skb, len);
 		if (ah->caps.rx_status_len)
 			skb_pull(skb, ah->caps.rx_status_len);
 
+		if (use_copybreak) {
+			struct pci_dev *pdev = to_pci_dev(sc->dev);
+			pci_dma_sync_single_for_cpu(pdev, bf->bf_buf_addr,
+						    len, PCI_DMA_FROMDEVICE);
+			skb_copy_from_linear_data(bf->bf_mpdu, skb->data, len);
+			pci_dma_sync_single_for_device(pdev, bf->bf_buf_addr,
+						       len, PCI_DMA_FROMDEVICE);
+			memcpy(skb->cb, bf->bf_mpdu->cb, sizeof(skb->cb));
+			rxs =  IEEE80211_SKB_RXCB(skb);
+		}
+
 		ath9k_rx_skb_postprocess(common, skb, &rs,
 					 rxs, decrypt_error);
 
-		/* We will now give hardware our shiny new allocated skb */
-		bf->bf_mpdu = requeue_skb;
-		bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
-						 common->rx_bufsize,
-						 dma_type);
-		if (unlikely(dma_mapping_error(sc->dev,
-			  bf->bf_buf_addr))) {
-			dev_kfree_skb_any(requeue_skb);
-			bf->bf_mpdu = NULL;
-			bf->bf_buf_addr = 0;
-			ath_err(common, "dma_mapping_error() on RX\n");
-			ath_rx_send_to_mac80211(hw, sc, skb);
-			break;
+		if (!use_copybreak) {
+			/* We will now give hardware our shiny new allocated
+			 * skb */
+			bf->bf_mpdu = requeue_skb;
+			bf->bf_buf_addr = dma_map_single(sc->dev,
+							 requeue_skb->data,
+							 common->rx_bufsize,
+							 dma_type);
+			if (unlikely(dma_mapping_error(sc->dev,
+						       bf->bf_buf_addr))) {
+				dev_kfree_skb_any(requeue_skb);
+				bf->bf_mpdu = NULL;
+				bf->bf_buf_addr = 0;
+				ath_err(common, "dma_mapping_error() on RX\n");
+				ath_rx_send_to_mac80211(hw, sc, skb);
+				break;
+			}
 		}
 
 		/*
Signature · 1 line
1.7.2.3
#1 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 35 lines · greearb at candelatech.com

From: Ben Greear<[email protected]>

This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c

  drivers/net/wireless/ath/ath9k/recv.c |   92 ++++++++++++++++++++++-----------
  1 files changed, 61 insertions(+), 31 deletions(-)
drivers/net/wireless/ath/ath9k/recv.c +0 -14
index b2497b8..ea2f67c 100644
@@ -1702,42 +1704,70 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
  		    unlikely(tsf_lower - rs.rs_tstamp>  0x10000000))
  			rxs->mactime += 0x100000000ULL;
 
-		/* Ensure we always have an skb to requeue once we are done
-		 * processing the current buffer's skb */
-		requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
-
-		/* If there is no memory we ignore the current RX'd frame,
-		 * tell hardware it can give us a new frame using the old
-		 * skb and put it at the tail of the sc->rx.rxbuf list for
-		 * processing. */
-		if (!requeue_skb)
-			goto requeue;
-
-		/* Unmap the frame */
-		dma_unmap_single(sc->dev, bf->bf_buf_addr,
-				 common->rx_bufsize,

drivers/net/wireless/ath/ath9k/recv.c int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · line 1715

Quoted 10 lines
drivers/net/wireless/ath/ath9k/recv.c +9 -1
-				 dma_type);
+		len = rs.rs_datalen + ah->caps.rx_status_len;
+		if (use_copybreak) {
+			skb = netdev_alloc_skb(NULL, len);
+			if (!skb) {
+				skb = bf->bf_mpdu;
+				use_copybreak = false;
+				goto non_copybreak;
+			}
+		} else {

I think this should be dependent on packet size, maybe even based on the architecture. Especially on embedded hardware, copying large frames is probably quite a bit more expensive than allocating large buffers. Cache sizes are small, memory access takes several cycles, especially during concurrent DMA.
Once I'm back home, I could try a few packet size threshold to find a sweet spot for the typical MIPS hardware that I'm playing with. I expect a visible performance regression from this patch when applied as-is.

- Felix

author
#2 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 42 lines · Felix Fietkau
Quoted 41 lines · greearb at candelatech.com

From: Ben Greear<[email protected]>

This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c drivers/net/wireless/ath/ath9k/recv.c | 92 ++++++++++++++++++++++-----------

1 files changed, 61 insertions(+), 31 deletions(-)
drivers/net/wireless/ath/ath9k/recv.c +5 -15
index b2497b8..ea2f67c 100644
@@ -1702,42 +1704,70 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 unlikely(tsf_lower - rs.rs_tstamp> 0x10000000))
 rxs->mactime += 0x100000000ULL;
 
- /* Ensure we always have an skb to requeue once we are done
- * processing the current buffer's skb */
- requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
-
- /* If there is no memory we ignore the current RX'd frame,
- * tell hardware it can give us a new frame using the old
- * skb and put it at the tail of the sc->rx.rxbuf list for
- * processing. */
- if (!requeue_skb)
- goto requeue;
-
- /* Unmap the frame */
- dma_unmap_single(sc->dev, bf->bf_buf_addr,
- common->rx_bufsize,
- dma_type);
+ len = rs.rs_datalen + ah->caps.rx_status_len;
+ if (use_copybreak) {
+ skb = netdev_alloc_skb(NULL, len);
+ if (!skb) {
+ skb = bf->bf_mpdu;
Quoted 8 lines

drivers/net/wireless/ath/ath9k/recv.c int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · line 1715

Quoted 4 lines
drivers/net/wireless/ath/ath9k/recv.c +4 -0
+ use_copybreak = false;
+ goto non_copybreak;
+ }
+ } else {

I think this should be dependent on packet size, maybe even based on the architecture. Especially on embedded hardware, copying large frames is probably quite a bit more expensive than allocating large buffers. Cache sizes are small, memory access takes several cycles, especially during concurrent DMA. Once I'm back home, I could try a few packet size threshold to find a sweet spot for the typical MIPS hardware that I'm playing with. I expect a visible performance regression from this patch when applied as-is.

I see a serious performance improvement with this patch. My current test is sending 1024 byte UDP payloads to/from each of 60 stations at 128kbps. Please do try it out on your system and see how it performs there. I'm guessing that any time you have more than 1 VIF this will be a good improvement since mac80211 does skb_copy (and you would typically be copying a much smaller packet with this patch).

If we do see performance differences on different platforms, this could perhaps be something we could tune at run-time.

Thanks,
Ben

Quoted 2 lines

- Felix

Signature · 2 lines
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com
#3 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 6 lines · Ben Greear
Quoted 4 lines · Felix Fietkau

I think this should be dependent on packet size, maybe even based on the architecture. Especially on embedded hardware, copying large frames is probably quite a bit more expensive than allocating large buffers. Cache sizes are small, memory access takes several cycles, especially during concurrent DMA. Once I'm back home, I could try a few packet size threshold to find a sweet spot for the typical MIPS hardware that I'm playing with. I expect a visible performance regression from this patch when applied as-is.

Quoted 8 lines

I see a serious performance improvement with this patch. My current test is sending 1024 byte UDP payloads to/from each of 60 stations at 128kbps. Please do try it out on your system and see how it performs there. I'm guessing that any time you have more than 1 VIF this will be a good improvement since mac80211 does skb_copy (and you would typically be copying a much smaller packet with this patch).

If we do see performance differences on different platforms, this could perhaps be something we could tune at run-time.

What kind of system are you testing on? If it's a PC, then the performance characteristics will be completely different compared to embedded hardware. I've had to remove a few copybreak-like implementations from various ethernet drivers on similar hardware, because even taking the hit of unaligned load/store exceptions (which are already *very* expensive on MIPS) was less than copying the full packet data, even with packet sizes less than what you're using.

I don't have suitable test hardware with me right now, but I'll do some tests in a week or so.

- Felix

author
#4 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 13 lines · Felix Fietkau
Quoted 12 lines · Ben Greear
Quoted 4 lines · Felix Fietkau

I think this should be dependent on packet size, maybe even based on the architecture. Especially on embedded hardware, copying large frames is probably quite a bit more expensive than allocating large buffers. Cache sizes are small, memory access takes several cycles, especially during concurrent DMA. Once I'm back home, I could try a few packet size threshold to find a sweet spot for the typical MIPS hardware that I'm playing with. I expect a visible performance regression from this patch when applied as-is.

I see a serious performance improvement with this patch. My current test is sending 1024 byte UDP payloads to/from each of 60 stations at 128kbps. Please do try it out on your system and see how it performs there. I'm guessing that any time you have more than 1 VIF this will be a good improvement since mac80211 does skb_copy (and you would typically be copying a much smaller packet with this patch).

Quoted 7 lines
Quoted 2 lines

If we do see performance differences on different platforms, this could perhaps be something we could tune at run-time.

What kind of system are you testing on? If it's a PC, then the performance characteristics will be completely different compared to embedded hardware. I've had to remove a few copybreak-like implementations from various ethernet drivers on similar hardware, because even taking the hit of unaligned load/store exceptions (which are already *very* expensive on MIPS) was less than copying the full packet data, even with packet sizes less than what you're using.

I don't have suitable test hardware with me right now, but I'll do some tests in a week or so.

I'm on a dual-core Atom processor. I'm interested in your MIPs results when you get them...

Thanks,
Ben

Quoted 2 lines

- Felix

Signature · 2 lines
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com
#5 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 39 lines · Ben Greear
Quoted 38 lines · Felix Fietkau
Quoted 23 lines · Ben Greear
Quoted 10 lines · Felix Fietkau

I think this should be dependent on packet size, maybe even based on the architecture. Especially on embedded hardware, copying large frames is probably quite a
bit more expensive than allocating large buffers. Cache sizes are small, memory access takes several cycles, especially during concurrent DMA. Once I'm back home, I could try a few packet size threshold to find a sweet spot for the typical MIPS hardware that I'm playing with. I expect a visible
performance regression from this patch when applied as-is.

I see a serious performance improvement with this patch. My current test is sending 1024 byte UDP
payloads to/from each of 60 stations at 128kbps. Please do try it out on your system and see how
it performs there. I'm guessing that any time you have more than 1 VIF this will be a good
improvement since mac80211 does skb_copy (and you would typically be copying a much smaller
packet with this patch).

Quoted 3 lines

If we do see performance differences on different platforms, this could perhaps be
something we could tune at run-time.

What kind of system are you testing on? If it's a PC, then the performance characteristics will be completely different compared to embedded hardware. I've had
to remove a few copybreak-like implementations from various ethernet drivers on similar hardware, because even taking the hit of unaligned load/store exceptions
(which are already *very* expensive on MIPS) was less than copying the full packet data, even with packet sizes less than what you're using.

Quoted 5 lines
Quoted 2 lines

I don't have suitable test hardware with me right now, but I'll do some tests in a week or so.

I'm on a dual-core Atom processor. ?I'm interested in your MIPs results when you get them...

I think we should also consider the added stability/saneness with this patch. I for one would be willing to live with some extra cpu load if that means the unstoppable rx dma problem can be contained (all the time).

Perhaps make it a configuration option?

/Bj?rn

#6 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 4 lines · Bj?rn Smedman

I think we should also consider the added stability/saneness with this patch. I for one would be willing to live with some extra cpu load if that means the unstoppable rx dma problem can be contained (all the time).

I don't think this patch has anything to do with the rx dma stop issue.

- Felix

#7 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

2011/1/9 Felix Fietkau <[email protected]>:

Quoted 8 lines · Bj?rn Smedman
Quoted 5 lines

I think we should also consider the added stability/saneness with this patch. I for one would be willing to live with some extra cpu load if that means the unstoppable rx dma problem can be contained (all the time).

I don't think this patch has anything to do with the rx dma stop issue.

Ok, so if you have a machine gun that can go off at any time and is impossible to stop you don't think it makes a difference where it's pointed? ;) Just kidding, and call me superstitious, but I would feel much better knowing ath9k is pointing that half-broken dma engine at it's own data only, at least until it's 100% stable.

/Bj?rn

#8 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

In reply to Ben Greear
Quoted 7 lines · Ben Greear
Quoted 6 lines · Felix Fietkau
Quoted 5 lines · greearb at candelatech.com

From: Ben Greear<[email protected]>
This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

As far as CPU use is concerned, 60 VIF scenario should not be the one to use for checking what is most efficient.. This really needs to be tested on something that uses a single VIF on an embedded (low-power CPU)..

For the order-1 allocation issues, it would be interesting to see if someone could take a look at using paged skbs or multiple RX descriptors with shorter skbs (and copying only for the case where a long frame is received so that only the A-MSDU RX case would suffer from extra copying).

Quoted 5 lines

I see a serious performance improvement with this patch. My current test is sending 1024 byte UDP payloads to/from each of 60 stations at 128kbps. Please do try it out on your system and see how it performs there. I'm guessing that any time you have more than 1 VIF this will be a good improvement since mac80211 does skb_copy (and you would typically be copying a much smaller packet with this patch).

How would this patch change the number of bytes copied by skb_copy?

Quoted 2 lines

If we do see performance differences on different platforms, this could perhaps be something we could tune at run-time.

I guess that could be looked at, but as long as that is not the case, the test setup you used is not exactly the most common case for ath9k in the upstream kernel and should not be used to figure out default behavior.

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
#9 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 13 lines · On Sunday 09 January 2011 19:13:04 Jouni Malinen wrote:
Quoted 7 lines · Ben Greear
Quoted 6 lines · Felix Fietkau
Quoted 5 lines · greearb at candelatech.com

From: Ben Greear<[email protected]>
This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

As far as CPU use is concerned, 60 VIF scenario should not be the one to use for checking what is most efficient.. This really needs to be tested on something that uses a single VIF on an embedded (low-power CPU)..

Quoted 5 lines

For the order-1 allocation issues, it would be interesting to see if someone could take a look at using paged skbs or multiple RX descriptors with shorter skbs (and copying only for the case where a long frame is received so that only the A-MSDU RX case would suffer from extra copying).

Well, here's a shot at paged rx. It'll only work when PAGE_SIZE > buf_size (which will be true for most system, I guess)

No idea how to handle EDMA... In fact I don't have any ath9k* solution at the moment to test ;), so you better backup your data!
---

drivers/net/wireless/ath/ath9k/ath9k.h +1 -0
index 3681caf5..b113f44 100644
@@ -227,6 +227,7 @@ struct ath_buf {
 					   an aggregate) */
 	struct ath_buf *bf_next;	/* next subframe in the aggregate */
 	struct sk_buff *bf_mpdu;	/* enclosing frame structure */
+	struct page *page;
 	void *bf_desc;			/* virtual addr of desc */
 	dma_addr_t bf_daddr;		/* physical addr of desc */
 	dma_addr_t bf_buf_addr;	/* physical addr of data buffer, for DMA */
drivers/net/wireless/ath/ath9k/recv.c +56 -53

234 lines not on this page · raw message

#10 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 20 lines · Christian Lamparter
Quoted 13 lines · On Sunday 09 January 2011 19:13:04 Jouni Malinen wrote:
Quoted 7 lines · Ben Greear
Quoted 6 lines · Felix Fietkau
Quoted 5 lines · greearb at candelatech.com

From: Ben Greear<[email protected]>
This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

As far as CPU use is concerned, 60 VIF scenario should not be the one to use for checking what is most efficient.. This really needs to be tested on something that uses a single VIF on an embedded (low-power CPU)..

Quoted 5 lines

For the order-1 allocation issues, it would be interesting to see if someone could take a look at using paged skbs or multiple RX descriptors with shorter skbs (and copying only for the case where a long frame is received so that only the A-MSDU RX case would suffer from extra copying).

Quoted 5 lines

Well, here's a shot at paged rx. It'll only work when PAGE_SIZE> buf_size (which will be true for most system, I guess)

No idea how to handle EDMA... In fact I don't have any ath9k* solution at the moment to test ;), so you better backup your data!

I think paged rx would be quite problematic for performance on embedded hardware that way. If I read the networking stack correctly, this would trigger skb_linearize() for network drivers/devices that cannot do scatter/gather IO when packets are forwarded between interfaces (the most common use case for OpenWrt).
It might be possible to avoid this by changing the network stack to bypass the linearize if there is only data in the page attached to the skb, but I don't know how easy that is to add, nor what corner cases I'd need to take care of.

- Felix

#11 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

In reply to Christian Lamparter
Quoted 9 lines · Christian Lamparter
Quoted 5 lines · On Sunday 09 January 2011 19:13:04 Jouni Malinen wrote:

For the order-1 allocation issues, it would be interesting to see if someone could take a look at using paged skbs or multiple RX descriptors with shorter skbs (and copying only for the case where a long frame is received so that only the A-MSDU RX case would suffer from extra copying).

Well, here's a shot at paged rx. It'll only work when PAGE_SIZE > buf_size (which will be true for most system, I guess)

Thanks!

For the multiple RX descriptors (fragmented buffer for DMA) part, here's a very preliminary patch to show how it could be done in ath9k for anyone who might want to experiment more in this area. This version is obviously only helping with large allocations (it uses half the buffer size). The extra copying is there for large A-MSDU case. Though, I did add some concept code to use skb frag_list to allow such a frame be delivered to mac80211 without needing any extra allocation/copying. That is commented out for now, if mac80211 can be made to handle A-MSDU RX processing with fragmented data (which should be relatively simple change, I'd hope), there should be no need for doing the extra copy in ath9k. (And likewise, I was too lazy to handle the EDMA case for now..)

The version here is limited to at maximum two fragments. If desired, this could be further extended to handle multiple fragments to get the default RX skb allocation shorter than 2k (i.e., to cover the normal 1500 MTU). I'm not sure whether that would result in noticeable benefit, but it could help in saving some memory when there are multiple skbs queued in various places in the networking stack. Likewise, the maximum A-MSDU receive length could be extended with this approach without having to use even longer individual buffers for RX.

---
 drivers/net/wireless/ath/ath9k/hw.h   |    2 
 drivers/net/wireless/ath/ath9k/main.c |    5 +
 drivers/net/wireless/ath/ath9k/recv.c |  102 +++++++++++++++++++++++++++++-----
 3 files changed, 95 insertions(+), 14 deletions(-)
drivers/net/wireless/ath/ath9k/hw.h +2 -0
@@ -852,6 +852,8 @@ struct ath_hw {
 
 	/* Enterprise mode cap */
 	u32 ent_mode;
+
+	struct sk_buff *rx_frag;
 };
 
 static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
drivers/net/wireless/ath/ath9k/main.c +5 -0
@@ -1320,6 +1320,11 @@ static void ath9k_stop(struct ieee80211_
 	} else
 		sc->rx.rxlink = NULL;
 
+	if (ah->rx_frag) {
+		dev_kfree_skb_any(ah->rx_frag);
+		ah->rx_frag = NULL;
+	}
+
 	/* disable HAL and put h/w to sleep */
 	ath9k_hw_disable(ah);
 	ath9k_hw_configpcipowersave(ah, 1, 1);
drivers/net/wireless/ath/ath9k/recv.c +88 -14

143 lines not on this page · raw message

Signature · 1 line
Jouni Malinen                                            PGP id EFC895FA
author
#12 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

In reply to Jouni Malinen
Quoted 20 lines · Jouni Malinen
Quoted 7 lines · Ben Greear
Quoted 6 lines · Felix Fietkau
Quoted 5 lines · greearb at candelatech.com

From: Ben Greear<[email protected]>
This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

As far as CPU use is concerned, 60 VIF scenario should not be the one to use for checking what is most efficient.. This really needs to be tested on something that uses a single VIF on an embedded (low-power CPU)..

For the order-1 allocation issues, it would be interesting to see if someone could take a look at using paged skbs or multiple RX descriptors with shorter skbs (and copying only for the case where a long frame is received so that only the A-MSDU RX case would suffer from extra copying).

Quoted 7 lines
Quoted 5 lines

I see a serious performance improvement with this patch. My current test is sending 1024 byte UDP payloads to/from each of 60 stations at 128kbps. Please do try it out on your system and see how it performs there. I'm guessing that any time you have more than 1 VIF this will be a good improvement since mac80211 does skb_copy (and you would typically be copying a much smaller packet with this patch).

How would this patch change the number of bytes copied by skb_copy?

It seems that if you allocate a 2-page SKB, as upstream ath9k does, pass that up the stack, then if/when anything calls 'skb_copy' it allocates a new skb with 2 pages even if the actual data-length is much smaller.

This copy wouldn't be so bad for single VIF scenarios (which means probably no copying), but you still end up exhausting the order-1 memory buffer pool with lots of big skbs floating around the system. Note that the original bug was not filed by me and happened on some embedded device, though I also see memory exhaustion in my tests with upstream code.

Quoted 8 lines
Quoted 3 lines

If we do see performance differences on different platforms, this could perhaps be something we could tune at run-time.

I guess that could be looked at, but as long as that is not the case, the test setup you used is not exactly the most common case for ath9k in the upstream kernel and should not be used to figure out default behavior.

True, but I also like the protection this should offer against stray DMA that this chipset/driver seems capable of.

I'm curious if anyone has any stats at all as far as ath9k performance goes?

Thanks,
Ben

Signature · 2 lines
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com
#13 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

In reply to greearb at candelatech.com

Hi Ben,

Quoted 12 lines

From: Ben Greear <[email protected]>

This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c

 drivers/net/wireless/ath/ath9k/recv.c |   92 ++++++++++++++++++++++-----------
 1 files changed, 61 insertions(+), 31 deletions(-)

<...>

Review

Quoted 2 lines
(quoted diff) +2 -0
+		if (use_copybreak) {
+			struct pci_dev *pdev = to_pci_dev(sc->dev);

This would cause undefined behaviour with ath9k devices sitting on an AHB bus.

drivers/net/wireless/ath/ath9k/recv.c int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · line 1746

Quoted 5 lines
drivers/net/wireless/ath/ath9k/recv.c +5 -0
+			pci_dma_sync_single_for_cpu(pdev, bf->bf_buf_addr,
+						    len, PCI_DMA_FROMDEVICE);
+			skb_copy_from_linear_data(bf->bf_mpdu, skb->data, len);
+			pci_dma_sync_single_for_device(pdev, bf->bf_buf_addr,
+						       len, PCI_DMA_FROMDEVICE);

Please use the bus agnostic equivalents of these DMA functions.

- Gabor

author
#14 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

Quoted 22 lines · Gabor Juhos

Hi Ben,

Quoted 12 lines

From: Ben Greear<[email protected]>

This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c

  drivers/net/wireless/ath/ath9k/recv.c |   92 ++++++++++++++++++++++-----------
  1 files changed, 61 insertions(+), 31 deletions(-)

<...>

Review

Quoted 2 lines
(quoted diff) +2 -0
+		if (use_copybreak) {
+			struct pci_dev *pdev = to_pci_dev(sc->dev);

This would cause undefined behaviour with ath9k devices sitting on an AHB bus.

Quoted 7 lines

drivers/net/wireless/ath/ath9k/recv.c int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) · line 1746

Quoted 5 lines
drivers/net/wireless/ath/ath9k/recv.c +5 -0
+			pci_dma_sync_single_for_cpu(pdev, bf->bf_buf_addr,
+						    len, PCI_DMA_FROMDEVICE);
+			skb_copy_from_linear_data(bf->bf_mpdu, skb->data, len);
+			pci_dma_sync_single_for_device(pdev, bf->bf_buf_addr,
+						       len, PCI_DMA_FROMDEVICE);

Please use the bus agnostic equivalents of these DMA functions.

Any idea what that might be?

Should we just disable copybreak for things on AHB bus?

Thanks,
Ben

Signature · 2 lines
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com
#15 lore raw

PATCH 1/1 ath9k: Implement rx copy-break.

2011.01.09. 18:49 keltez?ssel, Ben Greear ?rta:

Quoted 29 lines · Gabor Juhos
Quoted 28 lines

Hi Ben,

Quoted 12 lines

From: Ben Greear<[email protected]>

This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.

---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c

  drivers/net/wireless/ath/ath9k/recv.c |   92 ++++++++++++++++++++++-----------
  1 files changed, 61 insertions(+), 31 deletions(-)

<...>

Review

Quoted 2 lines
(quoted diff) +2 -0
+        if (use_copybreak) {
+            struct pci_dev *pdev = to_pci_dev(sc->dev);

This would cause undefined behaviour with ath9k devices sitting on an AHB bus.

Quoted 5 lines
drivers/net/wireless/ath/ath9k/recv.c +5 -0
+            pci_dma_sync_single_for_cpu(pdev, bf->bf_buf_addr,
+                            len, PCI_DMA_FROMDEVICE);
+            skb_copy_from_linear_data(bf->bf_mpdu, skb->data, len);
+            pci_dma_sync_single_for_device(pdev, bf->bf_buf_addr,
+                               len, PCI_DMA_FROMDEVICE);
Quoted 3 lines
Quoted 1 line

Please use the bus agnostic equivalents of these DMA functions.

Any idea what that might be?

Invalid/null pointer dereference probably. The problem is that sc->dev is pointing to a device structure inside a platform_device structure when it is not PCI device. Converting sc->dev to 'struct *pci_dev' and using the result as a parameter for a PCI specific function is not correct in this case.

Quoted 1 line

Should we just disable copybreak for things on AHB bus?

We should not disable it, order-1 allocation failures are present there as well.

-Gabor