]>
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> | |
3327989a | 20 | #include <linuxver.h> |
a9533e7e HP |
21 | #include <osl.h> |
22 | #include <bcmutils.h> | |
23 | #include <siutils.h> | |
a9533e7e | 24 | #include <wlioctl.h> |
a9533e7e HP |
25 | #include <wlc_pub.h> |
26 | #include <wlc_key.h> | |
a9533e7e HP |
27 | #include <wlc_mac80211.h> |
28 | #include <wlc_alloc.h> | |
29 | ||
7cc4a4c0 | 30 | static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, |
a9533e7e | 31 | uint devid); |
7cc4a4c0 JC |
32 | static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub); |
33 | static void wlc_tunables_init(wlc_tunables_t *tunables, uint devid); | |
a9533e7e | 34 | |
7cc4a4c0 | 35 | void *wlc_calloc(osl_t *osh, uint unit, uint size) |
a9533e7e HP |
36 | { |
37 | void *item; | |
38 | ||
5fcc1fcb | 39 | item = kzalloc(size, GFP_ATOMIC); |
ca8c1e59 | 40 | if (item == NULL) |
97e17d0e | 41 | WL_ERROR(("wl%d: %s: out of memory\n", unit, __func__)); |
a9533e7e HP |
42 | return item; |
43 | } | |
44 | ||
0d2f0724 | 45 | void wlc_tunables_init(wlc_tunables_t *tunables, uint devid) |
a2627bc0 | 46 | { |
a9533e7e HP |
47 | tunables->ntxd = NTXD; |
48 | tunables->nrxd = NRXD; | |
49 | tunables->rxbufsz = RXBUFSZ; | |
50 | tunables->nrxbufpost = NRXBUFPOST; | |
51 | tunables->maxscb = MAXSCB; | |
52 | tunables->ampdunummpdu = AMPDU_NUM_MPDU; | |
53 | tunables->maxpktcb = MAXPKTCB; | |
54 | tunables->maxucodebss = WLC_MAX_UCODE_BSS; | |
55 | tunables->maxucodebss4 = WLC_MAX_UCODE_BSS4; | |
56 | tunables->maxbss = MAXBSS; | |
57 | tunables->datahiwat = WLC_DATAHIWAT; | |
58 | tunables->ampdudatahiwat = WLC_AMPDUDATAHIWAT; | |
59 | tunables->rxbnd = RXBND; | |
60 | tunables->txsbnd = TXSBND; | |
61 | #if defined(WLC_HIGH_ONLY) && defined(NTXD_USB_4319) | |
62 | if (devid == BCM4319_CHIP_ID) { | |
63 | tunables->ntxd = NTXD_USB_4319; | |
64 | } | |
65 | #endif /* WLC_HIGH_ONLY */ | |
66 | } | |
67 | ||
0d2f0724 GKH |
68 | static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid) |
69 | { | |
a9533e7e HP |
70 | wlc_pub_t *pub; |
71 | ||
ca8c1e59 JC |
72 | pub = (wlc_pub_t *) wlc_calloc(osh, unit, sizeof(wlc_pub_t)); |
73 | if (pub == NULL) { | |
a9533e7e HP |
74 | *err = 1001; |
75 | goto fail; | |
76 | } | |
77 | ||
ca8c1e59 JC |
78 | pub->tunables = (wlc_tunables_t *)wlc_calloc(osh, unit, |
79 | sizeof(wlc_tunables_t)); | |
80 | if (pub->tunables == NULL) { | |
a9533e7e HP |
81 | *err = 1028; |
82 | goto fail; | |
83 | } | |
84 | ||
85 | /* need to init the tunables now */ | |
86 | wlc_tunables_init(pub->tunables, devid); | |
87 | ||
ca8c1e59 JC |
88 | pub->multicast = (struct ether_addr *)wlc_calloc(osh, unit, |
89 | (sizeof(struct ether_addr) * MAXMULTILIST)); | |
90 | if (pub->multicast == NULL) { | |
a9533e7e HP |
91 | *err = 1003; |
92 | goto fail; | |
93 | } | |
94 | ||
95 | return pub; | |
96 | ||
97 | fail: | |
98 | wlc_pub_mfree(osh, pub); | |
99 | return NULL; | |
100 | } | |
101 | ||
0d2f0724 | 102 | static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub) |
a2627bc0 | 103 | { |
a9533e7e HP |
104 | if (pub == NULL) |
105 | return; | |
106 | ||
107 | if (pub->multicast) | |
182acb3c | 108 | kfree(pub->multicast); |
a9533e7e | 109 | if (pub->tunables) { |
182acb3c | 110 | kfree(pub->tunables); |
a9533e7e HP |
111 | pub->tunables = NULL; |
112 | } | |
113 | ||
182acb3c | 114 | kfree(pub); |
a9533e7e HP |
115 | } |
116 | ||
7cc4a4c0 | 117 | wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t *osh, uint unit) |
a9533e7e HP |
118 | { |
119 | wlc_bsscfg_t *cfg; | |
120 | ||
ca8c1e59 JC |
121 | cfg = (wlc_bsscfg_t *) wlc_calloc(osh, unit, sizeof(wlc_bsscfg_t)); |
122 | if (cfg == NULL) | |
a9533e7e HP |
123 | goto fail; |
124 | ||
ca8c1e59 JC |
125 | cfg->current_bss = (wlc_bss_info_t *)wlc_calloc(osh, unit, |
126 | sizeof(wlc_bss_info_t)); | |
127 | if (cfg->current_bss == NULL) | |
a9533e7e HP |
128 | goto fail; |
129 | ||
130 | return cfg; | |
131 | ||
132 | fail: | |
133 | wlc_bsscfg_mfree(osh, cfg); | |
134 | return NULL; | |
135 | } | |
136 | ||
7cc4a4c0 | 137 | void wlc_bsscfg_mfree(osl_t *osh, wlc_bsscfg_t *cfg) |
a9533e7e HP |
138 | { |
139 | if (cfg == NULL) | |
140 | return; | |
141 | ||
142 | if (cfg->maclist) { | |
182acb3c | 143 | kfree(cfg->maclist); |
a9533e7e HP |
144 | cfg->maclist = NULL; |
145 | } | |
146 | ||
147 | if (cfg->current_bss != NULL) { | |
148 | wlc_bss_info_t *current_bss = cfg->current_bss; | |
149 | if (current_bss->bcn_prb != NULL) | |
182acb3c | 150 | kfree(current_bss->bcn_prb); |
151 | kfree(current_bss); | |
a9533e7e HP |
152 | cfg->current_bss = NULL; |
153 | } | |
154 | ||
182acb3c | 155 | kfree(cfg); |
a9533e7e HP |
156 | } |
157 | ||
7cc4a4c0 | 158 | void wlc_bsscfg_ID_assign(wlc_info_t *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 | */ | |
0d2f0724 GKH |
167 | wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid) |
168 | { | |
a9533e7e HP |
169 | wlc_info_t *wlc; |
170 | ||
ca8c1e59 JC |
171 | wlc = (wlc_info_t *) wlc_calloc(osh, unit, sizeof(wlc_info_t)); |
172 | if (wlc == NULL) { | |
a9533e7e HP |
173 | *err = 1002; |
174 | goto fail; | |
175 | } | |
176 | ||
177 | wlc->hwrxoff = WL_HWRXOFF; | |
178 | ||
179 | /* allocate wlc_pub_t state structure */ | |
ca8c1e59 JC |
180 | wlc->pub = wlc_pub_malloc(osh, unit, err, devid); |
181 | if (wlc->pub == NULL) { | |
a9533e7e HP |
182 | *err = 1003; |
183 | goto fail; | |
184 | } | |
185 | wlc->pub->wlc = wlc; | |
186 | ||
187 | /* allocate wlc_hw_info_t state structure */ | |
188 | ||
ca8c1e59 JC |
189 | wlc->hw = (wlc_hw_info_t *)wlc_calloc(osh, unit, |
190 | sizeof(wlc_hw_info_t)); | |
191 | if (wlc->hw == NULL) { | |
a9533e7e HP |
192 | *err = 1005; |
193 | goto fail; | |
194 | } | |
195 | wlc->hw->wlc = wlc; | |
196 | ||
197 | #ifdef WLC_LOW | |
ca8c1e59 JC |
198 | wlc->hw->bandstate[0] = (wlc_hwband_t *)wlc_calloc(osh, unit, |
199 | (sizeof(wlc_hwband_t) * MAXBANDS)); | |
200 | if (wlc->hw->bandstate[0] == NULL) { | |
a9533e7e HP |
201 | *err = 1006; |
202 | goto fail; | |
203 | } else { | |
204 | int i; | |
205 | ||
206 | for (i = 1; i < MAXBANDS; i++) { | |
207 | wlc->hw->bandstate[i] = (wlc_hwband_t *) | |
f024c48a | 208 | ((unsigned long)wlc->hw->bandstate[0] + |
a9533e7e HP |
209 | (sizeof(wlc_hwband_t) * i)); |
210 | } | |
211 | } | |
212 | #endif /* WLC_LOW */ | |
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 | ||
ca8c1e59 JC |
269 | wlc->bandstate[0] = (wlcband_t *)wlc_calloc(osh, unit, |
270 | (sizeof(wlcband_t) * MAXBANDS)); | |
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] = | |
f024c48a | 279 | (wlcband_t *) ((unsigned long)wlc->bandstate[0] + |
a9533e7e HP |
280 | (sizeof(wlcband_t) * i)); |
281 | } | |
282 | } | |
283 | ||
ca8c1e59 JC |
284 | wlc->corestate = (wlccore_t *)wlc_calloc(osh, unit, sizeof(wlccore_t)); |
285 | if (wlc->corestate == NULL) { | |
a9533e7e HP |
286 | *err = 1026; |
287 | goto fail; | |
288 | } | |
289 | ||
ca8c1e59 JC |
290 | wlc->corestate->macstat_snapshot = |
291 | (macstat_t *)wlc_calloc(osh, unit, sizeof(macstat_t)); | |
292 | if (wlc->corestate->macstat_snapshot == NULL) { | |
a9533e7e HP |
293 | *err = 1027; |
294 | goto fail; | |
295 | } | |
296 | ||
297 | return wlc; | |
298 | ||
299 | fail: | |
300 | wlc_detach_mfree(wlc, osh); | |
301 | return NULL; | |
302 | } | |
303 | ||
0d2f0724 | 304 | void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh) |
a2627bc0 | 305 | { |
a9533e7e HP |
306 | if (wlc == NULL) |
307 | return; | |
308 | ||
309 | if (wlc->modulecb) { | |
182acb3c | 310 | kfree(wlc->modulecb); |
a9533e7e HP |
311 | wlc->modulecb = NULL; |
312 | } | |
313 | ||
314 | if (wlc->default_bss) { | |
182acb3c | 315 | kfree(wlc->default_bss); |
a9533e7e HP |
316 | wlc->default_bss = NULL; |
317 | } | |
318 | if (wlc->cfg) { | |
319 | wlc_bsscfg_mfree(osh, wlc->cfg); | |
320 | wlc->cfg = NULL; | |
321 | } | |
322 | ||
323 | if (wlc->pkt_callback && wlc->pub && wlc->pub->tunables) { | |
182acb3c | 324 | kfree(wlc->pkt_callback); |
a9533e7e HP |
325 | wlc->pkt_callback = NULL; |
326 | } | |
327 | ||
328 | if (wlc->wsec_def_keys[0]) | |
182acb3c | 329 | kfree(wlc->wsec_def_keys[0]); |
a9533e7e | 330 | if (wlc->protection) { |
182acb3c | 331 | kfree(wlc->protection); |
a9533e7e HP |
332 | wlc->protection = NULL; |
333 | } | |
334 | ||
335 | if (wlc->stf) { | |
182acb3c | 336 | kfree(wlc->stf); |
a9533e7e HP |
337 | wlc->stf = NULL; |
338 | } | |
339 | ||
340 | if (wlc->bandstate[0]) | |
182acb3c | 341 | kfree(wlc->bandstate[0]); |
a9533e7e HP |
342 | |
343 | if (wlc->corestate) { | |
344 | if (wlc->corestate->macstat_snapshot) { | |
182acb3c | 345 | kfree(wlc->corestate->macstat_snapshot); wlc->corestate->macstat_snapshot = NULL; |
a9533e7e | 346 | } |
182acb3c | 347 | kfree(wlc->corestate); |
a9533e7e HP |
348 | wlc->corestate = NULL; |
349 | } | |
350 | ||
351 | if (wlc->pub) { | |
352 | /* free pub struct */ | |
353 | wlc_pub_mfree(osh, wlc->pub); | |
354 | wlc->pub = NULL; | |
355 | } | |
356 | ||
357 | if (wlc->hw) { | |
358 | #ifdef WLC_LOW | |
359 | if (wlc->hw->bandstate[0]) { | |
182acb3c | 360 | kfree(wlc->hw->bandstate[0]); |
a9533e7e HP |
361 | wlc->hw->bandstate[0] = NULL; |
362 | } | |
363 | #endif | |
364 | ||
365 | /* free hw struct */ | |
182acb3c | 366 | kfree(wlc->hw); |
a9533e7e HP |
367 | wlc->hw = NULL; |
368 | } | |
369 | ||
370 | /* free the wlc */ | |
182acb3c | 371 | kfree(wlc); |
a9533e7e HP |
372 | wlc = NULL; |
373 | } |