aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2014-07-30 07:20:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-07-31 13:45:26 -0400
commit9a1bb60250d2b6b546a62e5b73f55c4f1d22016b (patch)
tree7aae569da33de35db22e3f455382540be3da4b5c
parent8851cce085dce026f14e9fc525acc71e4c9d305b (diff)
brcmfmac: Adding msgbuf protocol.
This patch will add the msgbuf protocol. This protocol is used by the soon to be added new bus interface PCIe. Msgbuf is a protocol where most data is and remains located on the host (driver) side and transferred by DMA from and to device. Msgbuf is the protocol which takes care of the signalling of the buffers between host and device which identifies this DMA-able data. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.c273
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.h69
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h35
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.c362
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.h74
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c1387
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h40
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/proto.c21
10 files changed, 2275 insertions, 21 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 14e8a8d33520..0447a47fe237 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -31,6 +31,9 @@ brcmfmac-objs += \
31 p2p.o \ 31 p2p.o \
32 proto.o \ 32 proto.o \
33 bcdc.o \ 33 bcdc.o \
34 commonring.o \
35 flowring.o \
36 msgbuf.o \
34 dhd_common.o \ 37 dhd_common.o \
35 dhd_linux.o \ 38 dhd_linux.o \
36 firmware.o \ 39 firmware.o \
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
new file mode 100644
index 000000000000..c6d65b8e1e15
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
@@ -0,0 +1,273 @@
1/* Copyright (c) 2014 Broadcom Corporation
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16#include <linux/types.h>
17#include <linux/netdevice.h>
18
19#include <brcmu_utils.h>
20#include <brcmu_wifi.h>
21
22#include "dhd.h"
23#include "commonring.h"
24
25
26/* dma flushing needs implementation for mips and arm platforms. Should
27 * be put in util. Note, this is not real flushing. It is virtual non
28 * cached memory. Only write buffers should have to be drained. Though
29 * this may be different depending on platform......
30 * SEE ALSO msgbuf.c
31 */
32#define brcmf_dma_flush(addr, len)
33#define brcmf_dma_invalidate_cache(addr, len)
34
35
36void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
37 int (*cr_ring_bell)(void *ctx),
38 int (*cr_update_rptr)(void *ctx),
39 int (*cr_update_wptr)(void *ctx),
40 int (*cr_write_rptr)(void *ctx),
41 int (*cr_write_wptr)(void *ctx), void *ctx)
42{
43 commonring->cr_ring_bell = cr_ring_bell;
44 commonring->cr_update_rptr = cr_update_rptr;
45 commonring->cr_update_wptr = cr_update_wptr;
46 commonring->cr_write_rptr = cr_write_rptr;
47 commonring->cr_write_wptr = cr_write_wptr;
48 commonring->cr_ctx = ctx;
49}
50
51
52void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,
53 u16 item_len, void *buf_addr)
54{
55 commonring->depth = depth;
56 commonring->item_len = item_len;
57 commonring->buf_addr = buf_addr;
58 if (!commonring->inited) {
59 spin_lock_init(&commonring->lock);
60 commonring->inited = true;
61 }
62 commonring->r_ptr = 0;
63 if (commonring->cr_write_rptr)
64 commonring->cr_write_rptr(commonring->cr_ctx);
65 commonring->w_ptr = 0;
66 if (commonring->cr_write_wptr)
67 commonring->cr_write_wptr(commonring->cr_ctx);
68 commonring->f_ptr = 0;
69}
70
71
72void brcmf_commonring_lock(struct brcmf_commonring *commonring)
73 __acquires(&commonring->lock)
74{
75 unsigned long flags;
76
77 spin_lock_irqsave(&commonring->lock, flags);
78 commonring->flags = flags;
79}
80
81
82void brcmf_commonring_unlock(struct brcmf_commonring *commonring)
83 __releases(&commonring->lock)
84{
85 spin_unlock_irqrestore(&commonring->lock, commonring->flags);
86}
87
88
89bool brcmf_commonring_write_available(struct brcmf_commonring *commonring)
90{
91 u16 available;
92 bool retry = true;
93
94again:
95 if (commonring->r_ptr <= commonring->w_ptr)
96 available = commonring->depth - commonring->w_ptr +
97 commonring->r_ptr;
98 else
99 available = commonring->r_ptr - commonring->w_ptr;
100
101 if (available > 1) {
102 if (!commonring->was_full)
103 return true;
104 if (available > commonring->depth / 8) {
105 commonring->was_full = false;
106 return true;
107 }
108 if (retry) {
109 if (commonring->cr_update_rptr)
110 commonring->cr_update_rptr(commonring->cr_ctx);
111 retry = false;
112 goto again;
113 }
114 return false;
115 }
116
117 if (retry) {
118 if (commonring->cr_update_rptr)
119 commonring->cr_update_rptr(commonring->cr_ctx);
120 retry = false;
121 goto again;
122 }
123
124 commonring->was_full = true;
125 return false;
126}
127
128
129void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring)
130{
131 void *ret_ptr;
132 u16 available;
133 bool retry = true;
134
135again:
136 if (commonring->r_ptr <= commonring->w_ptr)
137 available = commonring->depth - commonring->w_ptr +
138 commonring->r_ptr;
139 else
140 available = commonring->r_ptr - commonring->w_ptr;
141
142 if (available > 1) {
143 ret_ptr = commonring->buf_addr +
144 (commonring->w_ptr * commonring->item_len);
145 commonring->w_ptr++;
146 if (commonring->w_ptr == commonring->depth)
147 commonring->w_ptr = 0;
148 return ret_ptr;
149 }
150
151 if (retry) {
152 if (commonring->cr_update_rptr)
153 commonring->cr_update_rptr(commonring->cr_ctx);
154 retry = false;
155 goto again;
156 }
157
158 commonring->was_full = true;
159 return NULL;
160}
161
162
163void *
164brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,
165 u16 n_items, u16 *alloced)
166{
167 void *ret_ptr;
168 u16 available;
169 bool retry = true;
170
171again:
172 if (commonring->r_ptr <= commonring->w_ptr)
173 available = commonring->depth - commonring->w_ptr +
174 commonring->r_ptr;
175 else
176 available = commonring->r_ptr - commonring->w_ptr;
177
178 if (available > 1) {
179 ret_ptr = commonring->buf_addr +
180 (commonring->w_ptr * commonring->item_len);
181 *alloced = min_t(u16, n_items, available - 1);
182 if (*alloced + commonring->w_ptr > commonring->depth)
183 *alloced = commonring->depth - commonring->w_ptr;
184 commonring->w_ptr += *alloced;
185 if (commonring->w_ptr == commonring->depth)
186 commonring->w_ptr = 0;
187 return ret_ptr;
188 }
189
190 if (retry) {
191 if (commonring->cr_update_rptr)
192 commonring->cr_update_rptr(commonring->cr_ctx);
193 retry = false;
194 goto again;
195 }
196
197 commonring->was_full = true;
198 return NULL;
199}
200
201
202int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)
203{
204 void *address;
205
206 address = commonring->buf_addr;
207 address += (commonring->f_ptr * commonring->item_len);
208 if (commonring->f_ptr > commonring->w_ptr) {
209 brcmf_dma_flush(address,
210 (commonring->depth - commonring->f_ptr) *
211 commonring->item_len);
212 address = commonring->buf_addr;
213 commonring->f_ptr = 0;
214 }
215 brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) *
216 commonring->item_len);
217
218 commonring->f_ptr = commonring->w_ptr;
219
220 if (commonring->cr_write_wptr)
221 commonring->cr_write_wptr(commonring->cr_ctx);
222 if (commonring->cr_ring_bell)
223 return commonring->cr_ring_bell(commonring->cr_ctx);
224
225 return -EIO;
226}
227
228
229void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
230 u16 n_items)
231{
232 if (commonring->w_ptr == 0)
233 commonring->w_ptr = commonring->depth - n_items;
234 else
235 commonring->w_ptr -= n_items;
236}
237
238
239void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
240 u16 *n_items)
241{
242 void *ret_addr;
243
244 if (commonring->cr_update_wptr)
245 commonring->cr_update_wptr(commonring->cr_ctx);
246
247 *n_items = (commonring->w_ptr >= commonring->r_ptr) ?
248 (commonring->w_ptr - commonring->r_ptr) :
249 (commonring->depth - commonring->r_ptr);
250
251 if (*n_items == 0)
252 return NULL;
253
254 ret_addr = commonring->buf_addr +
255 (commonring->r_ptr * commonring->item_len);
256
257 commonring->r_ptr += *n_items;
258 if (commonring->r_ptr == commonring->depth)
259 commonring->r_ptr = 0;
260
261 brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len);
262
263 return ret_addr;
264}
265
266
267int brcmf_commonring_read_complete(struct brcmf_commonring *commonring)
268{
269 if (commonring->cr_write_rptr)
270 return commonring->cr_write_rptr(commonring->cr_ctx);
271
272 return -EIO;
273}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
new file mode 100644
index 000000000000..002336e35764
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
@@ -0,0 +1,69 @@
1/* Copyright (c) 2014 Broadcom Corporation
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15#ifndef BRCMFMAC_COMMONRING_H
16#define BRCMFMAC_COMMONRING_H
17
18
19struct brcmf_commonring {
20 u16 r_ptr;
21 u16 w_ptr;
22 u16 f_ptr;
23 u16 depth;
24 u16 item_len;
25
26 void *buf_addr;
27
28 int (*cr_ring_bell)(void *ctx);
29 int (*cr_update_rptr)(void *ctx);
30 int (*cr_update_wptr)(void *ctx);
31 int (*cr_write_rptr)(void *ctx);
32 int (*cr_write_wptr)(void *ctx);
33
34 void *cr_ctx;
35
36 spinlock_t lock;
37 unsigned long flags;
38 bool inited;
39 bool was_full;
40};
41
42
43void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
44 int (*cr_ring_bell)(void *ctx),
45 int (*cr_update_rptr)(void *ctx),
46 int (*cr_update_wptr)(void *ctx),
47 int (*cr_write_rptr)(void *ctx),
48 int (*cr_write_wptr)(void *ctx), void *ctx);
49void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,
50 u16 item_len, void *buf_addr);
51void brcmf_commonring_lock(struct brcmf_commonring *commonring);
52void brcmf_commonring_unlock(struct brcmf_commonring *commonring);
53bool brcmf_commonring_write_available(struct brcmf_commonring *commonring);
54void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring);
55void *
56brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,
57 u16 n_items, u16 *alloced);
58int brcmf_commonring_write_complete(struct brcmf_commonring *commonring);
59void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
60 u16 n_items);
61void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
62 u16 *n_items);
63int brcmf_commonring_read_complete(struct brcmf_commonring *commonring);
64
65#define brcmf_commonring_n_items(commonring) (commonring->depth)
66#define brcmf_commonring_len_item(commonring) (commonring->item_len)
67
68
69#endif /* BRCMFMAC_COMMONRING_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index 7735328fff21..4053368eb743 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -19,6 +19,18 @@
19 19
20#include "dhd_dbg.h" 20#include "dhd_dbg.h"
21 21
22/* IDs of the 6 default common rings of msgbuf protocol */
23#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0
24#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1
25#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2
26#define BRCMF_D2H_MSGRING_TX_COMPLETE 3
27#define BRCMF_D2H_MSGRING_RX_COMPLETE 4
28
29#define BRCMF_NROF_H2D_COMMON_MSGRINGS 2
30#define BRCMF_NROF_D2H_COMMON_MSGRINGS 3
31#define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \
32 BRCMF_NROF_D2H_COMMON_MSGRINGS)
33
22/* The level of bus communication with the dongle */ 34/* The level of bus communication with the dongle */
23enum brcmf_bus_state { 35enum brcmf_bus_state {
24 BRCMF_BUS_UNKNOWN, /* Not determined yet */ 36 BRCMF_BUS_UNKNOWN, /* Not determined yet */
@@ -70,6 +82,25 @@ struct brcmf_bus_ops {
70 struct pktq * (*gettxq)(struct device *dev); 82 struct pktq * (*gettxq)(struct device *dev);
71}; 83};
72 84
85
86/**
87 * struct brcmf_bus_msgbuf - bus ringbuf if in case of msgbuf.
88 *
89 * @commonrings: commonrings which are always there.
90 * @flowrings: commonrings which are dynamically created and destroyed for data.
91 * @rx_dataoffset: if set then all rx data has this this offset.
92 * @max_rxbufpost: maximum number of buffers to post for rx.
93 * @nrof_flowrings: number of flowrings.
94 */
95struct brcmf_bus_msgbuf {
96 struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS];
97 struct brcmf_commonring **flowrings;
98 u32 rx_dataoffset;
99 u32 max_rxbufpost;
100 u32 nrof_flowrings;
101};
102
103
73/** 104/**
74 * struct brcmf_bus - interface structure between common and bus layer 105 * struct brcmf_bus - interface structure between common and bus layer
75 * 106 *
@@ -101,6 +132,7 @@ struct brcmf_bus {
101 bool always_use_fws_queue; 132 bool always_use_fws_queue;
102 133
103 struct brcmf_bus_ops *ops; 134 struct brcmf_bus_ops *ops;
135 struct brcmf_bus_msgbuf *msgbuf;
104}; 136};
105 137
106/* 138/*
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index 6eade7c60c63..6804eeca7688 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -18,23 +18,24 @@
18#define _BRCMF_DBG_H_ 18#define _BRCMF_DBG_H_
19 19
20/* message levels */ 20/* message levels */
21#define BRCMF_TRACE_VAL 0x00000002 21#define BRCMF_TRACE_VAL 0x00000002
22#define BRCMF_INFO_VAL 0x00000004 22#define BRCMF_INFO_VAL 0x00000004
23#define BRCMF_DATA_VAL 0x00000008 23#define BRCMF_DATA_VAL 0x00000008
24#define BRCMF_CTL_VAL 0x00000010 24#define BRCMF_CTL_VAL 0x00000010
25#define BRCMF_TIMER_VAL 0x00000020 25#define BRCMF_TIMER_VAL 0x00000020
26#define BRCMF_HDRS_VAL 0x00000040 26#define BRCMF_HDRS_VAL 0x00000040
27#define BRCMF_BYTES_VAL 0x00000080 27#define BRCMF_BYTES_VAL 0x00000080
28#define BRCMF_INTR_VAL 0x00000100 28#define BRCMF_INTR_VAL 0x00000100
29#define BRCMF_GLOM_VAL 0x00000200 29#define BRCMF_GLOM_VAL 0x00000200
30#define BRCMF_EVENT_VAL 0x00000400 30#define BRCMF_EVENT_VAL 0x00000400
31#define BRCMF_BTA_VAL 0x00000800 31#define BRCMF_BTA_VAL 0x00000800
32#define BRCMF_FIL_VAL 0x00001000 32#define BRCMF_FIL_VAL 0x00001000
33#define BRCMF_USB_VAL 0x00002000 33#define BRCMF_USB_VAL 0x00002000
34#define BRCMF_SCAN_VAL 0x00004000 34#define BRCMF_SCAN_VAL 0x00004000
35#define BRCMF_CONN_VAL 0x00008000 35#define BRCMF_CONN_VAL 0x00008000
36#define BRCMF_BCDC_VAL 0x00010000 36#define BRCMF_BCDC_VAL 0x00010000
37#define BRCMF_SDIO_VAL 0x00020000 37#define BRCMF_SDIO_VAL 0x00020000
38#define BRCMF_MSGBUF_VAL 0x00040000
38 39
39/* set default print format */ 40/* set default print format */
40#undef pr_fmt 41#undef pr_fmt
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
new file mode 100644
index 000000000000..26cbb7c4ec4c
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -0,0 +1,362 @@
1/* Copyright (c) 2014 Broadcom Corporation
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16
17#include <linux/types.h>
18#include <linux/netdevice.h>
19#include <linux/etherdevice.h>
20#include <brcmu_utils.h>
21
22#include "dhd.h"
23#include "dhd_dbg.h"
24#include "dhd_bus.h"
25#include "proto.h"
26#include "flowring.h"
27#include "msgbuf.h"
28
29
30#define BRCMF_FLOWRING_HIGH 1024
31#define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
32#define BRCMF_FLOWRING_INVALID_IFIDX 0xff
33
34#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
35#define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
36
37static const u8 ALLZEROMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
38static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
39
40static const u8 brcmf_flowring_prio2fifo[] = {
41 1,
42 0,
43 0,
44 1,
45 2,
46 2,
47 3,
48 3
49};
50
51
52u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
53 u8 prio, u8 ifidx)
54{
55 struct brcmf_flowring_hash *hash;
56 u8 hash_idx;
57 u32 i;
58 bool found;
59 bool sta;
60 u8 fifo;
61 u8 *mac;
62
63 fifo = brcmf_flowring_prio2fifo[prio];
64 sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
65 mac = da;
66 if ((!sta) && (is_multicast_ether_addr(da))) {
67 mac = (u8 *)ALLFFMAC;
68 fifo = 0;
69 }
70 hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
71 BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
72 found = false;
73 hash = flow->hash;
74 for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
75 if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) &&
76 (hash[hash_idx].fifo == fifo) &&
77 (hash[hash_idx].ifidx == ifidx)) {
78 found = true;
79 break;
80 }
81 hash_idx++;
82 }
83 if (found)
84 return hash[hash_idx].flowid;
85
86 return BRCMF_FLOWRING_INVALID_ID;
87}
88
89
90u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
91 u8 prio, u8 ifidx)
92{
93 struct brcmf_flowring_ring *ring;
94 struct brcmf_flowring_hash *hash;
95 u8 hash_idx;
96 u32 i;
97 bool found;
98 u8 fifo;
99 bool sta;
100 u8 *mac;
101
102 fifo = brcmf_flowring_prio2fifo[prio];
103 sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
104 mac = da;
105 if ((!sta) && (is_multicast_ether_addr(da))) {
106 mac = (u8 *)ALLFFMAC;
107 fifo = 0;
108 }
109 hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
110 BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
111 found = false;
112 hash = flow->hash;
113 for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
114 if (((sta) &&
115 (hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX)) ||
116 ((!sta) &&
117 (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0))) {
118 found = true;
119 break;
120 }
121 hash_idx++;
122 }
123 if (found) {
124 for (i = 0; i < flow->nrofrings; i++) {
125 if (flow->rings[i] == NULL)
126 break;
127 }
128 if (i == flow->nrofrings)
129 return -ENOMEM;
130
131 ring = kzalloc(sizeof(*ring), GFP_ATOMIC);
132 if (!ring)
133 return -ENOMEM;
134
135 memcpy(hash[hash_idx].mac, mac, ETH_ALEN);
136 hash[hash_idx].fifo = fifo;
137 hash[hash_idx].ifidx = ifidx;
138 hash[hash_idx].flowid = i;
139
140 ring->hash_id = hash_idx;
141 ring->status = RING_CLOSED;
142 skb_queue_head_init(&ring->skblist);
143 flow->rings[i] = ring;
144
145 return i;
146 }
147 return BRCMF_FLOWRING_INVALID_ID;
148}
149
150
151u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
152{
153 struct brcmf_flowring_ring *ring;
154
155 ring = flow->rings[flowid];
156
157 return flow->hash[ring->hash_id].fifo;
158}
159
160
161void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
162{
163 struct brcmf_flowring_ring *ring;
164 u8 hash_idx;
165 struct sk_buff *skb;
166
167 ring = flow->rings[flowid];
168 if (!ring)
169 return;
170 hash_idx = ring->hash_id;
171 flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
172 memset(flow->hash[hash_idx].mac, 0, ETH_ALEN);
173 flow->rings[flowid] = NULL;
174
175 skb = skb_dequeue(&ring->skblist);
176 while (skb) {
177 brcmu_pkt_buf_free_skb(skb);
178 skb = skb_dequeue(&ring->skblist);
179 }
180
181 kfree(ring);
182}
183
184
185void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
186 struct sk_buff *skb)
187{
188 struct brcmf_flowring_ring *ring;
189
190 ring = flow->rings[flowid];
191
192 skb_queue_tail(&ring->skblist, skb);
193
194 if (!ring->blocked &&
195 (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
196 brcmf_txflowblock(flow->dev, true);
197 brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
198 ring->blocked = 1;
199 }
200}
201
202
203struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
204{
205 struct brcmf_flowring_ring *ring;
206 struct sk_buff *skb;
207
208 ring = flow->rings[flowid];
209 if (ring->status != RING_OPEN)
210 return NULL;
211
212 skb = skb_dequeue(&ring->skblist);
213
214 if (ring->blocked &&
215 (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
216 brcmf_txflowblock(flow->dev, false);
217 brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
218 ring->blocked = 0;
219 }
220
221 return skb;
222}
223
224
225void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
226 struct sk_buff *skb)
227{
228 struct brcmf_flowring_ring *ring;
229
230 ring = flow->rings[flowid];
231
232 skb_queue_head(&ring->skblist, skb);
233}
234
235
236u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
237{
238 struct brcmf_flowring_ring *ring;
239
240 ring = flow->rings[flowid];
241 if (!ring)
242 return 0;
243
244 if (ring->status != RING_OPEN)
245 return 0;
246
247 return skb_queue_len(&ring->skblist);
248}
249
250
251void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
252{
253 struct brcmf_flowring_ring *ring;
254
255 ring = flow->rings[flowid];
256 if (!ring) {
257 brcmf_err("Ring NULL, for flowid %d\n", flowid);
258 return;
259 }
260
261 ring->status = RING_OPEN;
262}
263
264
265u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid)
266{
267 struct brcmf_flowring_ring *ring;
268 u8 hash_idx;
269
270 ring = flow->rings[flowid];
271 hash_idx = ring->hash_id;
272
273 return flow->hash[hash_idx].ifidx;
274}
275
276
277struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
278{
279 struct brcmf_flowring *flow;
280 u32 i;
281
282 flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
283 if (flow) {
284 flow->dev = dev;
285 flow->nrofrings = nrofrings;
286 for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
287 flow->addr_mode[i] = ADDR_INDIRECT;
288 for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
289 flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
290 flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
291 GFP_ATOMIC);
292 if (!flow->rings) {
293 kfree(flow);
294 flow = NULL;
295 }
296 }
297
298 return flow;
299}
300
301
302void brcmf_flowring_detach(struct brcmf_flowring *flow)
303{
304 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
305 struct brcmf_pub *drvr = bus_if->drvr;
306 u8 flowid;
307
308 for (flowid = 0; flowid < flow->nrofrings; flowid++) {
309 if (flow->rings[flowid])
310 brcmf_msgbuf_delete_flowring(drvr, flowid);
311 }
312 kfree(flow->rings);
313 kfree(flow);
314}
315
316
317void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
318 enum proto_addr_mode addr_mode)
319{
320 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
321 struct brcmf_pub *drvr = bus_if->drvr;
322 u32 i;
323 u8 flowid;
324
325 if (flow->addr_mode[ifidx] != addr_mode) {
326 for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
327 if (flow->hash[i].ifidx == ifidx) {
328 flowid = flow->hash[i].flowid;
329 if (flow->rings[flowid]->status != RING_OPEN)
330 continue;
331 flow->rings[flowid]->status = RING_CLOSING;
332 brcmf_msgbuf_delete_flowring(drvr, flowid);
333 }
334 }
335 flow->addr_mode[ifidx] = addr_mode;
336 }
337}
338
339
340void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
341 u8 peer[ETH_ALEN])
342{
343 struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
344 struct brcmf_pub *drvr = bus_if->drvr;
345 struct brcmf_flowring_hash *hash;
346 u32 i;
347 u8 flowid;
348 bool sta;
349
350 sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
351 hash = flow->hash;
352 for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
353 if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
354 (hash[i].ifidx == ifidx)) {
355 flowid = flow->hash[i].flowid;
356 if (flow->rings[flowid]->status == RING_OPEN) {
357 flow->rings[flowid]->status = RING_CLOSING;
358 brcmf_msgbuf_delete_flowring(drvr, flowid);
359 }
360 }
361 }
362}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
new file mode 100644
index 000000000000..677f4b8065f6
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
@@ -0,0 +1,74 @@
1/* Copyright (c) 2014 Broadcom Corporation
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15#ifndef BRCMFMAC_FLOWRING_H
16#define BRCMFMAC_FLOWRING_H
17
18
19#define BRCMF_FLOWRING_HASHSIZE 256
20#define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF
21
22
23struct brcmf_flowring_hash {
24 u8 mac[ETH_ALEN];
25 u8 fifo;
26 u8 ifidx;
27 u8 flowid;
28};
29
30enum ring_status {
31 RING_CLOSED,
32 RING_CLOSING,
33 RING_OPEN
34};
35
36struct brcmf_flowring_ring {
37 u8 hash_id;
38 u8 blocked;
39 enum ring_status status;
40 struct sk_buff_head skblist;
41};
42
43struct brcmf_flowring {
44 struct device *dev;
45 struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];
46 struct brcmf_flowring_ring **rings;
47 enum proto_addr_mode addr_mode[BRCMF_MAX_IFS];
48 u16 nrofrings;
49};
50
51
52u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
53 u8 prio, u8 ifidx);
54u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
55 u8 prio, u8 ifidx);
56void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
57void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
58u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
59void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
60 struct sk_buff *skb);
61struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
62void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
63 struct sk_buff *skb);
64u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid);
65u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid);
66struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);
67void brcmf_flowring_detach(struct brcmf_flowring *flow);
68void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
69 enum proto_addr_mode addr_mode);
70void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
71 u8 peer[ETH_ALEN]);
72
73
74#endif /* BRCMFMAC_FLOWRING_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
new file mode 100644
index 000000000000..c7a1c59ba6c3
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -0,0 +1,1387 @@
1/* Copyright (c) 2014 Broadcom Corporation
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16/*******************************************************************************
17 * Communicates with the dongle by using dcmd codes.
18 * For certain dcmd codes, the dongle interprets string data from the host.
19 ******************************************************************************/
20
21#include <linux/types.h>
22#include <linux/netdevice.h>
23
24#include <brcmu_utils.h>
25#include <brcmu_wifi.h>
26
27#include "dhd.h"
28#include "dhd_dbg.h"
29#include "proto.h"
30#include "msgbuf.h"
31#include "commonring.h"
32#include "flowring.h"
33#include "dhd_bus.h"
34#include "tracepoint.h"
35
36
37#define MSGBUF_IOCTL_RESP_TIMEOUT 2000
38
39#define MSGBUF_TYPE_GEN_STATUS 0x1
40#define MSGBUF_TYPE_RING_STATUS 0x2
41#define MSGBUF_TYPE_FLOW_RING_CREATE 0x3
42#define MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT 0x4
43#define MSGBUF_TYPE_FLOW_RING_DELETE 0x5
44#define MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT 0x6
45#define MSGBUF_TYPE_FLOW_RING_FLUSH 0x7
46#define MSGBUF_TYPE_FLOW_RING_FLUSH_CMPLT 0x8
47#define MSGBUF_TYPE_IOCTLPTR_REQ 0x9
48#define MSGBUF_TYPE_IOCTLPTR_REQ_ACK 0xA
49#define MSGBUF_TYPE_IOCTLRESP_BUF_POST 0xB
50#define MSGBUF_TYPE_IOCTL_CMPLT 0xC
51#define MSGBUF_TYPE_EVENT_BUF_POST 0xD
52#define MSGBUF_TYPE_WL_EVENT 0xE
53#define MSGBUF_TYPE_TX_POST 0xF
54#define MSGBUF_TYPE_TX_STATUS 0x10
55#define MSGBUF_TYPE_RXBUF_POST 0x11
56#define MSGBUF_TYPE_RX_CMPLT 0x12
57#define MSGBUF_TYPE_LPBK_DMAXFER 0x13
58#define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT 0x14
59
60#define NR_TX_PKTIDS 2048
61#define NR_RX_PKTIDS 1024
62
63#define BRCMF_IOCTL_REQ_PKTID 0xFFFE
64
65#define BRCMF_MSGBUF_MAX_PKT_SIZE 2048
66#define BRCMF_MSGBUF_RXBUFPOST_THRESHOLD 32
67#define BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST 8
68#define BRCMF_MSGBUF_MAX_EVENTBUF_POST 8
69
70#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3 0x01
71#define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT 5
72
73#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32
74#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96
75
76
77struct msgbuf_common_hdr {
78 u8 msgtype;
79 u8 ifidx;
80 u8 flags;
81 u8 rsvd0;
82 __le32 request_id;
83};
84
85struct msgbuf_buf_addr {
86 __le32 low_addr;
87 __le32 high_addr;
88};
89
90struct msgbuf_ioctl_req_hdr {
91 struct msgbuf_common_hdr msg;
92 __le32 cmd;
93 __le16 trans_id;
94 __le16 input_buf_len;
95 __le16 output_buf_len;
96 __le16 rsvd0[3];
97 struct msgbuf_buf_addr req_buf_addr;
98 __le32 rsvd1[2];
99};
100
101struct msgbuf_tx_msghdr {
102 struct msgbuf_common_hdr msg;
103 u8 txhdr[ETH_HLEN];
104 u8 flags;
105 u8 seg_cnt;
106 struct msgbuf_buf_addr metadata_buf_addr;
107 struct msgbuf_buf_addr data_buf_addr;
108 __le16 metadata_buf_len;
109 __le16 data_len;
110 __le32 rsvd0;
111};
112
113struct msgbuf_rx_bufpost {
114 struct msgbuf_common_hdr msg;
115 __le16 metadata_buf_len;
116 __le16 data_buf_len;
117 __le32 rsvd0;
118 struct msgbuf_buf_addr metadata_buf_addr;
119 struct msgbuf_buf_addr data_buf_addr;
120};
121
122struct msgbuf_rx_ioctl_resp_or_event {
123 struct msgbuf_common_hdr msg;
124 __le16 host_buf_len;
125 __le16 rsvd0[3];
126 struct msgbuf_buf_addr host_buf_addr;
127 __le32 rsvd1[4];
128};
129
130struct msgbuf_completion_hdr {
131 __le16 status;
132 __le16 flow_ring_id;
133};
134
135struct msgbuf_rx_event {
136 struct msgbuf_common_hdr msg;
137 struct msgbuf_completion_hdr compl_hdr;
138 __le16 event_data_len;
139 __le16 seqnum;
140 __le16 rsvd0[4];
141};
142
143struct msgbuf_ioctl_resp_hdr {
144 struct msgbuf_common_hdr msg;
145 struct msgbuf_completion_hdr compl_hdr;
146 __le16 resp_len;
147 __le16 trans_id;
148 __le32 cmd;
149 __le32 rsvd0;
150};
151
152struct msgbuf_tx_status {
153 struct msgbuf_common_hdr msg;
154 struct msgbuf_completion_hdr compl_hdr;
155 __le16 metadata_len;
156 __le16 tx_status;
157};
158
159struct msgbuf_rx_complete {
160 struct msgbuf_common_hdr msg;
161 struct msgbuf_completion_hdr compl_hdr;
162 __le16 metadata_len;
163 __le16 data_len;
164 __le16 data_offset;
165 __le16 flags;
166 __le32 rx_status_0;
167 __le32 rx_status_1;
168 __le32 rsvd0;
169};
170
171struct msgbuf_tx_flowring_create_req {
172 struct msgbuf_common_hdr msg;
173 u8 da[ETH_ALEN];
174 u8 sa[ETH_ALEN];
175 u8 tid;
176 u8 if_flags;
177 __le16 flow_ring_id;
178 u8 tc;
179 u8 priority;
180 __le16 int_vector;
181 __le16 max_items;
182 __le16 len_item;
183 struct msgbuf_buf_addr flow_ring_addr;
184};
185
186struct msgbuf_tx_flowring_delete_req {
187 struct msgbuf_common_hdr msg;
188 __le16 flow_ring_id;
189 __le16 reason;
190 __le32 rsvd0[7];
191};
192
193struct msgbuf_flowring_create_resp {
194 struct msgbuf_common_hdr msg;
195 struct msgbuf_completion_hdr compl_hdr;
196 __le32 rsvd0[3];
197};
198
199struct msgbuf_flowring_delete_resp {
200 struct msgbuf_common_hdr msg;
201 struct msgbuf_completion_hdr compl_hdr;
202 __le32 rsvd0[3];
203};
204
205struct msgbuf_flowring_flush_resp {
206 struct msgbuf_common_hdr msg;
207 struct msgbuf_completion_hdr compl_hdr;
208 __le32 rsvd0[3];
209};
210
211struct brcmf_msgbuf {
212 struct brcmf_pub *drvr;
213
214 struct brcmf_commonring **commonrings;
215 struct brcmf_commonring **flowrings;
216 dma_addr_t *flowring_dma_handle;
217 u16 nrof_flowrings;
218
219 u16 rx_dataoffset;
220 u32 max_rxbufpost;
221 u16 rx_metadata_offset;
222 u32 rxbufpost;
223
224 u32 max_ioctlrespbuf;
225 u32 cur_ioctlrespbuf;
226 u32 max_eventbuf;
227 u32 cur_eventbuf;
228
229 void *ioctbuf;
230 dma_addr_t ioctbuf_handle;
231 u32 ioctbuf_phys_hi;
232 u32 ioctbuf_phys_lo;
233 u32 ioctl_resp_status;
234 u32 ioctl_resp_ret_len;
235 u32 ioctl_resp_pktid;
236
237 u16 data_seq_no;
238 u16 ioctl_seq_no;
239 u32 reqid;
240 wait_queue_head_t ioctl_resp_wait;
241 bool ctl_completed;
242
243 struct brcmf_msgbuf_pktids *tx_pktids;
244 struct brcmf_msgbuf_pktids *rx_pktids;
245 struct brcmf_flowring *flow;
246
247 struct workqueue_struct *txflow_wq;
248 struct work_struct txflow_work;
249 unsigned long *flow_map;
250 unsigned long *txstatus_done_map;
251};
252
253struct brcmf_msgbuf_pktid {
254 atomic_t allocated;
255 u16 data_offset;
256 struct sk_buff *skb;
257 dma_addr_t physaddr;
258};
259
260struct brcmf_msgbuf_pktids {
261 u32 array_size;
262 u32 last_allocated_idx;
263 enum dma_data_direction direction;
264 struct brcmf_msgbuf_pktid *array;
265};
266
267
268/* dma flushing needs implementation for mips and arm platforms. Should
269 * be put in util. Note, this is not real flushing. It is virtual non
270 * cached memory. Only write buffers should have to be drained. Though
271 * this may be different depending on platform......
272 */
273#define brcmf_dma_flush(addr, len)
274#define brcmf_dma_invalidate_cache(addr, len)
275
276
277static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf);
278
279
280static struct brcmf_msgbuf_pktids *
281brcmf_msgbuf_init_pktids(u32 nr_array_entries,
282 enum dma_data_direction direction)
283{
284 struct brcmf_msgbuf_pktid *array;
285 struct brcmf_msgbuf_pktids *pktids;
286
287 array = kcalloc(nr_array_entries, sizeof(*array), GFP_ATOMIC);
288 if (!array)
289 return NULL;
290
291 pktids = kzalloc(sizeof(*pktids), GFP_ATOMIC);
292 if (!pktids) {
293 kfree(array);
294 return NULL;
295 }
296 pktids->array = array;
297 pktids->array_size = nr_array_entries;
298
299 return pktids;
300}
301
302
303static int
304brcmf_msgbuf_alloc_pktid(struct device *dev,
305 struct brcmf_msgbuf_pktids *pktids,
306 struct sk_buff *skb, u16 data_offset,
307 dma_addr_t *physaddr, u32 *idx)
308{
309 struct brcmf_msgbuf_pktid *array;
310 u32 count;
311
312 array = pktids->array;
313
314 *physaddr = dma_map_single(dev, skb->data + data_offset,
315 skb->len - data_offset, pktids->direction);
316
317 if (dma_mapping_error(dev, *physaddr)) {
318 brcmf_err("dma_map_single failed !!\n");
319 return -ENOMEM;
320 }
321
322 *idx = pktids->last_allocated_idx;
323
324 count = 0;
325 do {
326 (*idx)++;
327 if (*idx == pktids->array_size)
328 *idx = 0;
329 if (array[*idx].allocated.counter == 0)
330 if (atomic_cmpxchg(&array[*idx].allocated, 0, 1) == 0)
331 break;
332 count++;
333 } while (count < pktids->array_size);
334
335 if (count == pktids->array_size)
336 return -ENOMEM;
337
338 array[*idx].data_offset = data_offset;
339 array[*idx].physaddr = *physaddr;
340 array[*idx].skb = skb;
341
342 pktids->last_allocated_idx = *idx;
343
344 return 0;
345}
346
347
348static struct sk_buff *
349brcmf_msgbuf_get_pktid(struct device *dev, struct brcmf_msgbuf_pktids *pktids,
350 u32 idx)
351{
352 struct brcmf_msgbuf_pktid *pktid;
353 struct sk_buff *skb;
354
355 if (idx >= pktids->array_size) {
356 brcmf_err("Invalid packet id %d (max %d)\n", idx,
357 pktids->array_size);
358 return NULL;
359 }
360 if (pktids->array[idx].allocated.counter) {
361 pktid = &pktids->array[idx];
362 dma_unmap_single(dev, pktid->physaddr,
363 pktid->skb->len - pktid->data_offset,
364 pktids->direction);
365 skb = pktid->skb;
366 pktid->allocated.counter = 0;
367 return skb;
368 } else {
369 brcmf_err("Invalid packet id %d (not in use)\n", idx);
370 }
371
372 return NULL;
373}
374
375
376static void
377brcmf_msgbuf_release_array(struct device *dev,
378 struct brcmf_msgbuf_pktids *pktids)
379{
380 struct brcmf_msgbuf_pktid *array;
381 struct brcmf_msgbuf_pktid *pktid;
382 u32 count;
383
384 array = pktids->array;
385 count = 0;
386 do {
387 if (array[count].allocated.counter) {
388 pktid = &array[count];
389 dma_unmap_single(dev, pktid->physaddr,
390 pktid->skb->len - pktid->data_offset,
391 pktids->direction);
392 brcmu_pkt_buf_free_skb(pktid->skb);
393 }
394 count++;
395 } while (count < pktids->array_size);
396
397 kfree(array);
398 kfree(pktids);
399}
400
401
402static void brcmf_msgbuf_release_pktids(struct brcmf_msgbuf *msgbuf)
403{
404 if (msgbuf->rx_pktids)
405 brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev,
406 msgbuf->rx_pktids);
407 if (msgbuf->tx_pktids)
408 brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev,
409 msgbuf->tx_pktids);
410}
411
412
413static int brcmf_msgbuf_tx_ioctl(struct brcmf_pub *drvr, int ifidx,
414 uint cmd, void *buf, uint len)
415{
416 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
417 struct brcmf_commonring *commonring;
418 struct msgbuf_ioctl_req_hdr *request;
419 u16 buf_len;
420 void *ret_ptr;
421 int err;
422
423 commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
424 brcmf_commonring_lock(commonring);
425 ret_ptr = brcmf_commonring_reserve_for_write(commonring);
426 if (!ret_ptr) {
427 brcmf_err("Failed to reserve space in commonring\n");
428 brcmf_commonring_unlock(commonring);
429 return -ENOMEM;
430 }
431
432 msgbuf->reqid++;
433
434 request = (struct msgbuf_ioctl_req_hdr *)ret_ptr;
435 request->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ;
436 request->msg.ifidx = (u8)ifidx;
437 request->msg.flags = 0;
438 request->msg.request_id = cpu_to_le32(BRCMF_IOCTL_REQ_PKTID);
439 request->cmd = cpu_to_le32(cmd);
440 request->output_buf_len = cpu_to_le16(len);
441 request->trans_id = cpu_to_le16(msgbuf->reqid);
442
443 buf_len = min_t(u16, len, BRCMF_TX_IOCTL_MAX_MSG_SIZE);
444 request->input_buf_len = cpu_to_le16(buf_len);
445 request->req_buf_addr.high_addr = cpu_to_le32(msgbuf->ioctbuf_phys_hi);
446 request->req_buf_addr.low_addr = cpu_to_le32(msgbuf->ioctbuf_phys_lo);
447 if (buf)
448 memcpy(msgbuf->ioctbuf, buf, buf_len);
449 else
450 memset(msgbuf->ioctbuf, 0, buf_len);
451 brcmf_dma_flush(ioctl_buf, buf_len);
452
453 err = brcmf_commonring_write_complete(commonring);
454 brcmf_commonring_unlock(commonring);
455
456 return err;
457}
458
459
460static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf)
461{
462 return wait_event_timeout(msgbuf->ioctl_resp_wait,
463 msgbuf->ctl_completed,
464 msecs_to_jiffies(MSGBUF_IOCTL_RESP_TIMEOUT));
465}
466
467
468static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf)
469{
470 if (waitqueue_active(&msgbuf->ioctl_resp_wait)) {
471 msgbuf->ctl_completed = true;
472 wake_up(&msgbuf->ioctl_resp_wait);
473 }
474}
475
476
477static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
478 uint cmd, void *buf, uint len)
479{
480 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
481 struct sk_buff *skb = NULL;
482 int timeout;
483 int err;
484
485 brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);
486 msgbuf->ctl_completed = false;
487 err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);
488 if (err)
489 return err;
490
491 timeout = brcmf_msgbuf_ioctl_resp_wait(msgbuf);
492 if (!timeout) {
493 brcmf_err("Timeout on response for query command\n");
494 return -EIO;
495 }
496
497 skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
498 msgbuf->rx_pktids,
499 msgbuf->ioctl_resp_pktid);
500 if (msgbuf->ioctl_resp_ret_len != 0) {
501 if (!skb) {
502 brcmf_err("Invalid packet id idx recv'd %d\n",
503 msgbuf->ioctl_resp_pktid);
504 return -EBADF;
505 }
506 memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?
507 len : msgbuf->ioctl_resp_ret_len);
508 }
509 if (skb)
510 brcmu_pkt_buf_free_skb(skb);
511
512 return msgbuf->ioctl_resp_status;
513}
514
515
516static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,
517 uint cmd, void *buf, uint len)
518{
519 return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len);
520}
521
522
523static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,
524 u8 *ifidx, struct sk_buff *skb)
525{
526 return -ENODEV;
527}
528
529
530static void
531brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)
532{
533 u32 dma_sz;
534 void *dma_buf;
535
536 brcmf_dbg(MSGBUF, "Removing flowring %d\n", flowid);
537
538 dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;
539 dma_buf = msgbuf->flowrings[flowid]->buf_addr;
540 dma_free_coherent(msgbuf->drvr->bus_if->dev, dma_sz, dma_buf,
541 msgbuf->flowring_dma_handle[flowid]);
542
543 brcmf_flowring_delete(msgbuf->flow, flowid);
544}
545
546
547static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,
548 struct sk_buff *skb)
549{
550 struct msgbuf_tx_flowring_create_req *create;
551 struct ethhdr *eh = (struct ethhdr *)(skb->data);
552 struct brcmf_commonring *commonring;
553 void *ret_ptr;
554 u32 flowid;
555 void *dma_buf;
556 u32 dma_sz;
557 long long address;
558 int err;
559
560 flowid = brcmf_flowring_create(msgbuf->flow, eh->h_dest,
561 skb->priority, ifidx);
562 if (flowid == BRCMF_FLOWRING_INVALID_ID)
563 return flowid;
564
565 dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;
566
567 dma_buf = dma_alloc_coherent(msgbuf->drvr->bus_if->dev, dma_sz,
568 &msgbuf->flowring_dma_handle[flowid],
569 GFP_ATOMIC);
570 if (!dma_buf) {
571 brcmf_err("dma_alloc_coherent failed\n");
572 brcmf_flowring_delete(msgbuf->flow, flowid);
573 return BRCMF_FLOWRING_INVALID_ID;
574 }
575
576 brcmf_commonring_config(msgbuf->flowrings[flowid],
577 BRCMF_H2D_TXFLOWRING_MAX_ITEM,
578 BRCMF_H2D_TXFLOWRING_ITEMSIZE, dma_buf);
579
580 commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
581 brcmf_commonring_lock(commonring);
582 ret_ptr = brcmf_commonring_reserve_for_write(commonring);
583 if (!ret_ptr) {
584 brcmf_err("Failed to reserve space in commonring\n");
585 brcmf_commonring_unlock(commonring);
586 brcmf_msgbuf_remove_flowring(msgbuf, flowid);
587 return BRCMF_FLOWRING_INVALID_ID;
588 }
589
590 create = (struct msgbuf_tx_flowring_create_req *)ret_ptr;
591 create->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
592 create->msg.ifidx = ifidx;
593 create->msg.request_id = 0;
594 create->tid = brcmf_flowring_tid(msgbuf->flow, flowid);
595 create->flow_ring_id = cpu_to_le16(flowid +
596 BRCMF_NROF_H2D_COMMON_MSGRINGS);
597 memcpy(create->sa, eh->h_source, ETH_ALEN);
598 memcpy(create->da, eh->h_dest, ETH_ALEN);
599 address = (long long)(long)msgbuf->flowring_dma_handle[flowid];
600 create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32);
601 create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff);
602 create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM);
603 create->len_item = cpu_to_le16(BRCMF_H2D_TXFLOWRING_ITEMSIZE);
604
605 brcmf_dbg(MSGBUF, "Send Flow Create Req flow ID %d for peer %pM prio %d ifindex %d\n",
606 flowid, eh->h_dest, create->tid, ifidx);
607
608 err = brcmf_commonring_write_complete(commonring);
609 brcmf_commonring_unlock(commonring);
610 if (err) {
611 brcmf_err("Failed to write commonring\n");
612 brcmf_msgbuf_remove_flowring(msgbuf, flowid);
613 return BRCMF_FLOWRING_INVALID_ID;
614 }
615
616 return flowid;
617}
618
619
620static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
621{
622 struct brcmf_flowring *flow = msgbuf->flow;
623 struct brcmf_commonring *commonring;
624 void *ret_ptr;
625 u32 count;
626 struct sk_buff *skb;
627 dma_addr_t physaddr;
628 u32 pktid;
629 struct msgbuf_tx_msghdr *tx_msghdr;
630 long long address;
631
632 commonring = msgbuf->flowrings[flowid];
633 if (!brcmf_commonring_write_available(commonring))
634 return;
635
636 brcmf_commonring_lock(commonring);
637
638 count = BRCMF_MSGBUF_TX_FLUSH_CNT2 - BRCMF_MSGBUF_TX_FLUSH_CNT1;
639 while (brcmf_flowring_qlen(flow, flowid)) {
640 skb = brcmf_flowring_dequeue(flow, flowid);
641 if (skb == NULL) {
642 brcmf_err("No SKB, but qlen %d\n",
643 brcmf_flowring_qlen(flow, flowid));
644 break;
645 }
646 skb_orphan(skb);
647 if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,
648 msgbuf->tx_pktids, skb, ETH_HLEN,
649 &physaddr, &pktid)) {
650 brcmf_flowring_reinsert(flow, flowid, skb);
651 brcmf_err("No PKTID available !!\n");
652 break;
653 }
654 ret_ptr = brcmf_commonring_reserve_for_write(commonring);
655 if (!ret_ptr) {
656 brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
657 msgbuf->tx_pktids, pktid);
658 brcmf_flowring_reinsert(flow, flowid, skb);
659 break;
660 }
661 count++;
662
663 tx_msghdr = (struct msgbuf_tx_msghdr *)ret_ptr;
664
665 tx_msghdr->msg.msgtype = MSGBUF_TYPE_TX_POST;
666 tx_msghdr->msg.request_id = cpu_to_le32(pktid);
667 tx_msghdr->msg.ifidx = brcmf_flowring_ifidx_get(flow, flowid);
668 tx_msghdr->flags = BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3;
669 tx_msghdr->flags |= (skb->priority & 0x07) <<
670 BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT;
671 tx_msghdr->seg_cnt = 1;
672 memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN);
673 tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN);
674 address = (long long)(long)physaddr;
675 tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32);
676 tx_msghdr->data_buf_addr.low_addr =
677 cpu_to_le32(address & 0xffffffff);
678 tx_msghdr->metadata_buf_len = 0;
679 tx_msghdr->metadata_buf_addr.high_addr = 0;
680 tx_msghdr->metadata_buf_addr.low_addr = 0;
681 if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) {
682 brcmf_commonring_write_complete(commonring);
683 count = 0;
684 }
685 }
686 if (count)
687 brcmf_commonring_write_complete(commonring);
688 brcmf_commonring_unlock(commonring);
689}
690
691
692static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)
693{
694 struct brcmf_msgbuf *msgbuf;
695 u32 flowid;
696
697 msgbuf = container_of(worker, struct brcmf_msgbuf, txflow_work);
698 for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->nrof_flowrings) {
699 clear_bit(flowid, msgbuf->flow_map);
700 brcmf_msgbuf_txflow(msgbuf, flowid);
701 }
702}
703
704
705static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid)
706{
707 set_bit(flowid, msgbuf->flow_map);
708 queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
709
710 return 0;
711}
712
713
714static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
715 u8 offset, struct sk_buff *skb)
716{
717 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
718 struct brcmf_flowring *flow = msgbuf->flow;
719 struct ethhdr *eh = (struct ethhdr *)(skb->data);
720 u32 flowid;
721
722 flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);
723 if (flowid == BRCMF_FLOWRING_INVALID_ID) {
724 flowid = brcmf_msgbuf_flowring_create(msgbuf, ifidx, skb);
725 if (flowid == BRCMF_FLOWRING_INVALID_ID)
726 return -ENOMEM;
727 }
728 brcmf_flowring_enqueue(flow, flowid, skb);
729 brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
730
731 return 0;
732}
733
734
735static void
736brcmf_msgbuf_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,
737 enum proto_addr_mode addr_mode)
738{
739 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
740
741 brcmf_flowring_configure_addr_mode(msgbuf->flow, ifidx, addr_mode);
742}
743
744
745static void
746brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])
747{
748 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
749
750 brcmf_flowring_delete_peer(msgbuf->flow, ifidx, peer);
751}
752
753
754static void
755brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf)
756{
757 struct msgbuf_ioctl_resp_hdr *ioctl_resp;
758
759 ioctl_resp = (struct msgbuf_ioctl_resp_hdr *)buf;
760
761 msgbuf->ioctl_resp_status = le16_to_cpu(ioctl_resp->compl_hdr.status);
762 msgbuf->ioctl_resp_ret_len = le16_to_cpu(ioctl_resp->resp_len);
763 msgbuf->ioctl_resp_pktid = le32_to_cpu(ioctl_resp->msg.request_id);
764
765 brcmf_msgbuf_ioctl_resp_wake(msgbuf);
766
767 if (msgbuf->cur_ioctlrespbuf)
768 msgbuf->cur_ioctlrespbuf--;
769 brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);
770}
771
772
773static void
774brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
775{
776 struct msgbuf_tx_status *tx_status;
777 u32 idx;
778 struct sk_buff *skb;
779 u16 flowid;
780
781 tx_status = (struct msgbuf_tx_status *)buf;
782 idx = le32_to_cpu(tx_status->msg.request_id);
783 flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id);
784 flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS;
785 skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
786 msgbuf->tx_pktids, idx);
787 if (!skb) {
788 brcmf_err("Invalid packet id idx recv'd %d\n", idx);
789 return;
790 }
791
792 set_bit(flowid, msgbuf->txstatus_done_map);
793
794 brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true);
795}
796
797
798static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)
799{
800 struct brcmf_commonring *commonring;
801 void *ret_ptr;
802 struct sk_buff *skb;
803 u16 alloced;
804 u32 pktlen;
805 dma_addr_t physaddr;
806 struct msgbuf_rx_bufpost *rx_bufpost;
807 long long address;
808 u32 pktid;
809 u32 i;
810
811 commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];
812 ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring,
813 count,
814 &alloced);
815 if (!ret_ptr) {
816 brcmf_err("Failed to reserve space in commonring\n");
817 return 0;
818 }
819
820 for (i = 0; i < alloced; i++) {
821 rx_bufpost = (struct msgbuf_rx_bufpost *)ret_ptr;
822 memset(rx_bufpost, 0, sizeof(*rx_bufpost));
823
824 skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE);
825
826 if (skb == NULL) {
827 brcmf_err("Failed to alloc SKB\n");
828 brcmf_commonring_write_cancel(commonring, alloced - i);
829 break;
830 }
831
832 pktlen = skb->len;
833 if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,
834 msgbuf->rx_pktids, skb, 0,
835 &physaddr, &pktid)) {
836 dev_kfree_skb_any(skb);
837 brcmf_err("No PKTID available !!\n");
838 brcmf_commonring_write_cancel(commonring, alloced - i);
839 break;
840 }
841
842 if (msgbuf->rx_metadata_offset) {
843 address = (long long)(long)physaddr;
844 rx_bufpost->metadata_buf_len =
845 cpu_to_le16(msgbuf->rx_metadata_offset);
846 rx_bufpost->metadata_buf_addr.high_addr =
847 cpu_to_le32(address >> 32);
848 rx_bufpost->metadata_buf_addr.low_addr =
849 cpu_to_le32(address & 0xffffffff);
850
851 skb_pull(skb, msgbuf->rx_metadata_offset);
852 pktlen = skb->len;
853 physaddr += msgbuf->rx_metadata_offset;
854 }
855 rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
856 rx_bufpost->msg.request_id = cpu_to_le32(pktid);
857
858 address = (long long)(long)physaddr;
859 rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen);
860 rx_bufpost->data_buf_addr.high_addr =
861 cpu_to_le32(address >> 32);
862 rx_bufpost->data_buf_addr.low_addr =
863 cpu_to_le32(address & 0xffffffff);
864
865 ret_ptr += brcmf_commonring_len_item(commonring);
866 }
867
868 if (i)
869 brcmf_commonring_write_complete(commonring);
870
871 return i;
872}
873
874
875static void
876brcmf_msgbuf_rxbuf_data_fill(struct brcmf_msgbuf *msgbuf)
877{
878 u32 fillbufs;
879 u32 retcount;
880
881 fillbufs = msgbuf->max_rxbufpost - msgbuf->rxbufpost;
882
883 while (fillbufs) {
884 retcount = brcmf_msgbuf_rxbuf_data_post(msgbuf, fillbufs);
885 if (!retcount)
886 break;
887 msgbuf->rxbufpost += retcount;
888 fillbufs -= retcount;
889 }
890}
891
892
893static void
894brcmf_msgbuf_update_rxbufpost_count(struct brcmf_msgbuf *msgbuf, u16 rxcnt)
895{
896 msgbuf->rxbufpost -= rxcnt;
897 if (msgbuf->rxbufpost <= (msgbuf->max_rxbufpost -
898 BRCMF_MSGBUF_RXBUFPOST_THRESHOLD))
899 brcmf_msgbuf_rxbuf_data_fill(msgbuf);
900}
901
902
903static u32
904brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf,
905 u32 count)
906{
907 struct brcmf_commonring *commonring;
908 void *ret_ptr;
909 struct sk_buff *skb;
910 u16 alloced;
911 u32 pktlen;
912 dma_addr_t physaddr;
913 struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost;
914 long long address;
915 u32 pktid;
916 u32 i;
917
918 commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
919 brcmf_commonring_lock(commonring);
920 ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring,
921 count,
922 &alloced);
923 if (!ret_ptr) {
924 brcmf_err("Failed to reserve space in commonring\n");
925 brcmf_commonring_unlock(commonring);
926 return 0;
927 }
928
929 for (i = 0; i < alloced; i++) {
930 rx_bufpost = (struct msgbuf_rx_ioctl_resp_or_event *)ret_ptr;
931 memset(rx_bufpost, 0, sizeof(*rx_bufpost));
932
933 skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE);
934
935 if (skb == NULL) {
936 brcmf_err("Failed to alloc SKB\n");
937 brcmf_commonring_write_cancel(commonring, alloced - i);
938 break;
939 }
940
941 pktlen = skb->len;
942 if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev,
943 msgbuf->rx_pktids, skb, 0,
944 &physaddr, &pktid)) {
945 dev_kfree_skb_any(skb);
946 brcmf_err("No PKTID available !!\n");
947 brcmf_commonring_write_cancel(commonring, alloced - i);
948 break;
949 }
950 if (event_buf)
951 rx_bufpost->msg.msgtype = MSGBUF_TYPE_EVENT_BUF_POST;
952 else
953 rx_bufpost->msg.msgtype =
954 MSGBUF_TYPE_IOCTLRESP_BUF_POST;
955 rx_bufpost->msg.request_id = cpu_to_le32(pktid);
956
957 address = (long long)(long)physaddr;
958 rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen);
959 rx_bufpost->host_buf_addr.high_addr =
960 cpu_to_le32(address >> 32);
961 rx_bufpost->host_buf_addr.low_addr =
962 cpu_to_le32(address & 0xffffffff);
963
964 ret_ptr += brcmf_commonring_len_item(commonring);
965 }
966
967 if (i)
968 brcmf_commonring_write_complete(commonring);
969
970 brcmf_commonring_unlock(commonring);
971
972 return i;
973}
974
975
976static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf)
977{
978 u32 count;
979
980 count = msgbuf->max_ioctlrespbuf - msgbuf->cur_ioctlrespbuf;
981 count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, false, count);
982 msgbuf->cur_ioctlrespbuf += count;
983}
984
985
986static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf)
987{
988 u32 count;
989
990 count = msgbuf->max_eventbuf - msgbuf->cur_eventbuf;
991 count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, true, count);
992 msgbuf->cur_eventbuf += count;
993}
994
995
996static void
997brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
998 u8 ifidx)
999{
1000 struct brcmf_if *ifp;
1001
1002 ifp = msgbuf->drvr->iflist[ifidx];
1003 if (!ifp || !ifp->ndev) {
1004 brcmu_pkt_buf_free_skb(skb);
1005 return;
1006 }
1007 brcmf_netif_rx(ifp, skb);
1008}
1009
1010
1011static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
1012{
1013 struct msgbuf_rx_event *event;
1014 u32 idx;
1015 u16 buflen;
1016 struct sk_buff *skb;
1017
1018 event = (struct msgbuf_rx_event *)buf;
1019 idx = le32_to_cpu(event->msg.request_id);
1020 buflen = le16_to_cpu(event->event_data_len);
1021
1022 if (msgbuf->cur_eventbuf)
1023 msgbuf->cur_eventbuf--;
1024 brcmf_msgbuf_rxbuf_event_post(msgbuf);
1025
1026 skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
1027 msgbuf->rx_pktids, idx);
1028 if (!skb)
1029 return;
1030
1031 if (msgbuf->rx_dataoffset)
1032 skb_pull(skb, msgbuf->rx_dataoffset);
1033
1034 skb_trim(skb, buflen);
1035
1036 brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
1037}
1038
1039
1040static void
1041brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
1042{
1043 struct msgbuf_rx_complete *rx_complete;
1044 struct sk_buff *skb;
1045 u16 data_offset;
1046 u16 buflen;
1047 u32 idx;
1048
1049 brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
1050
1051 rx_complete = (struct msgbuf_rx_complete *)buf;
1052 data_offset = le16_to_cpu(rx_complete->data_offset);
1053 buflen = le16_to_cpu(rx_complete->data_len);
1054 idx = le32_to_cpu(rx_complete->msg.request_id);
1055
1056 skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
1057 msgbuf->rx_pktids, idx);
1058
1059 if (data_offset)
1060 skb_pull(skb, data_offset);
1061 else if (msgbuf->rx_dataoffset)
1062 skb_pull(skb, msgbuf->rx_dataoffset);
1063
1064 skb_trim(skb, buflen);
1065
1066 brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
1067}
1068
1069
1070static void
1071brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,
1072 void *buf)
1073{
1074 struct msgbuf_flowring_create_resp *flowring_create_resp;
1075 u16 status;
1076 u16 flowid;
1077
1078 flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf;
1079
1080 flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id);
1081 flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS;
1082 status = le16_to_cpu(flowring_create_resp->compl_hdr.status);
1083
1084 if (status) {
1085 brcmf_err("Flowring creation failed, code %d\n", status);
1086 brcmf_msgbuf_remove_flowring(msgbuf, flowid);
1087 return;
1088 }
1089 brcmf_dbg(MSGBUF, "Flowring %d Create response status %d\n", flowid,
1090 status);
1091
1092 brcmf_flowring_open(msgbuf->flow, flowid);
1093
1094 brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
1095}
1096
1097
1098static void
1099brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf,
1100 void *buf)
1101{
1102 struct msgbuf_flowring_delete_resp *flowring_delete_resp;
1103 u16 status;
1104 u16 flowid;
1105
1106 flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf;
1107
1108 flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id);
1109 flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS;
1110 status = le16_to_cpu(flowring_delete_resp->compl_hdr.status);
1111
1112 if (status) {
1113 brcmf_err("Flowring deletion failed, code %d\n", status);
1114 brcmf_flowring_delete(msgbuf->flow, flowid);
1115 return;
1116 }
1117 brcmf_dbg(MSGBUF, "Flowring %d Delete response status %d\n", flowid,
1118 status);
1119
1120 brcmf_msgbuf_remove_flowring(msgbuf, flowid);
1121}
1122
1123
1124static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf)
1125{
1126 struct msgbuf_common_hdr *msg;
1127
1128 msg = (struct msgbuf_common_hdr *)buf;
1129 switch (msg->msgtype) {
1130 case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT:
1131 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT\n");
1132 brcmf_msgbuf_process_flow_ring_create_response(msgbuf, buf);
1133 break;
1134 case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT:
1135 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT\n");
1136 brcmf_msgbuf_process_flow_ring_delete_response(msgbuf, buf);
1137 break;
1138 case MSGBUF_TYPE_IOCTLPTR_REQ_ACK:
1139 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTLPTR_REQ_ACK\n");
1140 break;
1141 case MSGBUF_TYPE_IOCTL_CMPLT:
1142 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTL_CMPLT\n");
1143 brcmf_msgbuf_process_ioctl_complete(msgbuf, buf);
1144 break;
1145 case MSGBUF_TYPE_WL_EVENT:
1146 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_WL_EVENT\n");
1147 brcmf_msgbuf_process_event(msgbuf, buf);
1148 break;
1149 case MSGBUF_TYPE_TX_STATUS:
1150 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_TX_STATUS\n");
1151 brcmf_msgbuf_process_txstatus(msgbuf, buf);
1152 break;
1153 case MSGBUF_TYPE_RX_CMPLT:
1154 brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RX_CMPLT\n");
1155 brcmf_msgbuf_process_rx_complete(msgbuf, buf);
1156 break;
1157 default:
1158 brcmf_err("Unsupported msgtype %d\n", msg->msgtype);
1159 break;
1160 }
1161}
1162
1163
1164static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf,
1165 struct brcmf_commonring *commonring)
1166{
1167 void *buf;
1168 u16 count;
1169
1170again:
1171 buf = brcmf_commonring_get_read_ptr(commonring, &count);
1172 if (buf == NULL)
1173 return;
1174
1175 while (count) {
1176 brcmf_msgbuf_process_msgtype(msgbuf,
1177 buf + msgbuf->rx_dataoffset);
1178 buf += brcmf_commonring_len_item(commonring);
1179 count--;
1180 }
1181 brcmf_commonring_read_complete(commonring);
1182
1183 if (commonring->r_ptr == 0)
1184 goto again;
1185}
1186
1187
1188int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
1189{
1190 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1191 struct brcmf_pub *drvr = bus_if->drvr;
1192 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
1193 void *buf;
1194 u32 flowid;
1195
1196 buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];
1197 brcmf_msgbuf_process_rx(msgbuf, buf);
1198 buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];
1199 brcmf_msgbuf_process_rx(msgbuf, buf);
1200 buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];
1201 brcmf_msgbuf_process_rx(msgbuf, buf);
1202
1203 for_each_set_bit(flowid, msgbuf->txstatus_done_map,
1204 msgbuf->nrof_flowrings) {
1205 clear_bit(flowid, msgbuf->txstatus_done_map);
1206 if (brcmf_flowring_qlen(msgbuf->flow, flowid))
1207 brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
1208 }
1209
1210 return 0;
1211}
1212
1213
1214void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid)
1215{
1216 struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
1217 struct msgbuf_tx_flowring_delete_req *delete;
1218 struct brcmf_commonring *commonring;
1219 void *ret_ptr;
1220 u8 ifidx;
1221 int err;
1222
1223 commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
1224 brcmf_commonring_lock(commonring);
1225 ret_ptr = brcmf_commonring_reserve_for_write(commonring);
1226 if (!ret_ptr) {
1227 brcmf_err("FW unaware, flowring will be removed !!\n");
1228 brcmf_commonring_unlock(commonring);
1229 brcmf_msgbuf_remove_flowring(msgbuf, flowid);
1230 return;
1231 }
1232
1233 delete = (struct msgbuf_tx_flowring_delete_req *)ret_ptr;
1234
1235 ifidx = brcmf_flowring_ifidx_get(msgbuf->flow, flowid);
1236
1237 delete->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE;
1238 delete->msg.ifidx = ifidx;
1239 delete->msg.request_id = 0;
1240
1241 delete->flow_ring_id = cpu_to_le16(flowid +
1242 BRCMF_NROF_H2D_COMMON_MSGRINGS);
1243 delete->reason = 0;
1244
1245 brcmf_dbg(MSGBUF, "Send Flow Delete Req flow ID %d, ifindex %d\n",
1246 flowid, ifidx);
1247
1248 err = brcmf_commonring_write_complete(commonring);
1249 brcmf_commonring_unlock(commonring);
1250 if (err) {
1251 brcmf_err("Failed to submit RING_DELETE, flowring will be removed\n");
1252 brcmf_msgbuf_remove_flowring(msgbuf, flowid);
1253 }
1254}
1255
1256
1257int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
1258{
1259 struct brcmf_bus_msgbuf *if_msgbuf;
1260 struct brcmf_msgbuf *msgbuf;
1261 long long address;
1262 u32 count;
1263
1264 if_msgbuf = drvr->bus_if->msgbuf;
1265 msgbuf = kzalloc(sizeof(*msgbuf), GFP_ATOMIC);
1266 if (!msgbuf)
1267 goto fail;
1268
1269 msgbuf->txflow_wq = create_singlethread_workqueue("msgbuf_txflow");
1270 if (msgbuf->txflow_wq == NULL) {
1271 brcmf_err("workqueue creation failed\n");
1272 goto fail;
1273 }
1274 INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker);
1275 count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings);
1276 msgbuf->flow_map = kzalloc(count, GFP_ATOMIC);
1277 if (!msgbuf->flow_map)
1278 goto fail;
1279
1280 msgbuf->txstatus_done_map = kzalloc(count, GFP_ATOMIC);
1281 if (!msgbuf->txstatus_done_map)
1282 goto fail;
1283
1284 msgbuf->drvr = drvr;
1285 msgbuf->ioctbuf = dma_alloc_coherent(drvr->bus_if->dev,
1286 BRCMF_TX_IOCTL_MAX_MSG_SIZE,
1287 &msgbuf->ioctbuf_handle,
1288 GFP_ATOMIC);
1289 if (!msgbuf->ioctbuf)
1290 goto fail;
1291 address = (long long)(long)msgbuf->ioctbuf_handle;
1292 msgbuf->ioctbuf_phys_hi = address >> 32;
1293 msgbuf->ioctbuf_phys_lo = address & 0xffffffff;
1294
1295 drvr->proto->hdrpull = brcmf_msgbuf_hdrpull;
1296 drvr->proto->query_dcmd = brcmf_msgbuf_query_dcmd;
1297 drvr->proto->set_dcmd = brcmf_msgbuf_set_dcmd;
1298 drvr->proto->txdata = brcmf_msgbuf_txdata;
1299 drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode;
1300 drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;
1301 drvr->proto->pd = msgbuf;
1302
1303 init_waitqueue_head(&msgbuf->ioctl_resp_wait);
1304
1305 msgbuf->commonrings =
1306 (struct brcmf_commonring **)if_msgbuf->commonrings;
1307 msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings;
1308 msgbuf->nrof_flowrings = if_msgbuf->nrof_flowrings;
1309 msgbuf->flowring_dma_handle = kzalloc(msgbuf->nrof_flowrings *
1310 sizeof(*msgbuf->flowring_dma_handle), GFP_ATOMIC);
1311
1312 msgbuf->rx_dataoffset = if_msgbuf->rx_dataoffset;
1313 msgbuf->max_rxbufpost = if_msgbuf->max_rxbufpost;
1314
1315 msgbuf->max_ioctlrespbuf = BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST;
1316 msgbuf->max_eventbuf = BRCMF_MSGBUF_MAX_EVENTBUF_POST;
1317
1318 msgbuf->tx_pktids = brcmf_msgbuf_init_pktids(NR_TX_PKTIDS,
1319 DMA_TO_DEVICE);
1320 if (!msgbuf->tx_pktids)
1321 goto fail;
1322 msgbuf->rx_pktids = brcmf_msgbuf_init_pktids(NR_RX_PKTIDS,
1323 DMA_FROM_DEVICE);
1324 if (!msgbuf->rx_pktids)
1325 goto fail;
1326
1327 msgbuf->flow = brcmf_flowring_attach(drvr->bus_if->dev,
1328 if_msgbuf->nrof_flowrings);
1329 if (!msgbuf->flow)
1330 goto fail;
1331
1332
1333 brcmf_dbg(MSGBUF, "Feeding buffers, rx data %d, rx event %d, rx ioctl resp %d\n",
1334 msgbuf->max_rxbufpost, msgbuf->max_eventbuf,
1335 msgbuf->max_ioctlrespbuf);
1336 count = 0;
1337 do {
1338 brcmf_msgbuf_rxbuf_data_fill(msgbuf);
1339 if (msgbuf->max_rxbufpost != msgbuf->rxbufpost)
1340 msleep(10);
1341 else
1342 break;
1343 count++;
1344 } while (count < 10);
1345 brcmf_msgbuf_rxbuf_event_post(msgbuf);
1346 brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);
1347
1348 return 0;
1349
1350fail:
1351 if (msgbuf) {
1352 kfree(msgbuf->flow_map);
1353 kfree(msgbuf->txstatus_done_map);
1354 brcmf_msgbuf_release_pktids(msgbuf);
1355 if (msgbuf->ioctbuf)
1356 dma_free_coherent(drvr->bus_if->dev,
1357 BRCMF_TX_IOCTL_MAX_MSG_SIZE,
1358 msgbuf->ioctbuf,
1359 msgbuf->ioctbuf_handle);
1360 kfree(msgbuf);
1361 }
1362 return -ENOMEM;
1363}
1364
1365
1366void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr)
1367{
1368 struct brcmf_msgbuf *msgbuf;
1369
1370 brcmf_dbg(TRACE, "Enter\n");
1371 if (drvr->proto->pd) {
1372 msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
1373
1374 kfree(msgbuf->flow_map);
1375 kfree(msgbuf->txstatus_done_map);
1376 if (msgbuf->txflow_wq)
1377 destroy_workqueue(msgbuf->txflow_wq);
1378
1379 brcmf_flowring_detach(msgbuf->flow);
1380 dma_free_coherent(drvr->bus_if->dev,
1381 BRCMF_TX_IOCTL_MAX_MSG_SIZE,
1382 msgbuf->ioctbuf, msgbuf->ioctbuf_handle);
1383 brcmf_msgbuf_release_pktids(msgbuf);
1384 kfree(msgbuf);
1385 drvr->proto->pd = NULL;
1386 }
1387}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
new file mode 100644
index 000000000000..f901ae52bf2b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
@@ -0,0 +1,40 @@
1/* Copyright (c) 2014 Broadcom Corporation
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15#ifndef BRCMFMAC_MSGBUF_H
16#define BRCMFMAC_MSGBUF_H
17
18
19#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20
20#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256
21#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 20
22#define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024
23#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 256
24#define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512
25
26#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40
27#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE 32
28#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_ITEMSIZE 24
29#define BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE 16
30#define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 32
31#define BRCMF_H2D_TXFLOWRING_ITEMSIZE 48
32
33
34int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
35int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
36void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
37void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
38
39
40#endif /* BRCMFMAC_MSGBUF_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c
index d333ff8fcfff..44b1cb466d4e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/proto.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c
@@ -21,9 +21,11 @@
21 21
22#include <brcmu_wifi.h> 22#include <brcmu_wifi.h>
23#include "dhd.h" 23#include "dhd.h"
24#include "dhd_bus.h"
24#include "dhd_dbg.h" 25#include "dhd_dbg.h"
25#include "proto.h" 26#include "proto.h"
26#include "bcdc.h" 27#include "bcdc.h"
28#include "msgbuf.h"
27 29
28 30
29int brcmf_proto_attach(struct brcmf_pub *drvr) 31int brcmf_proto_attach(struct brcmf_pub *drvr)
@@ -37,10 +39,18 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
37 goto fail; 39 goto fail;
38 40
39 drvr->proto = proto; 41 drvr->proto = proto;
40 /* BCDC protocol is only protocol supported for the moment */
41 if (brcmf_proto_bcdc_attach(drvr))
42 goto fail;
43 42
43 if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC) {
44 if (brcmf_proto_bcdc_attach(drvr))
45 goto fail;
46 } else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF) {
47 if (brcmf_proto_msgbuf_attach(drvr))
48 goto fail;
49 } else {
50 brcmf_err("Unsupported proto type %d\n",
51 drvr->bus_if->proto_type);
52 goto fail;
53 }
44 if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || 54 if ((proto->txdata == NULL) || (proto->hdrpull == NULL) ||
45 (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || 55 (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) ||
46 (proto->configure_addr_mode == NULL) || 56 (proto->configure_addr_mode == NULL) ||
@@ -61,7 +71,10 @@ void brcmf_proto_detach(struct brcmf_pub *drvr)
61 brcmf_dbg(TRACE, "Enter\n"); 71 brcmf_dbg(TRACE, "Enter\n");
62 72
63 if (drvr->proto) { 73 if (drvr->proto) {
64 brcmf_proto_bcdc_detach(drvr); 74 if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
75 brcmf_proto_bcdc_detach(drvr);
76 else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF)
77 brcmf_proto_msgbuf_detach(drvr);
65 kfree(drvr->proto); 78 kfree(drvr->proto);
66 drvr->proto = NULL; 79 drvr->proto = NULL;
67 } 80 }