2013-06-28 12:03:39

by Eric Dumazet

[permalink] [raw]
Subject: [PATCH] iwl3945: better skb management in rx path

From: Eric Dumazet <[email protected]>

Steinar reported reallocations of skb->head with IPv6, leading to
a warning in skb_try_coalesce()

It turns out iwl3945 has several problems :

1) skb->truesize is underestimated.
We really consume PAGE_SIZE bytes for a fragment,
not the frame length.
2) 128 bytes of initial headroom is a bit low and forces reallocations.
3) We can avoid consuming a full page for small enough frames.

Reported-by: Steinar H. Gunderson <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
---
Note : compiled only, I do not have this hardware.

drivers/net/wireless/iwlegacy/3945.c | 30 +++++++++++++++----------
1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index c092033..ad7294f 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -483,14 +483,13 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
- u16 len = le16_to_cpu(rx_hdr->len);
+ u32 len = le16_to_cpu(rx_hdr->len);
struct sk_buff *skb;
__le16 fc = hdr->frame_control;
+ u32 fraglen = PAGE_SIZE << il->hw_params.rx_page_order;

/* We received data from the HW, so stop the watchdog */
- if (unlikely
- (len + IL39_RX_FRAME_SIZE >
- PAGE_SIZE << il->hw_params.rx_page_order)) {
+ if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) {
D_DROP("Corruption detected!\n");
return;
}
@@ -506,26 +505,33 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
D_INFO("Woke queues - frame received on passive channel\n");
}

- skb = dev_alloc_skb(128);
+ skb = dev_alloc_skb(256);
if (!skb) {
IL_ERR("dev_alloc_skb failed\n");
return;
}

if (!il3945_mod_params.sw_crypto)
- il_set_decrypted_flag(il, (struct ieee80211_hdr *)rxb_addr(rxb),
+ il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt,
le32_to_cpu(rx_end->status), stats);

- skb_add_rx_frag(skb, 0, rxb->page,
- (void *)rx_hdr->payload - (void *)pkt, len,
- len);
-
+ /* If frame is small enough to fit into skb->head, copy it
+ * and do not consume a full page
+ */
+ if (len <= 256) {
+ skb_copy_to_linear_data(skb, rx_hdr->payload, len);
+ skb->tail += len;
+ } else {
+ skb_add_rx_frag(skb, 0, rxb->page,
+ (void *)rx_hdr->payload - (void *)pkt, len,
+ fraglen);
+ il->alloc_rxb_page--;
+ rxb->page = NULL;
+ }
il_update_stats(il, false, fc, len);
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));

ieee80211_rx(il->hw, skb);
- il->alloc_rxb_page--;
- rxb->page = NULL;
}

#define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)




2013-06-28 14:59:51

by Eric Dumazet

[permalink] [raw]
Subject: Re: [PATCH] iwl3945: better skb management in rx path

On Fri, 2013-06-28 at 07:50 -0700, Eric Dumazet wrote:
> From: Eric Dumazet <[email protected]>
>

> + if (len <= SMALL_PACKET_SIZE) {
> + skb_copy_to_linear_data(skb, rx_hdr->payload, len);
> + skb->tail += len;
> + } else {

Hmm I'll send a v3, we need a regular __skb_put() here



2013-06-28 14:50:19

by Eric Dumazet

[permalink] [raw]
Subject: Re: [PATCH] iwl3945: better skb management in rx path

From: Eric Dumazet <[email protected]>

On Fri, 2013-06-28 at 07:38 -0700, Paul Stewart wrote:

> Presumably this 256 is related to the "dev_alloc_skb(256)"? It might
> be worth making this a constant of some sort so they don't
> inadvertently drift apart in the future.

Hi Paul !

Well, I can do that, but the 128 was not a constant to begin with ;)

Thanks

[PATCH v2] iwl3945: better skb management in rx path

Steinar reported reallocations of skb->head with IPv6, leading to
a warning in skb_try_coalesce()

It turns out iwl3945 has several problems :

1) skb->truesize is underestimated.
We really consume PAGE_SIZE bytes for a fragment,
not the frame length.
2) 128 bytes of initial headroom is a bit low and forces reallocations.
3) We can avoid consuming a full page for small enough frames.

Reported-by: Steinar H. Gunderson <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
Cc: Paul Stewart <[email protected]>
---
v2: use a SMALL_PACKET_SIZE macro

drivers/net/wireless/iwlegacy/3945.c | 32 +++++++++++++++----------
1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index c092033..38e6be6 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -475,6 +475,8 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header)
}
}

+#define SMALL_PACKET_SIZE 256
+
static void
il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
struct ieee80211_rx_status *stats)
@@ -483,14 +485,13 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
- u16 len = le16_to_cpu(rx_hdr->len);
+ u32 len = le16_to_cpu(rx_hdr->len);
struct sk_buff *skb;
__le16 fc = hdr->frame_control;
+ u32 fraglen = PAGE_SIZE << il->hw_params.rx_page_order;

/* We received data from the HW, so stop the watchdog */
- if (unlikely
- (len + IL39_RX_FRAME_SIZE >
- PAGE_SIZE << il->hw_params.rx_page_order)) {
+ if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) {
D_DROP("Corruption detected!\n");
return;
}
@@ -506,26 +507,33 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
D_INFO("Woke queues - frame received on passive channel\n");
}

- skb = dev_alloc_skb(128);
+ skb = dev_alloc_skb(SMALL_PACKET_SIZE);
if (!skb) {
IL_ERR("dev_alloc_skb failed\n");
return;
}

if (!il3945_mod_params.sw_crypto)
- il_set_decrypted_flag(il, (struct ieee80211_hdr *)rxb_addr(rxb),
+ il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt,
le32_to_cpu(rx_end->status), stats);

- skb_add_rx_frag(skb, 0, rxb->page,
- (void *)rx_hdr->payload - (void *)pkt, len,
- len);
-
+ /* If frame is small enough to fit into skb->head, copy it
+ * and do not consume a full page
+ */
+ if (len <= SMALL_PACKET_SIZE) {
+ skb_copy_to_linear_data(skb, rx_hdr->payload, len);
+ skb->tail += len;
+ } else {
+ skb_add_rx_frag(skb, 0, rxb->page,
+ (void *)rx_hdr->payload - (void *)pkt, len,
+ fraglen);
+ il->alloc_rxb_page--;
+ rxb->page = NULL;
+ }
il_update_stats(il, false, fc, len);
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));

ieee80211_rx(il->hw, skb);
- il->alloc_rxb_page--;
- rxb->page = NULL;
}

#define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)



2013-06-28 14:38:58

by Paul Stewart

[permalink] [raw]
Subject: Re: [PATCH] iwl3945: better skb management in rx path

On Fri, Jun 28, 2013 at 5:03 AM, Eric Dumazet <[email protected]> wrote:
> From: Eric Dumazet <[email protected]>
>
> Steinar reported reallocations of skb->head with IPv6, leading to
> a warning in skb_try_coalesce()
>
> It turns out iwl3945 has several problems :
>
> 1) skb->truesize is underestimated.
> We really consume PAGE_SIZE bytes for a fragment,
> not the frame length.
> 2) 128 bytes of initial headroom is a bit low and forces reallocations.
> 3) We can avoid consuming a full page for small enough frames.
>
> Reported-by: Steinar H. Gunderson <[email protected]>
> Signed-off-by: Eric Dumazet <[email protected]>
> ---
> Note : compiled only, I do not have this hardware.
>
> drivers/net/wireless/iwlegacy/3945.c | 30 +++++++++++++++----------
> 1 file changed, 18 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
> index c092033..ad7294f 100644
> --- a/drivers/net/wireless/iwlegacy/3945.c
> +++ b/drivers/net/wireless/iwlegacy/3945.c
> @@ -483,14 +483,13 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
> struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
> struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
> struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
> - u16 len = le16_to_cpu(rx_hdr->len);
> + u32 len = le16_to_cpu(rx_hdr->len);
> struct sk_buff *skb;
> __le16 fc = hdr->frame_control;
> + u32 fraglen = PAGE_SIZE << il->hw_params.rx_page_order;
>
> /* We received data from the HW, so stop the watchdog */
> - if (unlikely
> - (len + IL39_RX_FRAME_SIZE >
> - PAGE_SIZE << il->hw_params.rx_page_order)) {
> + if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) {
> D_DROP("Corruption detected!\n");
> return;
> }
> @@ -506,26 +505,33 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
> D_INFO("Woke queues - frame received on passive channel\n");
> }
>
> - skb = dev_alloc_skb(128);
> + skb = dev_alloc_skb(256);
> if (!skb) {
> IL_ERR("dev_alloc_skb failed\n");
> return;
> }
>
> if (!il3945_mod_params.sw_crypto)
> - il_set_decrypted_flag(il, (struct ieee80211_hdr *)rxb_addr(rxb),
> + il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt,
> le32_to_cpu(rx_end->status), stats);
>
> - skb_add_rx_frag(skb, 0, rxb->page,
> - (void *)rx_hdr->payload - (void *)pkt, len,
> - len);
> -
> + /* If frame is small enough to fit into skb->head, copy it
> + * and do not consume a full page
> + */
> + if (len <= 256) {

Presumably this 256 is related to the "dev_alloc_skb(256)"? It might
be worth making this a constant of some sort so they don't
inadvertently drift apart in the future.

> + skb_copy_to_linear_data(skb, rx_hdr->payload, len);
> + skb->tail += len;
> + } else {
> + skb_add_rx_frag(skb, 0, rxb->page,
> + (void *)rx_hdr->payload - (void *)pkt, len,
> + fraglen);
> + il->alloc_rxb_page--;
> + rxb->page = NULL;
> + }
> il_update_stats(il, false, fc, len);
> memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
>
> ieee80211_rx(il->hw, skb);
> - il->alloc_rxb_page--;
> - rxb->page = NULL;
> }
>
> #define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2013-06-28 15:05:00

by Eric Dumazet

[permalink] [raw]
Subject: [PATCH v3] iwl3945: better skb management in rx path

From: Eric Dumazet <[email protected]>

Steinar reported reallocations of skb->head with IPv6, leading to
a warning in skb_try_coalesce()

It turns out iwl3945 has several problems :

1) skb->truesize is underestimated.
We really consume PAGE_SIZE bytes for a fragment,
not the frame length.
2) 128 bytes of initial headroom is a bit low and forces reallocations.
3) We can avoid consuming a full page for small enough frames.

Reported-by: Steinar H. Gunderson <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
Cc: Paul Stewart <[email protected]>
---
v3: use regular memcpy(skb_put(...),...)
v2: SMALL_PACKET_SIZE define

drivers/net/wireless/iwlegacy/3945.c | 31 +++++++++++++++----------
1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index c092033..f09e257 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -475,6 +475,8 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header)
}
}

+#define SMALL_PACKET_SIZE 256
+
static void
il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
struct ieee80211_rx_status *stats)
@@ -483,14 +485,13 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
- u16 len = le16_to_cpu(rx_hdr->len);
+ u32 len = le16_to_cpu(rx_hdr->len);
struct sk_buff *skb;
__le16 fc = hdr->frame_control;
+ u32 fraglen = PAGE_SIZE << il->hw_params.rx_page_order;

/* We received data from the HW, so stop the watchdog */
- if (unlikely
- (len + IL39_RX_FRAME_SIZE >
- PAGE_SIZE << il->hw_params.rx_page_order)) {
+ if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) {
D_DROP("Corruption detected!\n");
return;
}
@@ -506,26 +507,32 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
D_INFO("Woke queues - frame received on passive channel\n");
}

- skb = dev_alloc_skb(128);
+ skb = dev_alloc_skb(SMALL_PACKET_SIZE);
if (!skb) {
IL_ERR("dev_alloc_skb failed\n");
return;
}

if (!il3945_mod_params.sw_crypto)
- il_set_decrypted_flag(il, (struct ieee80211_hdr *)rxb_addr(rxb),
+ il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt,
le32_to_cpu(rx_end->status), stats);

- skb_add_rx_frag(skb, 0, rxb->page,
- (void *)rx_hdr->payload - (void *)pkt, len,
- len);
-
+ /* If frame is small enough to fit into skb->head, copy it
+ * and do not consume a full page
+ */
+ if (len <= SMALL_PACKET_SIZE) {
+ memcpy(skb_put(skb, len), rx_hdr->payload, len);
+ } else {
+ skb_add_rx_frag(skb, 0, rxb->page,
+ (void *)rx_hdr->payload - (void *)pkt, len,
+ fraglen);
+ il->alloc_rxb_page--;
+ rxb->page = NULL;
+ }
il_update_stats(il, false, fc, len);
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));

ieee80211_rx(il->hw, skb);
- il->alloc_rxb_page--;
- rxb->page = NULL;
}

#define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)



2013-06-28 23:05:03

by Steinar H. Gunderson

[permalink] [raw]
Subject: Re: [PATCH v3] iwl3945: better skb management in rx path

2013/6/28 Eric Dumazet <[email protected]>:
> Steinar reported reallocations of skb->head with IPv6, leading to
> a warning in skb_try_coalesce()
>
> It turns out iwl3945 has several problems :
>
> 1) skb->truesize is underestimated.
> We really consume PAGE_SIZE bytes for a fragment,
> not the frame length.
> 2) 128 bytes of initial headroom is a bit low and forces reallocations.
> 3) We can avoid consuming a full page for small enough frames.

I'm running 3.9.8 plus this patch (hand-applied since GMail mangled
it…), and so far, it seems to work fine. Well, network-manager still
doesn't like Cisco's band-select feature, so from time to time I get
network freezes while it's trying to roam from 5 GHz to 2.4 GHz, but
that's hardly iwl3945's fault.

/* Steinar */
--
Software Engineer, Google Switzerland

2013-07-01 12:13:24

by Stanislaw Gruszka

[permalink] [raw]
Subject: Re: [PATCH v3] iwl3945: better skb management in rx path

On Fri, Jun 28, 2013 at 08:05:06AM -0700, Eric Dumazet wrote:
> From: Eric Dumazet <[email protected]>
>
> Steinar reported reallocations of skb->head with IPv6, leading to
> a warning in skb_try_coalesce()
>
> It turns out iwl3945 has several problems :
>
> 1) skb->truesize is underestimated.
> We really consume PAGE_SIZE bytes for a fragment,
> not the frame length.
> 2) 128 bytes of initial headroom is a bit low and forces reallocations.
> 3) We can avoid consuming a full page for small enough frames.
>
> Reported-by: Steinar H. Gunderson <[email protected]>
> Signed-off-by: Eric Dumazet <[email protected]>
> Cc: Paul Stewart <[email protected]>

Acked-by: Stanislaw Gruszka <[email protected]>

FYI, I'll post 4965 version soon.