diff options
author | Arend van Spriel <arend@broadcom.com> | 2011-10-21 10:16:31 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-08 15:54:23 -0500 |
commit | 3fd172d30b59d9b73cb35ab263a1f0173dae974c (patch) | |
tree | 1d4af5d073bdb1dc62a4182544487f047bd106c2 /drivers/net/wireless/brcm80211 | |
parent | 81d2e2d148c2263f29a971d027f04c6e2c87e0d2 (diff) |
brcm80211: smac: use sk_buff list for handling frames in receive path
In the receive path the frames are obtained from the dma using
multiple sk_buff that were linked using the skb next pointer.
This has been changed and it now used sk_buff lists and skb_queue
functions instead.
Reported-by: Johannes Berg <johannes@sipsolutions.net>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Alwin Beukers <alwin@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/dma.c | 38 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/dma.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/main.c | 21 |
3 files changed, 32 insertions, 30 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 08960ce2ab78..ae541fbb4475 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c | |||
@@ -14,7 +14,6 @@ | |||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
19 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
20 | 19 | ||
@@ -901,7 +900,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall) | |||
901 | 900 | ||
902 | /* | 901 | /* |
903 | * !! rx entry routine | 902 | * !! rx entry routine |
904 | * returns a pointer to the next frame received, or NULL if there are no more | 903 | * returns the number packages in the next frame, or 0 if there are no more |
905 | * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is | 904 | * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is |
906 | * supported with pkts chain | 905 | * supported with pkts chain |
907 | * otherwise, it's treated as giant pkt and will be tossed. | 906 | * otherwise, it's treated as giant pkt and will be tossed. |
@@ -909,38 +908,40 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall) | |||
909 | * buffer data. After it reaches the max size of buffer, the data continues | 908 | * buffer data. After it reaches the max size of buffer, the data continues |
910 | * in next DMA descriptor buffer WITHOUT DMA header | 909 | * in next DMA descriptor buffer WITHOUT DMA header |
911 | */ | 910 | */ |
912 | struct sk_buff *dma_rx(struct dma_pub *pub) | 911 | int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) |
913 | { | 912 | { |
914 | struct dma_info *di = (struct dma_info *)pub; | 913 | struct dma_info *di = (struct dma_info *)pub; |
915 | struct sk_buff *p, *head, *tail; | 914 | struct sk_buff_head dma_frames; |
915 | struct sk_buff *p, *next; | ||
916 | uint len; | 916 | uint len; |
917 | uint pkt_len; | 917 | uint pkt_len; |
918 | int resid = 0; | 918 | int resid = 0; |
919 | int pktcnt = 1; | ||
919 | 920 | ||
921 | skb_queue_head_init(&dma_frames); | ||
920 | next_frame: | 922 | next_frame: |
921 | head = _dma_getnextrxp(di, false); | 923 | p = _dma_getnextrxp(di, false); |
922 | if (head == NULL) | 924 | if (p == NULL) |
923 | return NULL; | 925 | return 0; |
924 | 926 | ||
925 | len = le16_to_cpu(*(__le16 *) (head->data)); | 927 | len = le16_to_cpu(*(__le16 *) (p->data)); |
926 | DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); | 928 | DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); |
927 | dma_spin_for_len(len, head); | 929 | dma_spin_for_len(len, p); |
928 | 930 | ||
929 | /* set actual length */ | 931 | /* set actual length */ |
930 | pkt_len = min((di->rxoffset + len), di->rxbufsize); | 932 | pkt_len = min((di->rxoffset + len), di->rxbufsize); |
931 | __skb_trim(head, pkt_len); | 933 | __skb_trim(p, pkt_len); |
934 | skb_queue_tail(&dma_frames, p); | ||
932 | resid = len - (di->rxbufsize - di->rxoffset); | 935 | resid = len - (di->rxbufsize - di->rxoffset); |
933 | 936 | ||
934 | /* check for single or multi-buffer rx */ | 937 | /* check for single or multi-buffer rx */ |
935 | if (resid > 0) { | 938 | if (resid > 0) { |
936 | tail = head; | ||
937 | while ((resid > 0) && (p = _dma_getnextrxp(di, false))) { | 939 | while ((resid > 0) && (p = _dma_getnextrxp(di, false))) { |
938 | tail->next = p; | ||
939 | pkt_len = min_t(uint, resid, di->rxbufsize); | 940 | pkt_len = min_t(uint, resid, di->rxbufsize); |
940 | __skb_trim(p, pkt_len); | 941 | __skb_trim(p, pkt_len); |
941 | 942 | skb_queue_tail(&dma_frames, p); | |
942 | tail = p; | ||
943 | resid -= di->rxbufsize; | 943 | resid -= di->rxbufsize; |
944 | pktcnt++; | ||
944 | } | 945 | } |
945 | 946 | ||
946 | #ifdef BCMDBG | 947 | #ifdef BCMDBG |
@@ -959,13 +960,18 @@ struct sk_buff *dma_rx(struct dma_pub *pub) | |||
959 | if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { | 960 | if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { |
960 | DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", | 961 | DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", |
961 | di->name, len)); | 962 | di->name, len)); |
962 | brcmu_pkt_buf_free_skb(head); | 963 | skb_queue_walk_safe(&dma_frames, p, next) { |
964 | skb_unlink(p, &dma_frames); | ||
965 | brcmu_pkt_buf_free_skb(p); | ||
966 | } | ||
963 | di->dma.rxgiants++; | 967 | di->dma.rxgiants++; |
968 | pktcnt = 1; | ||
964 | goto next_frame; | 969 | goto next_frame; |
965 | } | 970 | } |
966 | } | 971 | } |
967 | 972 | ||
968 | return head; | 973 | skb_queue_splice_tail(&dma_frames, skb_list); |
974 | return pktcnt; | ||
969 | } | 975 | } |
970 | 976 | ||
971 | static bool dma64_rxidle(struct dma_info *di) | 977 | static bool dma64_rxidle(struct dma_info *di) |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/brcm80211/brcmsmac/dma.h index ebc5bc546f3b..d317c7c12f91 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #define _BRCM_DMA_H_ | 18 | #define _BRCM_DMA_H_ |
19 | 19 | ||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/skbuff.h> | ||
21 | #include "types.h" /* forward structure declarations */ | 22 | #include "types.h" /* forward structure declarations */ |
22 | 23 | ||
23 | /* map/unmap direction */ | 24 | /* map/unmap direction */ |
@@ -80,7 +81,7 @@ extern struct dma_pub *dma_attach(char *name, struct si_pub *sih, | |||
80 | uint nrxpost, uint rxoffset, uint *msg_level); | 81 | uint nrxpost, uint rxoffset, uint *msg_level); |
81 | 82 | ||
82 | void dma_rxinit(struct dma_pub *pub); | 83 | void dma_rxinit(struct dma_pub *pub); |
83 | struct sk_buff *dma_rx(struct dma_pub *pub); | 84 | int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list); |
84 | bool dma_rxfill(struct dma_pub *pub); | 85 | bool dma_rxfill(struct dma_pub *pub); |
85 | bool dma_rxreset(struct dma_pub *pub); | 86 | bool dma_rxreset(struct dma_pub *pub); |
86 | bool dma_txreset(struct dma_pub *pub); | 87 | bool dma_txreset(struct dma_pub *pub); |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 3f8a6c7d7a23..f193fab675dc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c | |||
@@ -8115,21 +8115,17 @@ static bool | |||
8115 | brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) | 8115 | brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) |
8116 | { | 8116 | { |
8117 | struct sk_buff *p; | 8117 | struct sk_buff *p; |
8118 | struct sk_buff *head = NULL; | 8118 | struct sk_buff *next = NULL; |
8119 | struct sk_buff *tail = NULL; | 8119 | struct sk_buff_head recv_frames; |
8120 | |||
8120 | uint n = 0; | 8121 | uint n = 0; |
8121 | uint bound_limit = bound ? RXBND : -1; | 8122 | uint bound_limit = bound ? RXBND : -1; |
8122 | 8123 | ||
8123 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); | 8124 | BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); |
8124 | /* gather received frames */ | 8125 | skb_queue_head_init(&recv_frames); |
8125 | while ((p = dma_rx(wlc_hw->di[fifo]))) { | ||
8126 | 8126 | ||
8127 | if (!tail) | 8127 | /* gather received frames */ |
8128 | head = tail = p; | 8128 | while (dma_rx(wlc_hw->di[fifo], &recv_frames)) { |
8129 | else { | ||
8130 | tail->prev = p; | ||
8131 | tail = p; | ||
8132 | } | ||
8133 | 8129 | ||
8134 | /* !give others some time to run! */ | 8130 | /* !give others some time to run! */ |
8135 | if (++n >= bound_limit) | 8131 | if (++n >= bound_limit) |
@@ -8140,12 +8136,11 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) | |||
8140 | dma_rxfill(wlc_hw->di[fifo]); | 8136 | dma_rxfill(wlc_hw->di[fifo]); |
8141 | 8137 | ||
8142 | /* process each frame */ | 8138 | /* process each frame */ |
8143 | while ((p = head) != NULL) { | 8139 | skb_queue_walk_safe(&recv_frames, p, next) { |
8144 | struct d11rxhdr_le *rxh_le; | 8140 | struct d11rxhdr_le *rxh_le; |
8145 | struct d11rxhdr *rxh; | 8141 | struct d11rxhdr *rxh; |
8146 | head = head->prev; | ||
8147 | p->prev = NULL; | ||
8148 | 8142 | ||
8143 | skb_unlink(p, &recv_frames); | ||
8149 | rxh_le = (struct d11rxhdr_le *)p->data; | 8144 | rxh_le = (struct d11rxhdr_le *)p->data; |
8150 | rxh = (struct d11rxhdr *)p->data; | 8145 | rxh = (struct d11rxhdr *)p->data; |
8151 | 8146 | ||