]>
Commit | Line | Data |
---|---|---|
a9533e7e HP |
1 | /* |
2 | * Copyright (c) 2010 Broadcom Corporation | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
3327989a BR |
16 | #include <linux/kernel.h> |
17 | #include <linux/string.h> | |
a1c16ed2 GKH |
18 | #include <bcmdefs.h> |
19 | #include <wlc_cfg.h> | |
c6ac24e9 BR |
20 | #include <linux/module.h> |
21 | #include <linux/pci.h> | |
a9533e7e HP |
22 | #include <osl.h> |
23 | #include <bcmutils.h> | |
24 | #include <siutils.h> | |
a9533e7e | 25 | #include <wlioctl.h> |
a9533e7e HP |
26 | #include <wlc_pub.h> |
27 | #include <wlc_key.h> | |
a52ba66c BR |
28 | #include <sbhndpio.h> |
29 | #include <sbhnddma.h> | |
a9533e7e HP |
30 | #include <wlc_mac80211.h> |
31 | #include <wlc_alloc.h> | |
69ec303a | 32 | #include <wl_dbg.h> |
a9533e7e | 33 | |
62b54dca AS |
34 | static struct wlc_bsscfg *wlc_bsscfg_malloc(struct osl_info *osh, uint unit); |
35 | static void wlc_bsscfg_mfree(struct osl_info *osh, struct wlc_bsscfg *cfg); | |
08db27dc RV |
36 | static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit, |
37 | uint *err, uint devid); | |
38 | static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub); | |
7cc4a4c0 | 39 | static void wlc_tunables_init(wlc_tunables_t *tunables, uint devid); |
a9533e7e | 40 | |
e69284f2 | 41 | void *wlc_calloc(struct osl_info *osh, uint unit, uint size) |
a9533e7e HP |
42 | { |
43 | void *item; | |
44 | ||
5fcc1fcb | 45 | item = kzalloc(size, GFP_ATOMIC); |
ca8c1e59 | 46 | if (item == NULL) |
f4528696 | 47 | WL_ERROR("wl%d: %s: out of memory\n", unit, __func__); |
a9533e7e HP |
48 | return item; |
49 | } | |
50 | ||
0d2f0724 | 51 | void wlc_tunables_init(wlc_tunables_t *tunables, uint devid) |
a2627bc0 | 52 | { |
a9533e7e HP |
53 | tunables->ntxd = NTXD; |
54 | tunables->nrxd = NRXD; | |
55 | tunables->rxbufsz = RXBUFSZ; | |
56 | tunables->nrxbufpost = NRXBUFPOST; | |
57 | tunables->maxscb = MAXSCB; | |
58 | tunables->ampdunummpdu = AMPDU_NUM_MPDU; | |
59 | tunables->maxpktcb = MAXPKTCB; | |
60 | tunables->maxucodebss = WLC_MAX_UCODE_BSS; | |
61 | tunables->maxucodebss4 = WLC_MAX_UCODE_BSS4; | |
62 | tunables->maxbss = MAXBSS; | |
63 | tunables->datahiwat = WLC_DATAHIWAT; | |
64 | tunables->ampdudatahiwat = WLC_AMPDUDATAHIWAT; | |
65 | tunables->rxbnd = RXBND; | |
66 | tunables->txsbnd = TXSBND; | |
a9533e7e HP |
67 | } |
68 | ||
08db27dc RV |
69 | static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit, |
70 | uint *err, uint devid) | |
0d2f0724 | 71 | { |
08db27dc | 72 | struct wlc_pub *pub; |
a9533e7e | 73 | |
e4cf544e | 74 | pub = wlc_calloc(osh, unit, sizeof(struct wlc_pub)); |
ca8c1e59 | 75 | if (pub == NULL) { |
a9533e7e HP |
76 | *err = 1001; |
77 | goto fail; | |
78 | } | |
79 | ||
e4cf544e | 80 | pub->tunables = wlc_calloc(osh, unit, |
ca8c1e59 JC |
81 | sizeof(wlc_tunables_t)); |
82 | if (pub->tunables == NULL) { | |
a9533e7e HP |
83 | *err = 1028; |
84 | goto fail; | |
85 | } | |
86 | ||
87 | /* need to init the tunables now */ | |
88 | wlc_tunables_init(pub->tunables, devid); | |
89 | ||
e4cf544e AS |
90 | pub->_cnt = wlc_calloc(osh, unit, sizeof(struct wl_cnt)); |
91 | if (pub->_cnt == NULL) | |
92 | goto fail; | |
93 | ||
a44d4236 AS |
94 | pub->multicast = (u8 *)wlc_calloc(osh, unit, |
95 | (ETH_ALEN * MAXMULTILIST)); | |
ca8c1e59 | 96 | if (pub->multicast == NULL) { |
a9533e7e HP |
97 | *err = 1003; |
98 | goto fail; | |
99 | } | |
100 | ||
101 | return pub; | |
102 | ||
103 | fail: | |
104 | wlc_pub_mfree(osh, pub); | |
105 | return NULL; | |
106 | } | |
107 | ||
08db27dc | 108 | static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub) |
a2627bc0 | 109 | { |
a9533e7e HP |
110 | if (pub == NULL) |
111 | return; | |
112 | ||
e4cf544e AS |
113 | kfree(pub->multicast); |
114 | kfree(pub->_cnt); | |
115 | kfree(pub->tunables); | |
182acb3c | 116 | kfree(pub); |
a9533e7e HP |
117 | } |
118 | ||
62b54dca | 119 | static wlc_bsscfg_t *wlc_bsscfg_malloc(struct osl_info *osh, uint unit) |
a9533e7e HP |
120 | { |
121 | wlc_bsscfg_t *cfg; | |
122 | ||
ca8c1e59 JC |
123 | cfg = (wlc_bsscfg_t *) wlc_calloc(osh, unit, sizeof(wlc_bsscfg_t)); |
124 | if (cfg == NULL) | |
a9533e7e HP |
125 | goto fail; |
126 | ||
ca8c1e59 JC |
127 | cfg->current_bss = (wlc_bss_info_t *)wlc_calloc(osh, unit, |
128 | sizeof(wlc_bss_info_t)); | |
129 | if (cfg->current_bss == NULL) | |
a9533e7e HP |
130 | goto fail; |
131 | ||
132 | return cfg; | |
133 | ||
134 | fail: | |
135 | wlc_bsscfg_mfree(osh, cfg); | |
136 | return NULL; | |
137 | } | |
138 | ||
62b54dca | 139 | static void wlc_bsscfg_mfree(struct osl_info *osh, wlc_bsscfg_t *cfg) |
a9533e7e HP |
140 | { |
141 | if (cfg == NULL) | |
142 | return; | |
143 | ||
144 | if (cfg->maclist) { | |
182acb3c | 145 | kfree(cfg->maclist); |
a9533e7e HP |
146 | cfg->maclist = NULL; |
147 | } | |
148 | ||
149 | if (cfg->current_bss != NULL) { | |
150 | wlc_bss_info_t *current_bss = cfg->current_bss; | |
182acb3c | 151 | kfree(current_bss); |
a9533e7e HP |
152 | cfg->current_bss = NULL; |
153 | } | |
154 | ||
182acb3c | 155 | kfree(cfg); |
a9533e7e HP |
156 | } |
157 | ||
c6a9e1fc | 158 | void wlc_bsscfg_ID_assign(struct wlc_info *wlc, wlc_bsscfg_t *bsscfg) |
a9533e7e HP |
159 | { |
160 | bsscfg->ID = wlc->next_bsscfg_ID; | |
161 | wlc->next_bsscfg_ID++; | |
162 | } | |
163 | ||
164 | /* | |
165 | * The common driver entry routine. Error codes should be unique | |
166 | */ | |
c6a9e1fc | 167 | struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, |
e69284f2 | 168 | uint devid) |
0d2f0724 | 169 | { |
c6a9e1fc | 170 | struct wlc_info *wlc; |
a9533e7e | 171 | |
c6a9e1fc RV |
172 | wlc = (struct wlc_info *) wlc_calloc(osh, unit, |
173 | sizeof(struct wlc_info)); | |
ca8c1e59 | 174 | if (wlc == NULL) { |
a9533e7e HP |
175 | *err = 1002; |
176 | goto fail; | |
177 | } | |
178 | ||
179 | wlc->hwrxoff = WL_HWRXOFF; | |
180 | ||
08db27dc | 181 | /* allocate struct wlc_pub state structure */ |
ca8c1e59 JC |
182 | wlc->pub = wlc_pub_malloc(osh, unit, err, devid); |
183 | if (wlc->pub == NULL) { | |
a9533e7e HP |
184 | *err = 1003; |
185 | goto fail; | |
186 | } | |
187 | wlc->pub->wlc = wlc; | |
188 | ||
e304151f | 189 | /* allocate struct wlc_hw_info state structure */ |
a9533e7e | 190 | |
e304151f RV |
191 | wlc->hw = (struct wlc_hw_info *)wlc_calloc(osh, unit, |
192 | sizeof(struct wlc_hw_info)); | |
ca8c1e59 | 193 | if (wlc->hw == NULL) { |
a9533e7e HP |
194 | *err = 1005; |
195 | goto fail; | |
196 | } | |
197 | wlc->hw->wlc = wlc; | |
198 | ||
ca8c1e59 JC |
199 | wlc->hw->bandstate[0] = (wlc_hwband_t *)wlc_calloc(osh, unit, |
200 | (sizeof(wlc_hwband_t) * MAXBANDS)); | |
201 | if (wlc->hw->bandstate[0] == NULL) { | |
a9533e7e HP |
202 | *err = 1006; |
203 | goto fail; | |
204 | } else { | |
205 | int i; | |
206 | ||
207 | for (i = 1; i < MAXBANDS; i++) { | |
208 | wlc->hw->bandstate[i] = (wlc_hwband_t *) | |
f024c48a | 209 | ((unsigned long)wlc->hw->bandstate[0] + |
a9533e7e HP |
210 | (sizeof(wlc_hwband_t) * i)); |
211 | } | |
212 | } | |
a9533e7e | 213 | |
ca8c1e59 JC |
214 | wlc->modulecb = (modulecb_t *)wlc_calloc(osh, unit, |
215 | sizeof(modulecb_t) * WLC_MAXMODULES); | |
216 | if (wlc->modulecb == NULL) { | |
a9533e7e HP |
217 | *err = 1009; |
218 | goto fail; | |
219 | } | |
220 | ||
ca8c1e59 JC |
221 | wlc->default_bss = (wlc_bss_info_t *)wlc_calloc(osh, unit, |
222 | sizeof(wlc_bss_info_t)); | |
223 | if (wlc->default_bss == NULL) { | |
a9533e7e HP |
224 | *err = 1010; |
225 | goto fail; | |
226 | } | |
227 | ||
ca8c1e59 JC |
228 | wlc->cfg = wlc_bsscfg_malloc(osh, unit); |
229 | if (wlc->cfg == NULL) { | |
a9533e7e HP |
230 | *err = 1011; |
231 | goto fail; | |
232 | } | |
233 | wlc_bsscfg_ID_assign(wlc, wlc->cfg); | |
234 | ||
ca8c1e59 JC |
235 | wlc->pkt_callback = (pkt_cb_t *)wlc_calloc(osh, unit, |
236 | (sizeof(pkt_cb_t) * (wlc->pub->tunables->maxpktcb + 1))); | |
237 | if (wlc->pkt_callback == NULL) { | |
a9533e7e HP |
238 | *err = 1013; |
239 | goto fail; | |
240 | } | |
241 | ||
ca8c1e59 JC |
242 | wlc->wsec_def_keys[0] = (wsec_key_t *)wlc_calloc(osh, unit, |
243 | (sizeof(wsec_key_t) * WLC_DEFAULT_KEYS)); | |
244 | if (wlc->wsec_def_keys[0] == NULL) { | |
a9533e7e HP |
245 | *err = 1015; |
246 | goto fail; | |
247 | } else { | |
248 | int i; | |
249 | for (i = 1; i < WLC_DEFAULT_KEYS; i++) { | |
250 | wlc->wsec_def_keys[i] = (wsec_key_t *) | |
f024c48a | 251 | ((unsigned long)wlc->wsec_def_keys[0] + |
a9533e7e HP |
252 | (sizeof(wsec_key_t) * i)); |
253 | } | |
254 | } | |
255 | ||
ca8c1e59 JC |
256 | wlc->protection = (wlc_protection_t *)wlc_calloc(osh, unit, |
257 | sizeof(wlc_protection_t)); | |
258 | if (wlc->protection == NULL) { | |
a9533e7e HP |
259 | *err = 1016; |
260 | goto fail; | |
261 | } | |
262 | ||
ca8c1e59 JC |
263 | wlc->stf = (wlc_stf_t *)wlc_calloc(osh, unit, sizeof(wlc_stf_t)); |
264 | if (wlc->stf == NULL) { | |
a9533e7e HP |
265 | *err = 1017; |
266 | goto fail; | |
267 | } | |
268 | ||
f077f718 RV |
269 | wlc->bandstate[0] = (struct wlcband *)wlc_calloc(osh, unit, |
270 | (sizeof(struct wlcband)*MAXBANDS)); | |
ca8c1e59 | 271 | if (wlc->bandstate[0] == NULL) { |
a9533e7e HP |
272 | *err = 1025; |
273 | goto fail; | |
274 | } else { | |
275 | int i; | |
276 | ||
277 | for (i = 1; i < MAXBANDS; i++) { | |
278 | wlc->bandstate[i] = | |
f077f718 RV |
279 | (struct wlcband *) ((unsigned long)wlc->bandstate[0] |
280 | + (sizeof(struct wlcband)*i)); | |
a9533e7e HP |
281 | } |
282 | } | |
283 | ||
c41c858f RV |
284 | wlc->corestate = (struct wlccore *)wlc_calloc(osh, unit, |
285 | sizeof(struct wlccore)); | |
ca8c1e59 | 286 | if (wlc->corestate == NULL) { |
a9533e7e HP |
287 | *err = 1026; |
288 | goto fail; | |
289 | } | |
290 | ||
ca8c1e59 JC |
291 | wlc->corestate->macstat_snapshot = |
292 | (macstat_t *)wlc_calloc(osh, unit, sizeof(macstat_t)); | |
293 | if (wlc->corestate->macstat_snapshot == NULL) { | |
a9533e7e HP |
294 | *err = 1027; |
295 | goto fail; | |
296 | } | |
297 | ||
298 | return wlc; | |
299 | ||
300 | fail: | |
301 | wlc_detach_mfree(wlc, osh); | |
302 | return NULL; | |
303 | } | |
304 | ||
c6a9e1fc | 305 | void wlc_detach_mfree(struct wlc_info *wlc, struct osl_info *osh) |
a2627bc0 | 306 | { |
a9533e7e HP |
307 | if (wlc == NULL) |
308 | return; | |
309 | ||
310 | if (wlc->modulecb) { | |
182acb3c | 311 | kfree(wlc->modulecb); |
a9533e7e HP |
312 | wlc->modulecb = NULL; |
313 | } | |
314 | ||
315 | if (wlc->default_bss) { | |
182acb3c | 316 | kfree(wlc->default_bss); |
a9533e7e HP |
317 | wlc->default_bss = NULL; |
318 | } | |
319 | if (wlc->cfg) { | |
320 | wlc_bsscfg_mfree(osh, wlc->cfg); | |
321 | wlc->cfg = NULL; | |
322 | } | |
323 | ||
324 | if (wlc->pkt_callback && wlc->pub && wlc->pub->tunables) { | |
182acb3c | 325 | kfree(wlc->pkt_callback); |
a9533e7e HP |
326 | wlc->pkt_callback = NULL; |
327 | } | |
328 | ||
329 | if (wlc->wsec_def_keys[0]) | |
182acb3c | 330 | kfree(wlc->wsec_def_keys[0]); |
a9533e7e | 331 | if (wlc->protection) { |
182acb3c | 332 | kfree(wlc->protection); |
a9533e7e HP |
333 | wlc->protection = NULL; |
334 | } | |
335 | ||
336 | if (wlc->stf) { | |
182acb3c | 337 | kfree(wlc->stf); |
a9533e7e HP |
338 | wlc->stf = NULL; |
339 | } | |
340 | ||
341 | if (wlc->bandstate[0]) | |
182acb3c | 342 | kfree(wlc->bandstate[0]); |
a9533e7e HP |
343 | |
344 | if (wlc->corestate) { | |
345 | if (wlc->corestate->macstat_snapshot) { | |
182acb3c | 346 | kfree(wlc->corestate->macstat_snapshot); wlc->corestate->macstat_snapshot = NULL; |
a9533e7e | 347 | } |
182acb3c | 348 | kfree(wlc->corestate); |
a9533e7e HP |
349 | wlc->corestate = NULL; |
350 | } | |
351 | ||
352 | if (wlc->pub) { | |
353 | /* free pub struct */ | |
354 | wlc_pub_mfree(osh, wlc->pub); | |
355 | wlc->pub = NULL; | |
356 | } | |
357 | ||
358 | if (wlc->hw) { | |
a9533e7e | 359 | if (wlc->hw->bandstate[0]) { |
182acb3c | 360 | kfree(wlc->hw->bandstate[0]); |
a9533e7e HP |
361 | wlc->hw->bandstate[0] = NULL; |
362 | } | |
a9533e7e HP |
363 | |
364 | /* free hw struct */ | |
182acb3c | 365 | kfree(wlc->hw); |
a9533e7e HP |
366 | wlc->hw = NULL; |
367 | } | |
368 | ||
369 | /* free the wlc */ | |
182acb3c | 370 | kfree(wlc); |
a9533e7e HP |
371 | wlc = NULL; |
372 | } |