]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/brcm80211/sys/wlc_alloc.c
Staging: brcm80211: remove BCMATTACHFN macro
[net-next-2.6.git] / drivers / staging / brcm80211 / sys / wlc_alloc.c
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  */
16
17 #include <wlc_cfg.h>
18 #include <typedefs.h>
19 #include <linux/kernel.h>
20 #include <linux/string.h>
21 #include <linuxver.h>
22 #include <osl.h>
23 #include <bcmutils.h>
24 #include <siutils.h>
25 #include <wlioctl.h>
26 #include <wlc_pub.h>
27 #include <wlc_key.h>
28 #include <wlc_mac80211.h>
29 #include <wlc_alloc.h>
30
31 static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err,
32                                  uint devid);
33 static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub);
34 static void wlc_tunables_init(wlc_tunables_t *tunables, uint devid);
35
36 void *wlc_calloc(osl_t *osh, uint unit, uint size)
37 {
38         void *item;
39
40         item = MALLOC(osh, size);
41         if (item == NULL)
42                 WL_ERROR(("wl%d: %s: out of memory, malloced %d bytes\n",
43                           unit, __func__, MALLOCED(osh)));
44         else
45                 bzero((char *)item, size);
46         return item;
47 }
48
49 void wlc_tunables_init(wlc_tunables_t *tunables, uint devid)
50 {
51         tunables->ntxd = NTXD;
52         tunables->nrxd = NRXD;
53         tunables->rxbufsz = RXBUFSZ;
54         tunables->nrxbufpost = NRXBUFPOST;
55         tunables->maxscb = MAXSCB;
56         tunables->ampdunummpdu = AMPDU_NUM_MPDU;
57         tunables->maxpktcb = MAXPKTCB;
58         tunables->maxucodebss = WLC_MAX_UCODE_BSS;
59         tunables->maxucodebss4 = WLC_MAX_UCODE_BSS4;
60         tunables->maxbss = MAXBSS;
61         tunables->datahiwat = WLC_DATAHIWAT;
62         tunables->ampdudatahiwat = WLC_AMPDUDATAHIWAT;
63         tunables->rxbnd = RXBND;
64         tunables->txsbnd = TXSBND;
65 #if defined(WLC_HIGH_ONLY) && defined(NTXD_USB_4319)
66         if (devid == BCM4319_CHIP_ID) {
67                 tunables->ntxd = NTXD_USB_4319;
68         }
69 #endif                          /* WLC_HIGH_ONLY */
70 }
71
72 static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid)
73 {
74         wlc_pub_t *pub;
75
76         pub = (wlc_pub_t *) wlc_calloc(osh, unit, sizeof(wlc_pub_t));
77         if (pub == NULL) {
78                 *err = 1001;
79                 goto fail;
80         }
81
82         pub->tunables = (wlc_tunables_t *)wlc_calloc(osh, unit,
83                 sizeof(wlc_tunables_t));
84         if (pub->tunables == NULL) {
85                 *err = 1028;
86                 goto fail;
87         }
88
89         /* need to init the tunables now */
90         wlc_tunables_init(pub->tunables, devid);
91
92         pub->multicast = (struct ether_addr *)wlc_calloc(osh, unit,
93                 (sizeof(struct ether_addr) * MAXMULTILIST));
94         if (pub->multicast == NULL) {
95                 *err = 1003;
96                 goto fail;
97         }
98
99         return pub;
100
101  fail:
102         wlc_pub_mfree(osh, pub);
103         return NULL;
104 }
105
106 static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub)
107 {
108         if (pub == NULL)
109                 return;
110
111         if (pub->multicast)
112                 MFREE(osh, pub->multicast,
113                       (sizeof(struct ether_addr) * MAXMULTILIST));
114
115         if (pub->tunables) {
116                 MFREE(osh, pub->tunables, sizeof(wlc_tunables_t));
117                 pub->tunables = NULL;
118         }
119
120         MFREE(osh, pub, sizeof(wlc_pub_t));
121 }
122
123 wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t *osh, uint unit)
124 {
125         wlc_bsscfg_t *cfg;
126
127         cfg = (wlc_bsscfg_t *) wlc_calloc(osh, unit, sizeof(wlc_bsscfg_t));
128         if (cfg == NULL)
129                 goto fail;
130
131         cfg->current_bss = (wlc_bss_info_t *)wlc_calloc(osh, unit,
132                 sizeof(wlc_bss_info_t));
133         if (cfg->current_bss == NULL)
134                 goto fail;
135
136         return cfg;
137
138  fail:
139         wlc_bsscfg_mfree(osh, cfg);
140         return NULL;
141 }
142
143 void wlc_bsscfg_mfree(osl_t *osh, wlc_bsscfg_t *cfg)
144 {
145         if (cfg == NULL)
146                 return;
147
148         if (cfg->maclist) {
149                 MFREE(osh, cfg->maclist,
150                       (int)(offsetof(struct maclist, ea) +
151                             cfg->nmac * ETHER_ADDR_LEN));
152                 cfg->maclist = NULL;
153         }
154
155         if (cfg->current_bss != NULL) {
156                 wlc_bss_info_t *current_bss = cfg->current_bss;
157                 if (current_bss->bcn_prb != NULL)
158                         MFREE(osh, current_bss->bcn_prb,
159                               current_bss->bcn_prb_len);
160                 MFREE(osh, current_bss, sizeof(wlc_bss_info_t));
161                 cfg->current_bss = NULL;
162         }
163
164         MFREE(osh, cfg, sizeof(wlc_bsscfg_t));
165 }
166
167 void wlc_bsscfg_ID_assign(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg)
168 {
169         bsscfg->ID = wlc->next_bsscfg_ID;
170         wlc->next_bsscfg_ID++;
171 }
172
173 /*
174  * The common driver entry routine. Error codes should be unique
175  */
176 wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid)
177 {
178         wlc_info_t *wlc;
179
180         wlc = (wlc_info_t *) wlc_calloc(osh, unit, sizeof(wlc_info_t));
181         if (wlc == NULL) {
182                 *err = 1002;
183                 goto fail;
184         }
185
186         wlc->hwrxoff = WL_HWRXOFF;
187
188         /* allocate wlc_pub_t state structure */
189         wlc->pub = wlc_pub_malloc(osh, unit, err, devid);
190         if (wlc->pub == NULL) {
191                 *err = 1003;
192                 goto fail;
193         }
194         wlc->pub->wlc = wlc;
195
196         /* allocate wlc_hw_info_t state structure */
197
198         wlc->hw = (wlc_hw_info_t *)wlc_calloc(osh, unit,
199                 sizeof(wlc_hw_info_t));
200         if (wlc->hw == NULL) {
201                 *err = 1005;
202                 goto fail;
203         }
204         wlc->hw->wlc = wlc;
205
206 #ifdef WLC_LOW
207         wlc->hw->bandstate[0] = (wlc_hwband_t *)wlc_calloc(osh, unit,
208                 (sizeof(wlc_hwband_t) * MAXBANDS));
209         if (wlc->hw->bandstate[0] == NULL) {
210                 *err = 1006;
211                 goto fail;
212         } else {
213                 int i;
214
215                 for (i = 1; i < MAXBANDS; i++) {
216                         wlc->hw->bandstate[i] = (wlc_hwband_t *)
217                             ((uintptr) wlc->hw->bandstate[0] +
218                              (sizeof(wlc_hwband_t) * i));
219                 }
220         }
221 #endif                          /* WLC_LOW */
222
223         wlc->modulecb = (modulecb_t *)wlc_calloc(osh, unit,
224                 sizeof(modulecb_t) * WLC_MAXMODULES);
225         if (wlc->modulecb == NULL) {
226                 *err = 1009;
227                 goto fail;
228         }
229
230         wlc->default_bss = (wlc_bss_info_t *)wlc_calloc(osh, unit,
231                 sizeof(wlc_bss_info_t));
232         if (wlc->default_bss == NULL) {
233                 *err = 1010;
234                 goto fail;
235         }
236
237         wlc->cfg = wlc_bsscfg_malloc(osh, unit);
238         if (wlc->cfg == NULL) {
239                 *err = 1011;
240                 goto fail;
241         }
242         wlc_bsscfg_ID_assign(wlc, wlc->cfg);
243
244         wlc->pkt_callback = (pkt_cb_t *)wlc_calloc(osh, unit,
245                 (sizeof(pkt_cb_t) * (wlc->pub->tunables->maxpktcb + 1)));
246         if (wlc->pkt_callback == NULL) {
247                 *err = 1013;
248                 goto fail;
249         }
250
251         wlc->wsec_def_keys[0] = (wsec_key_t *)wlc_calloc(osh, unit,
252                 (sizeof(wsec_key_t) * WLC_DEFAULT_KEYS));
253         if (wlc->wsec_def_keys[0] == NULL) {
254                 *err = 1015;
255                 goto fail;
256         } else {
257                 int i;
258                 for (i = 1; i < WLC_DEFAULT_KEYS; i++) {
259                         wlc->wsec_def_keys[i] = (wsec_key_t *)
260                             ((uintptr) wlc->wsec_def_keys[0] +
261                              (sizeof(wsec_key_t) * i));
262                 }
263         }
264
265         wlc->protection = (wlc_protection_t *)wlc_calloc(osh, unit,
266                 sizeof(wlc_protection_t));
267         if (wlc->protection == NULL) {
268                 *err = 1016;
269                 goto fail;
270         }
271
272         wlc->stf = (wlc_stf_t *)wlc_calloc(osh, unit, sizeof(wlc_stf_t));
273         if (wlc->stf == NULL) {
274                 *err = 1017;
275                 goto fail;
276         }
277
278         wlc->bandstate[0] = (wlcband_t *)wlc_calloc(osh, unit,
279                                 (sizeof(wlcband_t) * MAXBANDS));
280         if (wlc->bandstate[0] == NULL) {
281                 *err = 1025;
282                 goto fail;
283         } else {
284                 int i;
285
286                 for (i = 1; i < MAXBANDS; i++) {
287                         wlc->bandstate[i] =
288                             (wlcband_t *) ((uintptr) wlc->bandstate[0] +
289                                            (sizeof(wlcband_t) * i));
290                 }
291         }
292
293         wlc->corestate = (wlccore_t *)wlc_calloc(osh, unit, sizeof(wlccore_t));
294         if (wlc->corestate == NULL) {
295                 *err = 1026;
296                 goto fail;
297         }
298
299         wlc->corestate->macstat_snapshot =
300                 (macstat_t *)wlc_calloc(osh, unit, sizeof(macstat_t));
301         if (wlc->corestate->macstat_snapshot == NULL) {
302                 *err = 1027;
303                 goto fail;
304         }
305
306         return wlc;
307
308  fail:
309         wlc_detach_mfree(wlc, osh);
310         return NULL;
311 }
312
313 void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh)
314 {
315         if (wlc == NULL)
316                 return;
317
318         if (wlc->modulecb) {
319                 MFREE(osh, wlc->modulecb, sizeof(modulecb_t) * WLC_MAXMODULES);
320                 wlc->modulecb = NULL;
321         }
322
323         if (wlc->default_bss) {
324                 MFREE(osh, wlc->default_bss, sizeof(wlc_bss_info_t));
325                 wlc->default_bss = NULL;
326         }
327         if (wlc->cfg) {
328                 wlc_bsscfg_mfree(osh, wlc->cfg);
329                 wlc->cfg = NULL;
330         }
331
332         if (wlc->pkt_callback && wlc->pub && wlc->pub->tunables) {
333                 MFREE(osh,
334                       wlc->pkt_callback,
335                       sizeof(pkt_cb_t) * (wlc->pub->tunables->maxpktcb + 1));
336                 wlc->pkt_callback = NULL;
337         }
338
339         if (wlc->wsec_def_keys[0])
340                 MFREE(osh, wlc->wsec_def_keys[0],
341                       (sizeof(wsec_key_t) * WLC_DEFAULT_KEYS));
342
343         if (wlc->protection) {
344                 MFREE(osh, wlc->protection, sizeof(wlc_protection_t));
345                 wlc->protection = NULL;
346         }
347
348         if (wlc->stf) {
349                 MFREE(osh, wlc->stf, sizeof(wlc_stf_t));
350                 wlc->stf = NULL;
351         }
352
353         if (wlc->bandstate[0])
354                 MFREE(osh, wlc->bandstate[0], (sizeof(wlcband_t) * MAXBANDS));
355
356         if (wlc->corestate) {
357                 if (wlc->corestate->macstat_snapshot) {
358                         MFREE(osh, wlc->corestate->macstat_snapshot,
359                               sizeof(macstat_t));
360                         wlc->corestate->macstat_snapshot = NULL;
361                 }
362                 MFREE(osh, wlc->corestate, sizeof(wlccore_t));
363                 wlc->corestate = NULL;
364         }
365
366         if (wlc->pub) {
367                 /* free pub struct */
368                 wlc_pub_mfree(osh, wlc->pub);
369                 wlc->pub = NULL;
370         }
371
372         if (wlc->hw) {
373 #ifdef WLC_LOW
374                 if (wlc->hw->bandstate[0]) {
375                         MFREE(osh, wlc->hw->bandstate[0],
376                               (sizeof(wlc_hwband_t) * MAXBANDS));
377                         wlc->hw->bandstate[0] = NULL;
378                 }
379 #endif
380
381                 /* free hw struct */
382                 MFREE(osh, wlc->hw, sizeof(wlc_hw_info_t));
383                 wlc->hw = NULL;
384         }
385
386         /* free the wlc */
387         MFREE(osh, wlc, sizeof(wlc_info_t));
388         wlc = NULL;
389 }