~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/staging/brcm80211/brcmsmac/wlc_rate.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

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
#include <linux/kernel.h>
 
17
#include <linux/module.h>
 
18
 
 
19
#include <proto/802.11.h>
 
20
#include <bcmdefs.h>
 
21
#include <bcmutils.h>
 
22
#include <aiutils.h>
 
23
#include <wlioctl.h>
 
24
#include <sbhnddma.h>
 
25
 
 
26
#include "wlc_types.h"
 
27
#include "d11.h"
 
28
#include "wl_dbg.h"
 
29
#include "wlc_cfg.h"
 
30
#include "wlc_scb.h"
 
31
#include "wlc_pub.h"
 
32
#include "wlc_rate.h"
 
33
 
 
34
/* Rate info per rate: It tells whether a rate is ofdm or not and its phy_rate value */
 
35
const u8 rate_info[WLC_MAXRATE + 1] = {
 
36
        /*  0     1     2     3     4     5     6     7     8     9 */
 
37
/*   0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
 
38
/*  10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00,
 
39
/*  20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00,
 
40
/*  30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00,
 
41
/*  40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00,
 
42
/*  50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
43
/*  60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
44
/*  70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
45
/*  80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
46
/*  90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
 
47
/* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c
 
48
};
 
49
 
 
50
/* rates are in units of Kbps */
 
51
const mcs_info_t mcs_table[MCS_TABLE_SIZE] = {
 
52
        /* MCS  0: SS 1, MOD: BPSK,  CR 1/2 */
 
53
        {6500, 13500, CEIL(6500 * 10, 9), CEIL(13500 * 10, 9), 0x00,
 
54
         WLC_RATE_6M},
 
55
        /* MCS  1: SS 1, MOD: QPSK,  CR 1/2 */
 
56
        {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x08,
 
57
         WLC_RATE_12M},
 
58
        /* MCS  2: SS 1, MOD: QPSK,  CR 3/4 */
 
59
        {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x0A,
 
60
         WLC_RATE_18M},
 
61
        /* MCS  3: SS 1, MOD: 16QAM, CR 1/2 */
 
62
        {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x10,
 
63
         WLC_RATE_24M},
 
64
        /* MCS  4: SS 1, MOD: 16QAM, CR 3/4 */
 
65
        {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x12,
 
66
         WLC_RATE_36M},
 
67
        /* MCS  5: SS 1, MOD: 64QAM, CR 2/3 */
 
68
        {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x19,
 
69
         WLC_RATE_48M},
 
70
        /* MCS  6: SS 1, MOD: 64QAM, CR 3/4 */
 
71
        {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x1A,
 
72
         WLC_RATE_54M},
 
73
        /* MCS  7: SS 1, MOD: 64QAM, CR 5/6 */
 
74
        {65000, 135000, CEIL(65000 * 10, 9), CEIL(135000 * 10, 9), 0x1C,
 
75
         WLC_RATE_54M},
 
76
        /* MCS  8: SS 2, MOD: BPSK,  CR 1/2 */
 
77
        {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x40,
 
78
         WLC_RATE_6M},
 
79
        /* MCS  9: SS 2, MOD: QPSK,  CR 1/2 */
 
80
        {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x48,
 
81
         WLC_RATE_12M},
 
82
        /* MCS 10: SS 2, MOD: QPSK,  CR 3/4 */
 
83
        {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x4A,
 
84
         WLC_RATE_18M},
 
85
        /* MCS 11: SS 2, MOD: 16QAM, CR 1/2 */
 
86
        {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x50,
 
87
         WLC_RATE_24M},
 
88
        /* MCS 12: SS 2, MOD: 16QAM, CR 3/4 */
 
89
        {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x52,
 
90
         WLC_RATE_36M},
 
91
        /* MCS 13: SS 2, MOD: 64QAM, CR 2/3 */
 
92
        {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0x59,
 
93
         WLC_RATE_48M},
 
94
        /* MCS 14: SS 2, MOD: 64QAM, CR 3/4 */
 
95
        {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x5A,
 
96
         WLC_RATE_54M},
 
97
        /* MCS 15: SS 2, MOD: 64QAM, CR 5/6 */
 
98
        {130000, 270000, CEIL(130000 * 10, 9), CEIL(270000 * 10, 9), 0x5C,
 
99
         WLC_RATE_54M},
 
100
        /* MCS 16: SS 3, MOD: BPSK,  CR 1/2 */
 
101
        {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x80,
 
102
         WLC_RATE_6M},
 
103
        /* MCS 17: SS 3, MOD: QPSK,  CR 1/2 */
 
104
        {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x88,
 
105
         WLC_RATE_12M},
 
106
        /* MCS 18: SS 3, MOD: QPSK,  CR 3/4 */
 
107
        {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x8A,
 
108
         WLC_RATE_18M},
 
109
        /* MCS 19: SS 3, MOD: 16QAM, CR 1/2 */
 
110
        {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x90,
 
111
         WLC_RATE_24M},
 
112
        /* MCS 20: SS 3, MOD: 16QAM, CR 3/4 */
 
113
        {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x92,
 
114
         WLC_RATE_36M},
 
115
        /* MCS 21: SS 3, MOD: 64QAM, CR 2/3 */
 
116
        {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0x99,
 
117
         WLC_RATE_48M},
 
118
        /* MCS 22: SS 3, MOD: 64QAM, CR 3/4 */
 
119
        {175500, 364500, CEIL(175500 * 10, 9), CEIL(364500 * 10, 9), 0x9A,
 
120
         WLC_RATE_54M},
 
121
        /* MCS 23: SS 3, MOD: 64QAM, CR 5/6 */
 
122
        {195000, 405000, CEIL(195000 * 10, 9), CEIL(405000 * 10, 9), 0x9B,
 
123
         WLC_RATE_54M},
 
124
        /* MCS 24: SS 4, MOD: BPSK,  CR 1/2 */
 
125
        {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0xC0,
 
126
         WLC_RATE_6M},
 
127
        /* MCS 25: SS 4, MOD: QPSK,  CR 1/2 */
 
128
        {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0xC8,
 
129
         WLC_RATE_12M},
 
130
        /* MCS 26: SS 4, MOD: QPSK,  CR 3/4 */
 
131
        {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0xCA,
 
132
         WLC_RATE_18M},
 
133
        /* MCS 27: SS 4, MOD: 16QAM, CR 1/2 */
 
134
        {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0xD0,
 
135
         WLC_RATE_24M},
 
136
        /* MCS 28: SS 4, MOD: 16QAM, CR 3/4 */
 
137
        {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0xD2,
 
138
         WLC_RATE_36M},
 
139
        /* MCS 29: SS 4, MOD: 64QAM, CR 2/3 */
 
140
        {208000, 432000, CEIL(208000 * 10, 9), CEIL(432000 * 10, 9), 0xD9,
 
141
         WLC_RATE_48M},
 
142
        /* MCS 30: SS 4, MOD: 64QAM, CR 3/4 */
 
143
        {234000, 486000, CEIL(234000 * 10, 9), CEIL(486000 * 10, 9), 0xDA,
 
144
         WLC_RATE_54M},
 
145
        /* MCS 31: SS 4, MOD: 64QAM, CR 5/6 */
 
146
        {260000, 540000, CEIL(260000 * 10, 9), CEIL(540000 * 10, 9), 0xDB,
 
147
         WLC_RATE_54M},
 
148
        /* MCS 32: SS 1, MOD: BPSK,  CR 1/2 */
 
149
        {0, 6000, 0, CEIL(6000 * 10, 9), 0x00, WLC_RATE_6M},
 
150
};
 
151
 
 
152
/* phycfg for legacy OFDM frames: code rate, modulation scheme, spatial streams
 
153
 *   Number of spatial streams: always 1
 
154
 *   other fields: refer to table 78 of section 17.3.2.2 of the original .11a standard
 
155
 */
 
156
typedef struct legacy_phycfg {
 
157
        u32 rate_ofdm;  /* ofdm mac rate */
 
158
        u8 tx_phy_ctl3; /* phy ctl byte 3, code rate, modulation type, # of streams */
 
159
} legacy_phycfg_t;
 
160
 
 
161
#define LEGACY_PHYCFG_TABLE_SIZE        12      /* Number of legacy_rate_cfg entries in the table */
 
162
 
 
163
/* In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate */
 
164
/* Eventually MIMOPHY would also be converted to this format */
 
165
/* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
 
166
static const legacy_phycfg_t legacy_phycfg_table[LEGACY_PHYCFG_TABLE_SIZE] = {
 
167
        {WLC_RATE_1M, 0x00},    /* CCK  1Mbps,  data rate  0 */
 
168
        {WLC_RATE_2M, 0x08},    /* CCK  2Mbps,  data rate  1 */
 
169
        {WLC_RATE_5M5, 0x10},   /* CCK  5.5Mbps,  data rate  2 */
 
170
        {WLC_RATE_11M, 0x18},   /* CCK  11Mbps,  data rate   3 */
 
171
        {WLC_RATE_6M, 0x00},    /* OFDM  6Mbps,  code rate 1/2, BPSK,   1 spatial stream */
 
172
        {WLC_RATE_9M, 0x02},    /* OFDM  9Mbps,  code rate 3/4, BPSK,   1 spatial stream */
 
173
        {WLC_RATE_12M, 0x08},   /* OFDM  12Mbps, code rate 1/2, QPSK,   1 spatial stream */
 
174
        {WLC_RATE_18M, 0x0A},   /* OFDM  18Mbps, code rate 3/4, QPSK,   1 spatial stream */
 
175
        {WLC_RATE_24M, 0x10},   /* OFDM  24Mbps, code rate 1/2, 16-QAM, 1 spatial stream */
 
176
        {WLC_RATE_36M, 0x12},   /* OFDM  36Mbps, code rate 3/4, 16-QAM, 1 spatial stream */
 
177
        {WLC_RATE_48M, 0x19},   /* OFDM  48Mbps, code rate 2/3, 64-QAM, 1 spatial stream */
 
178
        {WLC_RATE_54M, 0x1A},   /* OFDM  54Mbps, code rate 3/4, 64-QAM, 1 spatial stream */
 
179
};
 
180
 
 
181
/* Hardware rates (also encodes default basic rates) */
 
182
 
 
183
const wlc_rateset_t cck_ofdm_mimo_rates = {
 
184
        12,
 
185
        {                       /*    1b,   2b,   5.5b, 6,    9,    11b,  12,   18,   24,   36,   48,   54 Mbps */
 
186
         0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
 
187
         0x6c},
 
188
        0x00,
 
189
        {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
190
         0x00, 0x00, 0x00, 0x00}
 
191
};
 
192
 
 
193
const wlc_rateset_t ofdm_mimo_rates = {
 
194
        8,
 
195
        {                       /*    6b,   9,    12b,  18,   24b,  36,   48,   54 Mbps */
 
196
         0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
 
197
        0x00,
 
198
        {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
199
         0x00, 0x00, 0x00, 0x00}
 
200
};
 
201
 
 
202
/* Default ratesets that include MCS32 for 40BW channels */
 
203
const wlc_rateset_t cck_ofdm_40bw_mimo_rates = {
 
204
        12,
 
205
        {                       /*    1b,   2b,   5.5b, 6,    9,    11b,  12,   18,   24,   36,   48,   54 Mbps */
 
206
         0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
 
207
         0x6c},
 
208
        0x00,
 
209
        {0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
210
         0x00, 0x00, 0x00, 0x00}
 
211
};
 
212
 
 
213
const wlc_rateset_t ofdm_40bw_mimo_rates = {
 
214
        8,
 
215
        {                       /*    6b,   9,    12b,  18,   24b,  36,   48,   54 Mbps */
 
216
         0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
 
217
        0x00,
 
218
        {0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
219
         0x00, 0x00, 0x00, 0x00}
 
220
};
 
221
 
 
222
const wlc_rateset_t cck_ofdm_rates = {
 
223
        12,
 
224
        {                       /*    1b,   2b,   5.5b, 6,    9,    11b,  12,   18,   24,   36,   48,   54 Mbps */
 
225
         0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
 
226
         0x6c},
 
227
        0x00,
 
228
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
229
         0x00, 0x00, 0x00, 0x00}
 
230
};
 
231
 
 
232
const wlc_rateset_t gphy_legacy_rates = {
 
233
        4,
 
234
        {                       /*    1b,   2b,   5.5b,  11b Mbps */
 
235
         0x82, 0x84, 0x8b, 0x96},
 
236
        0x00,
 
237
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
238
         0x00, 0x00, 0x00, 0x00}
 
239
};
 
240
 
 
241
const wlc_rateset_t ofdm_rates = {
 
242
        8,
 
243
        {                       /*    6b,   9,    12b,  18,   24b,  36,   48,   54 Mbps */
 
244
         0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
 
245
        0x00,
 
246
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
247
         0x00, 0x00, 0x00, 0x00}
 
248
};
 
249
 
 
250
const wlc_rateset_t cck_rates = {
 
251
        4,
 
252
        {                       /*    1b,   2b,   5.5,  11 Mbps */
 
253
         0x82, 0x84, 0x0b, 0x16},
 
254
        0x00,
 
255
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
256
         0x00, 0x00, 0x00, 0x00}
 
257
};
 
258
 
 
259
static bool wlc_rateset_valid(wlc_rateset_t *rs, bool check_brate);
 
260
 
 
261
/* check if rateset is valid.
 
262
 * if check_brate is true, rateset without a basic rate is considered NOT valid.
 
263
 */
 
264
static bool wlc_rateset_valid(wlc_rateset_t *rs, bool check_brate)
 
265
{
 
266
        uint idx;
 
267
 
 
268
        if (!rs->count)
 
269
                return false;
 
270
 
 
271
        if (!check_brate)
 
272
                return true;
 
273
 
 
274
        /* error if no basic rates */
 
275
        for (idx = 0; idx < rs->count; idx++) {
 
276
                if (rs->rates[idx] & WLC_RATE_FLAG)
 
277
                        return true;
 
278
        }
 
279
        return false;
 
280
}
 
281
 
 
282
void wlc_rateset_mcs_upd(wlc_rateset_t *rs, u8 txstreams)
 
283
{
 
284
        int i;
 
285
        for (i = txstreams; i < MAX_STREAMS_SUPPORTED; i++)
 
286
                rs->mcs[i] = 0;
 
287
}
 
288
 
 
289
/* filter based on hardware rateset, and sort filtered rateset with basic bit(s) preserved,
 
290
 * and check if resulting rateset is valid.
 
291
*/
 
292
bool
 
293
wlc_rate_hwrs_filter_sort_validate(wlc_rateset_t *rs,
 
294
                                   const wlc_rateset_t *hw_rs,
 
295
                                   bool check_brate, u8 txstreams)
 
296
{
 
297
        u8 rateset[WLC_MAXRATE + 1];
 
298
        u8 r;
 
299
        uint count;
 
300
        uint i;
 
301
 
 
302
        memset(rateset, 0, sizeof(rateset));
 
303
        count = rs->count;
 
304
 
 
305
        for (i = 0; i < count; i++) {
 
306
                /* mask off "basic rate" bit, WLC_RATE_FLAG */
 
307
                r = (int)rs->rates[i] & WLC_RATE_MASK;
 
308
                if ((r > WLC_MAXRATE) || (rate_info[r] == 0)) {
 
309
                        continue;
 
310
                }
 
311
                rateset[r] = rs->rates[i];      /* preserve basic bit! */
 
312
        }
 
313
 
 
314
        /* fill out the rates in order, looking at only supported rates */
 
315
        count = 0;
 
316
        for (i = 0; i < hw_rs->count; i++) {
 
317
                r = hw_rs->rates[i] & WLC_RATE_MASK;
 
318
                if (rateset[r])
 
319
                        rs->rates[count++] = rateset[r];
 
320
        }
 
321
 
 
322
        rs->count = count;
 
323
 
 
324
        /* only set the mcs rate bit if the equivalent hw mcs bit is set */
 
325
        for (i = 0; i < MCSSET_LEN; i++)
 
326
                rs->mcs[i] = (rs->mcs[i] & hw_rs->mcs[i]);
 
327
 
 
328
        if (wlc_rateset_valid(rs, check_brate))
 
329
                return true;
 
330
        else
 
331
                return false;
 
332
}
 
333
 
 
334
/* calculate the rate of a rx'd frame and return it as a ratespec */
 
335
ratespec_t wlc_compute_rspec(d11rxhdr_t *rxh, u8 *plcp)
 
336
{
 
337
        int phy_type;
 
338
        ratespec_t rspec = PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT;
 
339
 
 
340
        phy_type =
 
341
            ((rxh->RxChan & RXS_CHAN_PHYTYPE_MASK) >> RXS_CHAN_PHYTYPE_SHIFT);
 
342
 
 
343
        if ((phy_type == PHY_TYPE_N) || (phy_type == PHY_TYPE_SSN) ||
 
344
            (phy_type == PHY_TYPE_LCN) || (phy_type == PHY_TYPE_HT)) {
 
345
                switch (rxh->PhyRxStatus_0 & PRXS0_FT_MASK) {
 
346
                case PRXS0_CCK:
 
347
                        rspec =
 
348
                            CCK_PHY2MAC_RATE(((cck_phy_hdr_t *) plcp)->signal);
 
349
                        break;
 
350
                case PRXS0_OFDM:
 
351
                        rspec =
 
352
                            OFDM_PHY2MAC_RATE(((ofdm_phy_hdr_t *) plcp)->
 
353
                                              rlpt[0]);
 
354
                        break;
 
355
                case PRXS0_PREN:
 
356
                        rspec = (plcp[0] & MIMO_PLCP_MCS_MASK) | RSPEC_MIMORATE;
 
357
                        if (plcp[0] & MIMO_PLCP_40MHZ) {
 
358
                                /* indicate rspec is for 40 MHz mode */
 
359
                                rspec &= ~RSPEC_BW_MASK;
 
360
                                rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
 
361
                        }
 
362
                        break;
 
363
                case PRXS0_STDN:
 
364
                        /* fallthru */
 
365
                default:
 
366
                        /* not supported, error condition */
 
367
                        break;
 
368
                }
 
369
                if (PLCP3_ISSGI(plcp[3]))
 
370
                        rspec |= RSPEC_SHORT_GI;
 
371
        } else
 
372
            if ((phy_type == PHY_TYPE_A) || (rxh->PhyRxStatus_0 & PRXS0_OFDM))
 
373
                rspec = OFDM_PHY2MAC_RATE(((ofdm_phy_hdr_t *) plcp)->rlpt[0]);
 
374
        else
 
375
                rspec = CCK_PHY2MAC_RATE(((cck_phy_hdr_t *) plcp)->signal);
 
376
 
 
377
        return rspec;
 
378
}
 
379
 
 
380
/* copy rateset src to dst as-is (no masking or sorting) */
 
381
void wlc_rateset_copy(const wlc_rateset_t *src, wlc_rateset_t *dst)
 
382
{
 
383
        memcpy(dst, src, sizeof(wlc_rateset_t));
 
384
}
 
385
 
 
386
/*
 
387
 * Copy and selectively filter one rateset to another.
 
388
 * 'basic_only' means only copy basic rates.
 
389
 * 'rates' indicates cck (11b) and ofdm rates combinations.
 
390
 *    - 0: cck and ofdm
 
391
 *    - 1: cck only
 
392
 *    - 2: ofdm only
 
393
 * 'xmask' is the copy mask (typically 0x7f or 0xff).
 
394
 */
 
395
void
 
396
wlc_rateset_filter(wlc_rateset_t *src, wlc_rateset_t *dst, bool basic_only,
 
397
                   u8 rates, uint xmask, bool mcsallow)
 
398
{
 
399
        uint i;
 
400
        uint r;
 
401
        uint count;
 
402
 
 
403
        count = 0;
 
404
        for (i = 0; i < src->count; i++) {
 
405
                r = src->rates[i];
 
406
                if (basic_only && !(r & WLC_RATE_FLAG))
 
407
                        continue;
 
408
                if ((rates == WLC_RATES_CCK) && IS_OFDM((r & WLC_RATE_MASK)))
 
409
                        continue;
 
410
                if ((rates == WLC_RATES_OFDM) && IS_CCK((r & WLC_RATE_MASK)))
 
411
                        continue;
 
412
                dst->rates[count++] = r & xmask;
 
413
        }
 
414
        dst->count = count;
 
415
        dst->htphy_membership = src->htphy_membership;
 
416
 
 
417
        if (mcsallow && rates != WLC_RATES_CCK)
 
418
                memcpy(&dst->mcs[0], &src->mcs[0], MCSSET_LEN);
 
419
        else
 
420
                wlc_rateset_mcs_clear(dst);
 
421
}
 
422
 
 
423
/* select rateset for a given phy_type and bandtype and filter it, sort it
 
424
 * and fill rs_tgt with result
 
425
 */
 
426
void
 
427
wlc_rateset_default(wlc_rateset_t *rs_tgt, const wlc_rateset_t *rs_hw,
 
428
                    uint phy_type, int bandtype, bool cck_only, uint rate_mask,
 
429
                    bool mcsallow, u8 bw, u8 txstreams)
 
430
{
 
431
        const wlc_rateset_t *rs_dflt;
 
432
        wlc_rateset_t rs_sel;
 
433
        if ((PHYTYPE_IS(phy_type, PHY_TYPE_HT)) ||
 
434
            (PHYTYPE_IS(phy_type, PHY_TYPE_N)) ||
 
435
            (PHYTYPE_IS(phy_type, PHY_TYPE_LCN)) ||
 
436
            (PHYTYPE_IS(phy_type, PHY_TYPE_SSN))) {
 
437
                if (BAND_5G(bandtype)) {
 
438
                        rs_dflt = (bw == WLC_20_MHZ ?
 
439
                                   &ofdm_mimo_rates : &ofdm_40bw_mimo_rates);
 
440
                } else {
 
441
                        rs_dflt = (bw == WLC_20_MHZ ?
 
442
                                   &cck_ofdm_mimo_rates :
 
443
                                   &cck_ofdm_40bw_mimo_rates);
 
444
                }
 
445
        } else if (PHYTYPE_IS(phy_type, PHY_TYPE_LP)) {
 
446
                rs_dflt = (BAND_5G(bandtype)) ? &ofdm_rates : &cck_ofdm_rates;
 
447
        } else if (PHYTYPE_IS(phy_type, PHY_TYPE_A)) {
 
448
                rs_dflt = &ofdm_rates;
 
449
        } else if (PHYTYPE_IS(phy_type, PHY_TYPE_G)) {
 
450
                rs_dflt = &cck_ofdm_rates;
 
451
        } else {
 
452
                /* should not happen, error condition */
 
453
                rs_dflt = &cck_rates;   /* force cck */
 
454
        }
 
455
 
 
456
        /* if hw rateset is not supplied, assign selected rateset to it */
 
457
        if (!rs_hw)
 
458
                rs_hw = rs_dflt;
 
459
 
 
460
        wlc_rateset_copy(rs_dflt, &rs_sel);
 
461
        wlc_rateset_mcs_upd(&rs_sel, txstreams);
 
462
        wlc_rateset_filter(&rs_sel, rs_tgt, false,
 
463
                           cck_only ? WLC_RATES_CCK : WLC_RATES_CCK_OFDM,
 
464
                           rate_mask, mcsallow);
 
465
        wlc_rate_hwrs_filter_sort_validate(rs_tgt, rs_hw, false,
 
466
                                           mcsallow ? txstreams : 1);
 
467
}
 
468
 
 
469
s16 wlc_rate_legacy_phyctl(uint rate)
 
470
{
 
471
        uint i;
 
472
        for (i = 0; i < LEGACY_PHYCFG_TABLE_SIZE; i++)
 
473
                if (rate == legacy_phycfg_table[i].rate_ofdm)
 
474
                        return legacy_phycfg_table[i].tx_phy_ctl3;
 
475
 
 
476
        return -1;
 
477
}
 
478
 
 
479
void wlc_rateset_mcs_clear(wlc_rateset_t *rateset)
 
480
{
 
481
        uint i;
 
482
        for (i = 0; i < MCSSET_LEN; i++)
 
483
                rateset->mcs[i] = 0;
 
484
}
 
485
 
 
486
void wlc_rateset_mcs_build(wlc_rateset_t *rateset, u8 txstreams)
 
487
{
 
488
        memcpy(&rateset->mcs[0], &cck_ofdm_mimo_rates.mcs[0], MCSSET_LEN);
 
489
        wlc_rateset_mcs_upd(rateset, txstreams);
 
490
}
 
491
 
 
492
/* Based on bandwidth passed, allow/disallow MCS 32 in the rateset */
 
493
void wlc_rateset_bw_mcs_filter(wlc_rateset_t *rateset, u8 bw)
 
494
{
 
495
        if (bw == WLC_40_MHZ)
 
496
                setbit(rateset->mcs, 32);
 
497
        else
 
498
                clrbit(rateset->mcs, 32);
 
499
}