summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/310-rt2x00_implement_support_for_802.11n.patch
blob: f82144824ff41176f76fff961db3c8f158595055 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
From: Ivo van Doorn <IvDoorn@gmail.com>
Date: Sun, 28 Dec 2008 12:48:46 +0000 (+0100)
Subject: rt2x00: Implement support for 802.11n
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fivd%2Frt2x00.git;a=commitdiff_plain;h=1ddf4bdad5f51a799ee580e125dda19dd18daa39

rt2x00: Implement support for 802.11n

Extend rt2x00lib capabilities to support 802.11n,
it still lacks aggregation support, but that can
be added in the future.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---

--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -8,6 +8,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO)	+=
 rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL)	+= rt2x00rfkill.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE)	+= rt2x00firmware.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS)	+= rt2x00leds.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_HT)	+= rt2x00ht.o
 
 obj-$(CONFIG_RT2X00_LIB)		+= rt2x00lib.o
 obj-$(CONFIG_RT2X00_LIB_PCI)		+= rt2x00pci.o
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -107,6 +107,7 @@
  */
 #define ACK_SIZE		14
 #define IEEE80211_HEADER	24
+#define AGGREGATION_SIZE	3840
 #define PLCP			48
 #define BEACON			100
 #define PREAMBLE		144
@@ -356,6 +357,7 @@ static inline struct rt2x00_intf* vif_to
  *	for @tx_power_a, @tx_power_bg and @channels.
  * @channels: Device/chipset specific channel values (See &struct rf_channel).
  * @channels_info: Additional information for channels (See &struct channel_info).
+ * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap).
  */
 struct hw_mode_spec {
 	unsigned int supported_bands;
@@ -369,6 +371,8 @@ struct hw_mode_spec {
 	unsigned int num_channels;
 	const struct rf_channel *channels;
 	const struct channel_info *channels_info;
+
+	struct ieee80211_sta_ht_cap ht;
 };
 
 /*
@@ -603,6 +607,7 @@ enum rt2x00_flags {
 	CONFIG_EXTERNAL_LNA_BG,
 	CONFIG_DOUBLE_ANTENNA,
 	CONFIG_DISABLE_LINK_TUNING,
+	CONFIG_CHANNEL_HT40,
 };
 
 /*
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -173,6 +173,12 @@ void rt2x00lib_config(struct rt2x00_dev 
 	libconf.conf = conf;
 
 	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
+		if ((conf->ht.channel_type == NL80211_CHAN_HT40MINUS) ||
+		    (conf->ht.channel_type == NL80211_CHAN_HT40PLUS))
+			__set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+		else
+			__clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+
 		memcpy(&libconf.rf,
 		       &rt2x00dev->spec.channels[conf->channel->hw_value],
 		       sizeof(libconf.rf));
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -384,7 +384,9 @@ void rt2x00lib_rxdone(struct rt2x00_dev 
 		if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) &&
 		     (rate->plcp == rxdesc.signal)) ||
 		    ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) &&
-		      (rate->bitrate == rxdesc.signal))) {
+		      (rate->bitrate == rxdesc.signal)) ||
+		    ((rxdesc.dev_flags & RXDONE_SIGNAL_MCS) &&
+		      (rate->mcs == rxdesc.signal))) {
 			idx = i;
 			break;
 		}
@@ -439,72 +441,84 @@ const struct rt2x00_rate rt2x00_supporte
 		.bitrate = 10,
 		.ratemask = BIT(0),
 		.plcp = 0x00,
+		.mcs = RATE_MCS(RATE_MODE_CCK, 0),
 	},
 	{
 		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
 		.bitrate = 20,
 		.ratemask = BIT(1),
 		.plcp = 0x01,
+		.mcs = RATE_MCS(RATE_MODE_CCK, 1),
 	},
 	{
 		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
 		.bitrate = 55,
 		.ratemask = BIT(2),
 		.plcp = 0x02,
+		.mcs = RATE_MCS(RATE_MODE_CCK, 2),
 	},
 	{
 		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
 		.bitrate = 110,
 		.ratemask = BIT(3),
 		.plcp = 0x03,
+		.mcs = RATE_MCS(RATE_MODE_CCK, 3),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 60,
 		.ratemask = BIT(4),
 		.plcp = 0x0b,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 0),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 90,
 		.ratemask = BIT(5),
 		.plcp = 0x0f,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 1),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 120,
 		.ratemask = BIT(6),
 		.plcp = 0x0a,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 2),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 180,
 		.ratemask = BIT(7),
 		.plcp = 0x0e,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 3),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 240,
 		.ratemask = BIT(8),
 		.plcp = 0x09,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 4),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 360,
 		.ratemask = BIT(9),
 		.plcp = 0x0d,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 5),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 480,
 		.ratemask = BIT(10),
 		.plcp = 0x08,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 6),
 	},
 	{
 		.flags = DEV_RATE_OFDM,
 		.bitrate = 540,
 		.ratemask = BIT(11),
 		.plcp = 0x0c,
+		.mcs = RATE_MCS(RATE_MODE_OFDM, 7),
 	},
 };
 
@@ -582,6 +596,8 @@ static int rt2x00lib_probe_hw_modes(stru
 		rt2x00dev->bands[IEEE80211_BAND_2GHZ].bitrates = rates;
 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 		    &rt2x00dev->bands[IEEE80211_BAND_2GHZ];
+		memcpy(&rt2x00dev->bands[IEEE80211_BAND_2GHZ].ht_cap,
+		       &spec->ht, sizeof(spec->ht));
 	}
 
 	/*
@@ -598,6 +614,8 @@ static int rt2x00lib_probe_hw_modes(stru
 		rt2x00dev->bands[IEEE80211_BAND_5GHZ].bitrates = &rates[4];
 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
 		    &rt2x00dev->bands[IEEE80211_BAND_5GHZ];
+		memcpy(&rt2x00dev->bands[IEEE80211_BAND_5GHZ].ht_cap,
+		       &spec->ht, sizeof(spec->ht));
 	}
 
 	return 0;
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -0,0 +1,69 @@
+/*
+	Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: rt2x00 HT specific routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
+				   struct txentry_desc *txdesc,
+				   struct ieee80211_rate *rate)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	const struct rt2x00_rate *hwrate = rt2x00_get_rate(rate->hw_value);
+
+	if (tx_info->control.sta)
+		txdesc->mpdu_density =
+		    tx_info->control.sta->ht_cap.ampdu_density;
+	else
+		txdesc->mpdu_density = 0;
+
+	txdesc->ba_size = 0;	/* FIXME: What value is needed? */
+	txdesc->stbc = 0;	/* FIXME: What value is needed? */
+
+	txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
+	if (rt2x00_get_rate_preamble(rate->hw_value))
+		txdesc->mcs |= 0x08;
+
+	/*
+	 * Convert flags
+	 */
+	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+		__set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
+
+	/*
+	 * Determine HT Mix/Greenfield rate mode
+	 */
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+		txdesc->rate_mode = RATE_MODE_HT_MIX;
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)
+		txdesc->rate_mode = RATE_MODE_HT_GREENFIELD;
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+		__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
+		__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
+}
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -48,6 +48,7 @@ struct rt2x00_rate {
 	unsigned short ratemask;
 
 	unsigned short plcp;
+	unsigned short mcs;
 };
 
 extern const struct rt2x00_rate rt2x00_supported_rates[12];
@@ -68,6 +69,14 @@ static inline int rt2x00_get_rate_preamb
 	return (hw_value & 0xff00);
 }
 
+#define RATE_MCS(__mode, __mcs) \
+	( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) )
+
+static inline int rt2x00_get_rate_mcs(const u16 mcs_value)
+{
+	return (mcs_value & 0x00ff);
+}
+
 /*
  * Radio control handlers.
  */
@@ -341,6 +350,21 @@ static inline void rt2x00crypto_rx_inser
 #endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
 /*
+ * HT handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_HT
+void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
+				   struct txentry_desc *txdesc,
+				   struct ieee80211_rate *rate);
+#else
+static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
+						 struct txentry_desc *txdesc,
+						 struct ieee80211_rate *rate)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_HT */
+
+/*
  * RFkill handlers.
  */
 #ifdef CONFIG_RT2X00_LIB_RFKILL
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -325,6 +325,7 @@ static void rt2x00queue_create_tx_descri
 	 * Apply TX descriptor handling by components
 	 */
 	rt2x00crypto_create_tx_descriptor(entry, txdesc);
+	rt2x00ht_create_tx_descriptor(entry, txdesc, rate);
 	rt2x00queue_create_tx_descriptor_seq(entry, txdesc);
 	rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, rate);
 }
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -145,6 +145,7 @@ static inline struct skb_frame_desc* get
  *
  * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
  * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
+ * @RXDONE_SIGNAL_MCS: Signal field contains the mcs value.
  * @RXDONE_MY_BSS: Does this frame originate from device's BSS.
  * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data.
  * @RXDONE_CRYPTO_ICV: Driver provided ICV data.
@@ -152,9 +153,10 @@ static inline struct skb_frame_desc* get
 enum rxdone_entry_desc_flags {
 	RXDONE_SIGNAL_PLCP = 1 << 0,
 	RXDONE_SIGNAL_BITRATE = 1 << 1,
-	RXDONE_MY_BSS = 1 << 2,
-	RXDONE_CRYPTO_IV = 1 << 3,
-	RXDONE_CRYPTO_ICV = 1 << 4,
+	RXDONE_SIGNAL_MCS = 1 << 2,
+	RXDONE_MY_BSS = 1 << 3,
+	RXDONE_CRYPTO_IV = 1 << 4,
+	RXDONE_CRYPTO_ICV = 1 << 5,
 };
 
 /**
@@ -163,7 +165,7 @@ enum rxdone_entry_desc_flags {
  * from &rxdone_entry_desc to a signal value type.
  */
 #define RXDONE_SIGNAL_MASK \
-       ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE )
+	( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE | RXDONE_SIGNAL_MCS )
 
 /**
  * struct rxdone_entry_desc: RX Entry descriptor
@@ -243,6 +245,9 @@ struct txdone_entry_desc {
  * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared).
  * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware.
  * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware.
+ * @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU.
+ * @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth.
+ * @ENTRY_TXD_HT_SHORT_GI: Use short GI.
  */
 enum txentry_desc_flags {
 	ENTRY_TXD_RTS_FRAME,
@@ -258,6 +263,9 @@ enum txentry_desc_flags {
 	ENTRY_TXD_ENCRYPT_PAIRWISE,
 	ENTRY_TXD_ENCRYPT_IV,
 	ENTRY_TXD_ENCRYPT_MMIC,
+	ENTRY_TXD_HT_AMPDU,
+	ENTRY_TXD_HT_BW_40,
+	ENTRY_TXD_HT_SHORT_GI,
 };
 
 /**
@@ -271,7 +279,11 @@ enum txentry_desc_flags {
  * @length_low: PLCP length low word.
  * @signal: PLCP signal.
  * @service: PLCP service.
+ * @msc: MCS.
+ * @stbc: STBC.
+ * @ba_size: BA size.
  * @rate_mode: Rate mode (See @enum rate_modulation).
+ * @mpdu_density: MDPU density.
  * @retry_limit: Max number of retries.
  * @aifs: AIFS value.
  * @ifs: IFS value.
@@ -291,7 +303,11 @@ struct txentry_desc {
 	u16 signal;
 	u16 service;
 
+	u16 mcs;
+	u16 stbc;
+	u16 ba_size;
 	u16 rate_mode;
+	u16 mpdu_density;
 
 	short retry_limit;
 	short aifs;