~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/staging/brcm80211/sys/wlc_antsel.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno
  • Date: 2011-06-07 12:14:05 UTC
  • mfrom: (43.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110607121405-i3h1rd7nrnd2b73h
Tags: 2.6.39-2
[ Ben Hutchings ]
* [x86] Enable BACKLIGHT_APPLE, replacing BACKLIGHT_MBP_NVIDIA
  (Closes: #627492)
* cgroups: Disable memory resource controller by default. Allow it
  to be enabled using kernel parameter 'cgroup_enable=memory'.
* rt2800usb: Enable support for more USB devices including
  Linksys WUSB600N (Closes: #596626) (this change was accidentally
  omitted from 2.6.39-1)
* [x86] Remove Celeron from list of processors supporting PAE. Most
  'Celeron M' models do not.
* Update debconf template translations:
  - Swedish (Martin Bagge) (Closes: #628932)
  - French (David Prévot) (Closes: #628191)
* aufs: Update for 2.6.39 (Closes: #627837)
* Add stable 2.6.39.1, including:
  - ext4: dont set PageUptodate in ext4_end_bio()
  - pata_cmd64x: fix boot crash on parisc (Closes: #622997, #622745)
  - ext3: Fix fs corruption when make_indexed_dir() fails
  - netfilter: nf_ct_sip: validate Content-Length in TCP SIP messages
  - sctp: fix race between sctp_bind_addr_free() and
    sctp_bind_addr_conflict()
  - sctp: fix memory leak of the ASCONF queue when free asoc
  - md/bitmap: fix saving of events_cleared and other state
  - cdc_acm: Fix oops when Droids MuIn LCD is connected
  - cx88: Fix conversion from BKL to fine-grained locks (Closes: #619827)
  - keys: Set cred->user_ns in key_replace_session_keyring (CVE-2011-2184)
  - tmpfs: fix race between truncate and writepage
  - nfs41: Correct offset for LAYOUTCOMMIT
  - xen/mmu: fix a race window causing leave_mm BUG()
  - ext4: fix possible use-after-free in ext4_remove_li_request()
  For the complete list of changes, see:
   http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.39.1
* Bump ABI to 2
* netfilter: Enable IP_SET, IP_SET_BITMAP_IP, IP_SET_BITMAP_IPMAC,
  IP_SET_BITMAP_PORT, IP_SET_HASH_IP, IP_SET_HASH_IPPORT,
  IP_SET_HASH_IPPORTIP, IP_SET_HASH_IPPORTNET, IP_SET_HASH_NET,
  IP_SET_HASH_NETPORT, IP_SET_LIST_SET, NETFILTER_XT_SET as modules
  (Closes: #629401)

[ Aurelien Jarno ]
* [mipsel/loongson-2f] Disable_SCSI_LPFC to workaround GCC ICE.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
19
 
#ifdef WLANTSEL
20
 
 
21
 
#include <linux/kernel.h>
22
 
#include <linux/module.h>
23
 
#include <linux/pci.h>
24
 
#include <bcmdefs.h>
25
 
#include <osl.h>
26
 
#include <bcmutils.h>
27
 
#include <siutils.h>
28
 
#include <wlioctl.h>
29
 
 
30
 
#include <bcmdevs.h>
31
 
#include <sbhndpio.h>
32
 
#include <sbhnddma.h>
33
 
#include <d11.h>
34
 
#include <wlc_rate.h>
35
 
#include <wlc_key.h>
36
 
#include <wlc_pub.h>
37
 
#include <wl_dbg.h>
38
 
#include <wlc_event.h>
39
 
#include <wlc_mac80211.h>
40
 
#include <wlc_bmac.h>
41
 
#include <wlc_phy_hal.h>
42
 
#include <wl_export.h>
43
 
#include <wlc_antsel.h>
44
 
#include <wlc_phy_shim.h>
45
 
 
46
 
/* useful macros */
47
 
#define WLC_ANTSEL_11N_0(ant)   ((((ant) & ANT_SELCFG_MASK) >> 4) & 0xf)
48
 
#define WLC_ANTSEL_11N_1(ant)   (((ant) & ANT_SELCFG_MASK) & 0xf)
49
 
#define WLC_ANTIDX_11N(ant)     (((WLC_ANTSEL_11N_0(ant)) << 2) + (WLC_ANTSEL_11N_1(ant)))
50
 
#define WLC_ANT_ISAUTO_11N(ant) (((ant) & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO)
51
 
#define WLC_ANTSEL_11N(ant)     ((ant) & ANT_SELCFG_MASK)
52
 
 
53
 
/* antenna switch */
54
 
/* defines for no boardlevel antenna diversity */
55
 
#define ANT_SELCFG_DEF_2x2      0x01    /* default antenna configuration */
56
 
 
57
 
/* 2x3 antdiv defines and tables for GPIO communication */
58
 
#define ANT_SELCFG_NUM_2x3      3
59
 
#define ANT_SELCFG_DEF_2x3      0x01    /* default antenna configuration */
60
 
 
61
 
/* 2x4 antdiv rev4 defines and tables for GPIO communication */
62
 
#define ANT_SELCFG_NUM_2x4      4
63
 
#define ANT_SELCFG_DEF_2x4      0x02    /* default antenna configuration */
64
 
 
65
 
/* static functions */
66
 
static int wlc_antsel_cfgupd(struct antsel_info *asi, wlc_antselcfg_t *antsel);
67
 
static u8 wlc_antsel_id2antcfg(struct antsel_info *asi, u8 id);
68
 
static u16 wlc_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg);
69
 
static void wlc_antsel_init_cfg(struct antsel_info *asi,
70
 
                                wlc_antselcfg_t *antsel,
71
 
                                bool auto_sel);
72
 
 
73
 
const u16 mimo_2x4_div_antselpat_tbl[] = {
74
 
        0, 0, 0x9, 0xa,         /* ant0: 0 ant1: 2,3 */
75
 
        0, 0, 0x5, 0x6,         /* ant0: 1 ant1: 2,3 */
76
 
        0, 0, 0, 0,             /* n.a.              */
77
 
        0, 0, 0, 0              /* n.a.              */
78
 
};
79
 
 
80
 
const u8 mimo_2x4_div_antselid_tbl[16] = {
81
 
        0, 0, 0, 0, 0, 2, 3, 0,
82
 
        0, 0, 1, 0, 0, 0, 0, 0  /* pat to antselid */
83
 
};
84
 
 
85
 
const u16 mimo_2x3_div_antselpat_tbl[] = {
86
 
        16, 0, 1, 16,           /* ant0: 0 ant1: 1,2 */
87
 
        16, 16, 16, 16,         /* n.a.              */
88
 
        16, 2, 16, 16,          /* ant0: 2 ant1: 1   */
89
 
        16, 16, 16, 16          /* n.a.              */
90
 
};
91
 
 
92
 
const u8 mimo_2x3_div_antselid_tbl[16] = {
93
 
        0, 1, 2, 0, 0, 0, 0, 0,
94
 
        0, 0, 0, 0, 0, 0, 0, 0  /* pat to antselid */
95
 
};
96
 
 
97
 
struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc,
98
 
                                      struct osl_info *osh,
99
 
                                      struct wlc_pub *pub,
100
 
                                      struct wlc_hw_info *wlc_hw) {
101
 
        struct antsel_info *asi;
102
 
 
103
 
        asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
104
 
        if (!asi) {
105
 
                WL_ERROR("wl%d: wlc_antsel_attach: out of mem\n", pub->unit);
106
 
                return NULL;
107
 
        }
108
 
 
109
 
        asi->wlc = wlc;
110
 
        asi->pub = pub;
111
 
        asi->antsel_type = ANTSEL_NA;
112
 
        asi->antsel_avail = false;
113
 
        asi->antsel_antswitch = (u8) getintvar(asi->pub->vars, "antswitch");
114
 
 
115
 
        if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) {
116
 
                switch (asi->antsel_antswitch) {
117
 
                case ANTSWITCH_TYPE_1:
118
 
                case ANTSWITCH_TYPE_2:
119
 
                case ANTSWITCH_TYPE_3:
120
 
                        /* 4321/2 board with 2x3 switch logic */
121
 
                        asi->antsel_type = ANTSEL_2x3;
122
 
                        /* Antenna selection availability */
123
 
                        if (((u16) getintvar(asi->pub->vars, "aa2g") == 7) ||
124
 
                            ((u16) getintvar(asi->pub->vars, "aa5g") == 7)) {
125
 
                                asi->antsel_avail = true;
126
 
                        } else
127
 
                            if (((u16) getintvar(asi->pub->vars, "aa2g") ==
128
 
                                 3)
129
 
                                || ((u16) getintvar(asi->pub->vars, "aa5g")
130
 
                                    == 3)) {
131
 
                                asi->antsel_avail = false;
132
 
                        } else {
133
 
                                asi->antsel_avail = false;
134
 
                                WL_ERROR("wlc_antsel_attach: 2o3 board cfg invalid\n");
135
 
                                ASSERT(0);
136
 
                        }
137
 
                        break;
138
 
                default:
139
 
                        break;
140
 
                }
141
 
        } else if ((asi->pub->sromrev == 4) &&
142
 
                   ((u16) getintvar(asi->pub->vars, "aa2g") == 7) &&
143
 
                   ((u16) getintvar(asi->pub->vars, "aa5g") == 0)) {
144
 
                /* hack to match old 4321CB2 cards with 2of3 antenna switch */
145
 
                asi->antsel_type = ANTSEL_2x3;
146
 
                asi->antsel_avail = true;
147
 
        } else if (asi->pub->boardflags2 & BFL2_2X4_DIV) {
148
 
                asi->antsel_type = ANTSEL_2x4;
149
 
                asi->antsel_avail = true;
150
 
        }
151
 
 
152
 
        /* Set the antenna selection type for the low driver */
153
 
        wlc_bmac_antsel_type_set(wlc_hw, asi->antsel_type);
154
 
 
155
 
        /* Init (auto/manual) antenna selection */
156
 
        wlc_antsel_init_cfg(asi, &asi->antcfg_11n, true);
157
 
        wlc_antsel_init_cfg(asi, &asi->antcfg_cur, true);
158
 
 
159
 
        return asi;
160
 
}
161
 
 
162
 
void wlc_antsel_detach(struct antsel_info *asi)
163
 
{
164
 
        if (!asi)
165
 
                return;
166
 
 
167
 
        kfree(asi);
168
 
}
169
 
 
170
 
void wlc_antsel_init(struct antsel_info *asi)
171
 
{
172
 
        if ((asi->antsel_type == ANTSEL_2x3) ||
173
 
            (asi->antsel_type == ANTSEL_2x4))
174
 
                wlc_antsel_cfgupd(asi, &asi->antcfg_11n);
175
 
}
176
 
 
177
 
/* boardlevel antenna selection: init antenna selection structure */
178
 
static void
179
 
wlc_antsel_init_cfg(struct antsel_info *asi, wlc_antselcfg_t *antsel,
180
 
                    bool auto_sel)
181
 
{
182
 
        if (asi->antsel_type == ANTSEL_2x3) {
183
 
                u8 antcfg_def = ANT_SELCFG_DEF_2x3 |
184
 
                    ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0);
185
 
                antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def;
186
 
                antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def;
187
 
                antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def;
188
 
                antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def;
189
 
                antsel->num_antcfg = ANT_SELCFG_NUM_2x3;
190
 
 
191
 
        } else if (asi->antsel_type == ANTSEL_2x4) {
192
 
 
193
 
                antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4;
194
 
                antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4;
195
 
                antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4;
196
 
                antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4;
197
 
                antsel->num_antcfg = ANT_SELCFG_NUM_2x4;
198
 
 
199
 
        } else {                /* no antenna selection available */
200
 
 
201
 
                antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2;
202
 
                antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2;
203
 
                antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2;
204
 
                antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2;
205
 
                antsel->num_antcfg = 0;
206
 
        }
207
 
}
208
 
 
209
 
void BCMFASTPATH
210
 
wlc_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel,
211
 
                      u8 antselid, u8 fbantselid, u8 *antcfg,
212
 
                      u8 *fbantcfg)
213
 
{
214
 
        u8 ant;
215
 
 
216
 
        /* if use default, assign it and return */
217
 
        if (usedef) {
218
 
                *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_DEF];
219
 
                *fbantcfg = *antcfg;
220
 
                return;
221
 
        }
222
 
 
223
 
        if (!sel) {
224
 
                *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST];
225
 
                *fbantcfg = *antcfg;
226
 
 
227
 
        } else {
228
 
                ant = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST];
229
 
                if ((ant & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) {
230
 
                        *antcfg = wlc_antsel_id2antcfg(asi, antselid);
231
 
                        *fbantcfg = wlc_antsel_id2antcfg(asi, fbantselid);
232
 
                } else {
233
 
                        *antcfg =
234
 
                            asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST];
235
 
                        *fbantcfg = *antcfg;
236
 
                }
237
 
        }
238
 
        return;
239
 
}
240
 
 
241
 
/* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */
242
 
u8 wlc_antsel_antsel2id(struct antsel_info *asi, u16 antsel)
243
 
{
244
 
        u8 antselid = 0;
245
 
 
246
 
        if (asi->antsel_type == ANTSEL_2x4) {
247
 
                /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
248
 
                antselid = mimo_2x4_div_antselid_tbl[(antsel & 0xf)];
249
 
                return antselid;
250
 
 
251
 
        } else if (asi->antsel_type == ANTSEL_2x3) {
252
 
                /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
253
 
                antselid = mimo_2x3_div_antselid_tbl[(antsel & 0xf)];
254
 
                return antselid;
255
 
        }
256
 
 
257
 
        return antselid;
258
 
}
259
 
 
260
 
/* boardlevel antenna selection: convert id to ant_cfg */
261
 
static u8 wlc_antsel_id2antcfg(struct antsel_info *asi, u8 id)
262
 
{
263
 
        u8 antcfg = ANT_SELCFG_DEF_2x2;
264
 
 
265
 
        if (asi->antsel_type == ANTSEL_2x4) {
266
 
                /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
267
 
                antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2));
268
 
                return antcfg;
269
 
 
270
 
        } else if (asi->antsel_type == ANTSEL_2x3) {
271
 
                /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
272
 
                antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1));
273
 
                return antcfg;
274
 
        }
275
 
 
276
 
        return antcfg;
277
 
}
278
 
 
279
 
/* boardlevel antenna selection: convert ant_cfg to mimo_antsel (ucode interface) */
280
 
static u16 wlc_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg)
281
 
{
282
 
        u8 idx = WLC_ANTIDX_11N(WLC_ANTSEL_11N(ant_cfg));
283
 
        u16 mimo_antsel = 0;
284
 
 
285
 
        if (asi->antsel_type == ANTSEL_2x4) {
286
 
                /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
287
 
                mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf);
288
 
                return mimo_antsel;
289
 
 
290
 
        } else if (asi->antsel_type == ANTSEL_2x3) {
291
 
                /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
292
 
                mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf);
293
 
                return mimo_antsel;
294
 
        }
295
 
 
296
 
        return mimo_antsel;
297
 
}
298
 
 
299
 
/* boardlevel antenna selection: ucode interface control */
300
 
static int wlc_antsel_cfgupd(struct antsel_info *asi, wlc_antselcfg_t *antsel)
301
 
{
302
 
        struct wlc_info *wlc = asi->wlc;
303
 
        u8 ant_cfg;
304
 
        u16 mimo_antsel;
305
 
 
306
 
        ASSERT(asi->antsel_type != ANTSEL_NA);
307
 
 
308
 
        /* 1) Update TX antconfig for all frames that are not unicast data
309
 
         *    (aka default TX)
310
 
         */
311
 
        ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF];
312
 
        mimo_antsel = wlc_antsel_antcfg2antsel(asi, ant_cfg);
313
 
        wlc_write_shm(wlc, M_MIMO_ANTSEL_TXDFLT, mimo_antsel);
314
 
        /* Update driver stats for currently selected default tx/rx antenna config */
315
 
        asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg;
316
 
 
317
 
        /* 2) Update RX antconfig for all frames that are not unicast data
318
 
         *    (aka default RX)
319
 
         */
320
 
        ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF];
321
 
        mimo_antsel = wlc_antsel_antcfg2antsel(asi, ant_cfg);
322
 
        wlc_write_shm(wlc, M_MIMO_ANTSEL_RXDFLT, mimo_antsel);
323
 
        /* Update driver stats for currently selected default tx/rx antenna config */
324
 
        asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg;
325
 
 
326
 
        return 0;
327
 
}
328
 
 
329
 
#endif                          /* WLANTSEL */